FasterXML / jackson-dataformat-xml

Extension for Jackson JSON processor that adds support for serializing POJOs as XML (and deserializing from XML) as an alternative to JSON
Apache License 2.0
561 stars 221 forks source link

try to make code more robust to having stax2 classes not appear on classpath #566

Closed pjfanning closed 1 year ago

pjfanning commented 1 year ago

Based on a now deleted comment on https://github.com/FasterXML/jackson-dataformat-xml/issues/550#issuecomment-1376003827

pjfanning commented 1 year ago

Deleted comment - possibly removed after user decided it was fixable by adding the stax2-api jar.

I have an issue using the library in OSGi environment, namely WSO2 Micro Integrator. I am not entirely sure, where the issue lies. It might be Stax2 /Woodstox collision, wrong / missing service definition in manifest for Woodstox (was fixed in 6.4.0 apparently). My strong suspect tho is this alternative XML factory loading through classloader. See attached stacktrace at the bottom.

I've tried manually initialize XMLFactory and that works as expected.

        XmlFactory xmlFactory = XmlFactory.builder()
                .xmlInputFactory(new WstxInputFactory())
                .xmlOutputFactory(new WstxOutputFactory())
                .build();

        xmlMapper = new XmlMapper(xmlFactory);
I was curious, so I tried the initialization without classpath usage through service loader, basically the same solution as fallback implementation in XmlMapper. This is also working as expected.

        XMLInputFactory xmlInputFactory = XMLInputFactory.newFactory();
        XMLOutputFactory xmlOutputFactory = XMLOutputFactory.newFactory();

        XmlFactory xmlFactory = XmlFactory.builder()
                .xmlInputFactory(xmlInputFactory)
                .xmlOutputFactory(xmlOutputFactory)
                .build();

        xmlMapper = new XmlMapper(xmlFactory);
I wonder, if StaxUtils XML factory methods shouldn't also catch more exceptions like ClassNotFound and NoClassDefFoundError, or more general Exception and always try to resolve through default implementation without specifying classloader. I am no OSGi expert, but

Stack trace:

[2023-01-09 15:58:29,977] ERROR {org.eclipse.equinox.ds} - [SCR] Exception while activating instance cz.sodexo.wso2.mi.extensions.jdbc.JdbcService@27e507c of component cz.sodexo.wso2.mi.extensions.jdbc.JdbcService  java.lang.reflect.InvocationTargetException
    at jdk.internal.reflect.GeneratedMethodAccessor37.invoke(Unknown Source)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.eclipse.equinox.internal.ds.model.ServiceComponent.activate(ServiceComponent.java:235)
    at org.eclipse.equinox.internal.ds.model.ServiceComponentProp.activate(ServiceComponentProp.java:146)
    at org.eclipse.equinox.internal.ds.model.ServiceComponentProp.build(ServiceComponentProp.java:345)
    at org.eclipse.equinox.internal.ds.InstanceProcess.buildComponent(InstanceProcess.java:620)
    at org.eclipse.equinox.internal.ds.InstanceProcess.buildComponents(InstanceProcess.java:197)
    at org.eclipse.equinox.internal.ds.Resolver.getEligible(Resolver.java:386)
    at org.eclipse.equinox.internal.ds.SCRManager.serviceChanged(SCRManager.java:222)
    at org.eclipse.osgi.internal.serviceregistry.FilteredServiceListener.serviceChanged(FilteredServiceListener.java:113)
    at org.eclipse.osgi.internal.framework.BundleContextImpl.dispatchEvent(BundleContextImpl.java:985)
    at org.eclipse.osgi.framework.eventmgr.EventManager.dispatchEvent(EventManager.java:234)
    at org.eclipse.osgi.framework.eventmgr.ListenerQueue.dispatchEventSynchronous(ListenerQueue.java:151)
    at org.eclipse.osgi.internal.serviceregistry.ServiceRegistry.publishServiceEventPrivileged(ServiceRegistry.java:866)
    at org.eclipse.osgi.internal.serviceregistry.ServiceRegistry.publishServiceEvent(ServiceRegistry.java:804)
    at org.eclipse.osgi.internal.serviceregistry.ServiceRegistrationImpl.unregister(ServiceRegistrationImpl.java:227)
    at org.eclipse.equinox.internal.ds.InstanceProcess.disposeInstances(InstanceProcess.java:356)
    at org.eclipse.equinox.internal.ds.InstanceProcess.disposeInstances(InstanceProcess.java:306)
    at org.eclipse.equinox.internal.ds.Resolver.disposeComponentConfigs(Resolver.java:724)
    at org.eclipse.equinox.internal.ds.Resolver.disableComponents(Resolver.java:700)
    at org.eclipse.equinox.internal.ds.SCRManager.stoppingBundle(SCRManager.java:554)
    at org.eclipse.equinox.internal.ds.SCRManager.bundleChanged(SCRManager.java:233)
    at org.eclipse.osgi.internal.framework.BundleContextImpl.dispatchEvent(BundleContextImpl.java:973)
    at org.eclipse.osgi.framework.eventmgr.EventManager.dispatchEvent(EventManager.java:234)
    at org.eclipse.osgi.framework.eventmgr.ListenerQueue.dispatchEventSynchronous(ListenerQueue.java:151)
    at org.eclipse.osgi.internal.framework.EquinoxEventPublisher.publishBundleEventPrivileged(EquinoxEventPublisher.java:234)
    at org.eclipse.osgi.internal.framework.EquinoxEventPublisher.publishBundleEvent(EquinoxEventPublisher.java:140)
    at org.eclipse.osgi.internal.framework.EquinoxEventPublisher.publishBundleEvent(EquinoxEventPublisher.java:132)
    at org.eclipse.osgi.internal.framework.EquinoxContainerAdaptor.publishModuleEvent(EquinoxContainerAdaptor.java:231)
    at org.eclipse.osgi.container.Module.publishEvent(Module.java:493)
    at org.eclipse.osgi.container.Module.doStop(Module.java:651)
    at org.eclipse.osgi.container.Module.stop(Module.java:515)
    at org.eclipse.osgi.container.ModuleContainer$ContainerStartLevel.decStartLevel(ModuleContainer.java:1861)
    at org.eclipse.osgi.container.ModuleContainer$ContainerStartLevel.doContainerStartLevel(ModuleContainer.java:1753)
    at org.eclipse.osgi.container.SystemModule.stopWorker(SystemModule.java:275)
    at org.eclipse.osgi.internal.framework.EquinoxBundle$SystemBundle$EquinoxSystemModule.stopWorker(EquinoxBundle.java:202)
    at org.eclipse.osgi.container.Module.doStop(Module.java:653)
    at org.eclipse.osgi.container.Module.stop(Module.java:515)
    at org.eclipse.osgi.container.SystemModule.stop(SystemModule.java:207)
    at org.eclipse.osgi.internal.framework.EquinoxBundle$SystemBundle$EquinoxSystemModule$1.run(EquinoxBundle.java:220)
    at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: java.lang.NoClassDefFoundError: org/codehaus/stax2/XMLInputFactory2
    at java.base/java.lang.ClassLoader.defineClass1(Native Method)
    at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1017)
    at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:174)
    at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:800)
    at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:698)
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:621)
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:579)
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
    at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:507)
    at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:423)
    at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:415)
    at org.eclipse.osgi.internal.loader.ModuleClassLoader.loadClass(ModuleClassLoader.java:155)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
    at java.base/java.lang.Class.forName0(Native Method)
    at java.base/java.lang.Class.forName(Class.java:398)
    at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.nextProviderClass(ServiceLoader.java:1210)
    at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.hasNextService(ServiceLoader.java:1221)
    at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.hasNext(ServiceLoader.java:1265)
    at java.base/java.util.ServiceLoader$2.hasNext(ServiceLoader.java:1300)
    at java.base/java.util.ServiceLoader$3.hasNext(ServiceLoader.java:1385)
    at java.xml/javax.xml.stream.FactoryFinder$1.run(FactoryFinder.java:348)
    at java.base/java.security.AccessController.doPrivileged(Native Method)
    at java.xml/javax.xml.stream.FactoryFinder.findServiceProvider(FactoryFinder.java:337)
    at java.xml/javax.xml.stream.FactoryFinder.find(FactoryFinder.java:309)
    at java.xml/javax.xml.stream.XMLInputFactory.newFactory(XMLInputFactory.java:323)
    at com.fasterxml.jackson.dataformat.xml.util.StaxUtil.defaultInputFactory(StaxUtil.java:144)
    at com.fasterxml.jackson.dataformat.xml.XmlFactory.<init>(XmlFactory.java:123)
    at com.fasterxml.jackson.dataformat.xml.XmlFactory.<init>(XmlFactory.java:110)
    at com.fasterxml.jackson.dataformat.xml.XmlFactory.<init>(XmlFactory.java:103)
    at com.fasterxml.jackson.dataformat.xml.XmlFactory.<init>(XmlFactory.java:87)
    at com.fasterxml.jackson.dataformat.xml.XmlMapper.<init>(XmlMapper.java:135)
    at cz.sodexo.wso2.mi.extensions.jdbc.dialect.DefaultDialect.<init>(DefaultDialect.java:27)
    at cz.sodexo.wso2.mi.extensions.jdbc.dialect.PostgresDialect.<init>(PostgresDialect.java:15)
    at cz.sodexo.wso2.mi.extensions.jdbc.JdbcService.activateService(JdbcService.java:64)
    at cz.sodexo.wso2.mi.extensions.core.CommonAbstractService.activate(CommonAbstractService.java:22)
    at cz.sodexo.wso2.mi.extensions.jdbc.JdbcService.activate(JdbcService.java:51)
    ... 42 more
Caused by: java.lang.ClassNotFoundException: org.codehaus.stax2.XMLInputFactory2
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
    ... 79 more
pjfanning commented 1 year ago

I'm going to close this because stax2-api is clearly marked as required in pom.xml