eclipse-ee4j / eclipse-ee4j/jersey

javax.ws.rs.PathParam and javax.ws.rs.QueryParam fail with enum types having XmlType-annotation

Open
#4,014 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Java
Stars
730
Forks
382
PR merge metrics
No merged PRs in 30d

Description

Jersey version in our case is 2.27, while using it with Spring Boot. I see the newest version is actually 2.28 (from last month), but after some searching I couldn't find a reason to believe that this has been fixed, so hopefully this issue has some value.

Using enum-type as a parameter (QueryParam or PathParam -annotated) for a resource fails if the type is annotated with `@XmlType` (`@XmlRootElement` does the same, which is pretty clear when you look at the implementation code). For more details, please see the example code at the bottom of this comment. The resulting stack trace using our Spring Boot application is as follows:

```
PathParamException: HTTP 404 Not Found
org.xml.sax.SAXParseException: Content is not allowed in prolog.
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:203)
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.fatalError(ErrorHandlerWrapper.java:177)
at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:400)
at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:327)
at com.sun.org.apache.xerces.internal.impl.XMLScanner.reportFatalError(XMLScanner.java:1472)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(XMLDocumentScannerImpl.java:994)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:602)
at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:112)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:505)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:841)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:770)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1213)
at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:643)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:258)
... 101 common frames omitted
Wrapped by: javax.xml.bind.UnmarshalException: null
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.createUnmarshalException(AbstractUnmarshallerImpl.java:335)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.createUnmarshalException(UnmarshallerImpl.java:578)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:264)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:229)
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:140)
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:123)
at org.glassfish.jersey.jaxb.internal.JaxbStringReaderProvider$RootElementProvider$1.fromString(JaxbStringReaderProvider.java:191)
... 97 common frames omitted
Wrapped by: org.glassfish.jersey.internal.inject.ExtractorException: Error un-marshalling JAXB object of type: class fi.livi.tloik.ohjaus.tietomalli.api.SekvenssinOhjauskomento.
at org.glassfish.jersey.jaxb.internal.JaxbStringReaderProvider$RootElementProvider$1.fromString(JaxbStringReaderProvider.java:196)
at org.glassfish.jersey.server.internal.inject.AbstractParamValueExtractor.convert(AbstractParamValueExtractor.java:140)
at org.glassfish.jersey.server.internal.inject.AbstractParamValueExtractor.fromString(AbstractParamValueExtractor.java:131)
at org.glassfish.jersey.server.internal.inject.SingleValueExtractor.extract(SingleValueExtractor.java:85)
at org.glassfish.jersey.server.internal.inject.PathParamValueParamProvider$PathParamValueProvider.apply(PathParamValueParamProvider.java:116)
... 93 common frames omitted
Wrapped by: org.glassfish.jersey.server.ParamException$PathParamException: HTTP 404 Not Found
at org.glassfish.jersey.server.internal.inject.PathParamValueParamProvider$PathParamValueProvider.apply(PathParamValueParamProvider.java:118)
at org.glassfish.jersey.server.internal.inject.PathParamValueParamProvider$PathParamValueProvider.apply(PathParamValueParamProvider.java:103)
at org.glassfish.jersey.server.spi.internal.ParamValueFactoryWithSource.apply(ParamValueFactoryWithSource.java:74)
at org.glassfish.jersey.server.spi.internal.ParameterValueHelper.getParameterValues(ParameterValueHelper.java:88)
at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$AbstractMethodParamInvoker.getParamValues(JavaResourceMethodDispatcherProvider.java:133)
at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$ResponseOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:200)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:103)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:493)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:415)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:104)
at org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:277)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:272)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:268)
at org.glassfish.jersey.internal.Errors.process(Errors.java:316)
at org.glassfish.jersey.internal.Errors.process(Errors.java:298)
at org.glassfish.jersey.internal.Errors.process(Errors.java:268)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:289)
at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:256)
at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:703)
at org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:416)
at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:370)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:389)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:342)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:229)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.boot.actuate.web.trace.servlet.HttpTraceFilter.doFilterInternal(HttpTraceFilter.java:90)
```

I did some digging, and the problem is that it tries to use JaxbStringReaderProvider to parse the parameter, which seems to try to parse it as XML-tag. As far as I can see it, the problem comes from `getConverter`-methods following code snippet:
```
final boolean supported = (rawType.getAnnotation(XmlRootElement.class) != null
|| rawType.getAnnotation(XmlType.class) != null);
```
Which means for `org.glassfish.jersey.server.internal.inject.ParamConverterFactory` that this converter actually supports the given type (but it really doesn't since the type marshalled to xml is just the String without any tags, which this JaxbStringReaderProvider doesn't support).

Now, to get around this, it is possible to just remove `@XmlType` annotation from the enum. This will cause `JaxbStringReaderProvider` to ignore the type and it will get parsed by something that can succeed. As far as I see it, this shouldn't be a problem though (but it is) and removeing the XmlType-annotation could cause other problems, depending on use cases, which is why I'm creating this issue.

Also, to make things more interesting, the problem might not be easy to repeat. The issue might disappear when restarting the application and reappear after another restart. This seems to be because the order of `ParamConverterProvider` instances used in `ParamConverterFactory` is some way random (possibly resulting from the use of `HashMap` or similar collection somewhere else).

Following are simplified code snippets that demonstrates the problem. Hopefully they make the problem more clear:

```
@XmlType // removing this annotation is a workaround
@XmlEnum
public enum MyEnum {
first,
second
}
```

```
@Controller
@Path("/myresource")
public class MyResource {
@GET
@Produces(MediaType.APPLICATION_XML)
@StatusCodes({
@ResponseCode(code = 200, condition = "Success"),
@ResponseCode(code = 403, condition = "Forbidden") })
public Response myResource(@Context Request request, @QueryParam("myenum") MyEnum myenum) {
return Response.ok("hello").build(); // This won't be executed since the param parsing fails
}
}
```

**Environment:**
Problem appears in Windows, Mac, and Linux machines

**Version:**
2.27

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.