Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NumberFormatException leaks out through unmarshal #1211

Open
Tomas-Kraus opened this issue Jul 24, 2018 · 2 comments
Open

NumberFormatException leaks out through unmarshal #1211

Tomas-Kraus opened this issue Jul 24, 2018 · 2 comments

Comments

@Tomas-Kraus
Copy link
Member

Environment:
java version "1.8.0_121"
Java(TM) SE Runtime Environment (build 1.8.0_121-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.121-b13, mixed mode)

I think I'm experiencing a similar issue to what was reported against Jersey here:

http://download.oracle.com/javaee-archive/jersey.java.net/users/2010/01/9431.html
http://download.oracle.com/javaee-archive/jersey.java.net/users/2010/02/10038.html

To be specific: I'm using JAXB marshalling/unmarshalling of data using Jersey. The Java classes that describe the data are generated by xjc from an XML Schema.

If I invoke one of my API methods, where data is expected to be an int, but isn't (i.e., instead of providing an attribute upload-id="24" I provide upload-id="upload-id-goes-here"), I get back this stacktrace (from Tomcat):

HTTP Status 500 - java.lang.NumberFormatException: Not a number: upload-id-goes-here

type Exception report

message java.lang.NumberFormatException: Not a number: upload-id-goes-here

description The server encountered an internal error that prevented it from fulfilling this request.

exception

javax.servlet.ServletException:
        java.lang.NumberFormatException: Not a number:
        upload-id-goes-here
        org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:487)
        org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:425)
        org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:383)
        org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:336)
        org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:223)
        org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
        org.apache.catalina.filters.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:108)
        net.bull.javamelody.MonitoringFilter.doFilter(MonitoringFilter.java:198)
        net.bull.javamelody.MonitoringFilter.doFilter(MonitoringFilter.java:176)
        au.org.ands.vocabs.registry.api.context.ApiOriginFilter.doFilter(ApiOriginFilter.java:73) 

root cause

java.lang.NumberFormatException: Not a number:
        upload-id-goes-here
        com.sun.xml.internal.bind.DatatypeConverterImpl._parseInt(DatatypeConverterImpl.java:110)
        com.sun.xml.internal.bind.v2.model.impl.RuntimeBuiltinLeafInfoImpl$18.parse(RuntimeBuiltinLeafInfoImpl.java:725)
        com.sun.xml.internal.bind.v2.model.impl.RuntimeBuiltinLeafInfoImpl$18.parse(RuntimeBuiltinLeafInfoImpl.java:723)
        com.sun.xml.internal.bind.v2.runtime.reflect.TransducedAccessor$CompositeTransducedAccessorImpl.parse(TransducedAccessor.java:230)
        com.sun.xml.internal.bind.v2.runtime.unmarshaller.StructureLoader.startElement(StructureLoader.java:195)
        com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(UnmarshallingContext.java:559)
        com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.startElement(UnmarshallingContext.java:538)
        com.sun.xml.internal.bind.v2.runtime.unmarshaller.SAXConnector.startElement(SAXConnector.java:153)
        com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.startElement(AbstractSAXParser.java:509)
        com.sun.org.apache.xerces.internal.parsers.AbstractXMLDocumentParser.emptyElement(AbstractXMLDocumentParser.java:182)
        com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(XMLNSDocumentScannerImpl.java:351)
        com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2784)
        com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:602)
        com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:112)
        com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:505)
        com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:841)
        com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:770)
        com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
        com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1213)
        com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:643)
        com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:243)
        com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:214)
        javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:140)
        javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:123)
        org.glassfish.jersey.jaxb.internal.XmlRootElementJaxbProvider.readFrom(XmlRootElementJaxbProvider.java:140)
        org.glassfish.jersey.jaxb.internal.AbstractRootElementJaxbProvider.readFrom(AbstractRootElementJaxbProvider.java:134)
        org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.invokeReadFrom(ReaderInterceptorExecutor.java:256)
        org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.aroundReadFrom(ReaderInterceptorExecutor.java:235)
        org.glassfish.jersey.message.internal.ReaderInterceptorExecutor.proceed(ReaderInterceptorExecutor.java:155)
        org.glassfish.jersey.server.internal.MappableExceptionWrapperInterceptor.aroundReadFrom(MappableExceptionWrapperInterceptor.java:74)
        org.glassfish.jersey.message.internal.ReaderInterceptorExecutor.proceed(ReaderInterceptorExecutor.java:155)
        org.glassfish.jersey.message.internal.MessageBodyFactory.readFrom(MessageBodyFactory.java:1085)
        org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:874)
        org.glassfish.jersey.server.ContainerRequest.readEntity(ContainerRequest.java:271)
        org.glassfish.jersey.server.internal.inject.EntityParamValueFactoryProvider$EntityValueFactory.provide(EntityParamValueFactoryProvider.java:96)
        org.glassfish.jersey.server.spi.internal.ParamValueFactoryWithSource.provide(ParamValueFactoryWithSource.java:71)
        org.glassfish.jersey.server.spi.internal.ParameterValueHelper.getParameterValues(ParameterValueHelper.java:94)
        org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$AbstractMethodParamInvoker.getParamValues(JavaResourceMethodDispatcherProvider.java:127)
        org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$ResponseOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:160)
        org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:99)
        org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:389)
        org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:347)
        org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:102)
        org.glassfish.jersey.server.ServerRuntime$2.run(ServerRuntime.java:326)
        org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
        org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
        org.glassfish.jersey.internal.Errors.process(Errors.java:315)
        org.glassfish.jersey.internal.Errors.process(Errors.java:297)
        org.glassfish.jersey.internal.Errors.process(Errors.java:267)
        org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:317)
        org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:305)
        org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1154)
        org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:471)
        org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:425)
        org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:383)
        org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:336)
        org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:223)
        org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
        org.apache.catalina.filters.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:108)
        net.bull.javamelody.MonitoringFilter.doFilter(MonitoringFilter.java:198)
        net.bull.javamelody.MonitoringFilter.doFilter(MonitoringFilter.java:176)
        au.org.ands.vocabs.registry.api.context.ApiOriginFilter.doFilter(ApiOriginFilter.java:73) 

note The full stack trace of the root cause is available in the Apache Tomcat/7.0.69 logs.
Apache Tomcat/7.0.69

It seems the AbstractUnmarshallerImpl.unmarshal() method leaks the NumberFormatException, rather than wrapping it in either an UnmarshalException or a JAXBException. Is this correct behaviour?

Jersey intercepts UnmarshalExceptions and wraps them as BadRequestExceptions, and I have defined a Jersey ExceptionMapper for BadRequestExceptions, which usually catches errors when parsing XML content provided as input to my API methods. But it isn't intercepting this particular exception.

I note that within com.sun.xml.bind.v2.model.impl.RuntimeBuiltinLeafInfoImpl there are lots of places where various types of parse exceptions are wrapped as UnmarshalExceptions (using UnmarshallingContext.getInstance().handleError()). I am wondering if there should be (much?) more of this, e.g., the around the invocations of DatatypeConverterImpl._parseInt().

@Tomas-Kraus
Copy link
Member Author

@laeubi
Copy link

laeubi commented Jul 20, 2024

I also noticed this today and it looks like a bug, first the message "Not a number: upload-id-goes-here" might be clear in this case but the same happens for e.g having 1.0 versus 1 and then the message reads "Not a number: 1.0" where 1.0 obviously is a number (but not an integer).

Also this gives absolutely no context at all so it is very hard to find the cause in a larger XML document.

So it should be

  1. UnmarshallingException
  2. make clear what element/attribute
  3. say the type (e.g. 'XYZ' is not a valid facet of xsd:int)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants