Using jackson-dataformat-xml on android

2020-02-11 03:57发布

问题:

I'm strugling with using jackson-dataformat-xml on android

I have some very basic code that works fine on oracle jre

JacksonXmlModule module = new JacksonXmlModule();
module.setDefaultUseWrapper(false);
XmlMapper xmlMapper = new XmlMapper(module);

First I tried official documentation adapted for gradle (by me, not sure if done correctly):

compile 'com.fasterxml.jackson.core:jackson-core:2.5.4'
compile 'com.fasterxml.jackson.core:jackson-annotations:2.5.4'
compile 'com.fasterxml.jackson.core:jackson-databind:2.5.4'
compile 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.5.4'

compile 'org.codehaus.woodstox:woodstox-core-asl:4.4.1'
compile 'javax.xml.stream:stax-api:1.0-2'

Result: gradle fails build time about bundling corelibraries into an application

...
:app:preDexDebug
trouble processing "javax/xml/stream/EventFilter.class":
Ill-advised or mistaken usage of a core class (java.* or javax.*)
when not building a core library.
...

2nd attempt trying to follow Sean's answer (Basicly he repackages corelibs with prefix names and rebuilds jackson-dataformat-xml to use the prefixed names)

compile 'com.fasterxml.jackson.core:jackson-core:2.1.2'
compile 'com.fasterxml.jackson.core:jackson-annotations:2.1.2'
compile 'com.fasterxml.jackson.core:jackson-databind:2.1.2'
// Repackaged XML-specific libraries
compile 'edu.usf.cutr.android.xml:jackson-dataformat-xml-android:2.1.2'
compile 'edu.usf.cutr.android.xml:stax2-api-android:3.1.1'
compile 'edu.usf.cutr.android.xml:stax-api-android:1.0-2'
compile 'edu.usf.cutr.android.xml:aalto-xml-android:0.9.8'

And build time failed on duplicates

Duplicate files copied in APK META-INF/services/com.fasterxml.jackson.core.ObjectCodec

so added:

packagingOptions {
    ...
    exclude 'META-INF/services/com.fasterxml.jackson.core.JsonFactory'
    exclude 'META-INF/services/com.fasterxml.jackson.core.ObjectCodec'
}

When adding the exclusions it builds and deploys, but fails runtime on below stackdump (AFAIK it cant find the SAX provider, even tho it is added to the classpath to my understanding)

edu.usf.cutr.javax.xml.stream.FactoryConfigurationError: Provider com.bea.xml.stream.MXParserFactory not found
            at edu.usf.cutr.javax.xml.stream.FactoryFinder.newInstance(FactoryFinder.java:72)
            at edu.usf.cutr.javax.xml.stream.FactoryFinder.find(FactoryFinder.java:176)
            at edu.usf.cutr.javax.xml.stream.FactoryFinder.find(FactoryFinder.java:92)
            at edu.usf.cutr.javax.xml.stream.XMLInputFactory.newInstance(XMLInputFactory.java:136)
            at com.fasterxml.jackson.dataformat.xml.XmlFactory.<init>(XmlFactory.java:97)
            at com.fasterxml.jackson.dataformat.xml.XmlFactory.<init>(XmlFactory.java:85)
            at com.fasterxml.jackson.dataformat.xml.XmlFactory.<init>(XmlFactory.java:82)
            at com.fasterxml.jackson.dataformat.xml.XmlMapper.<init>(XmlMapper.java:46)

What is the proper way to move forward on either #1 or #2?

回答1:

Number 2 is the correct approach (Android doesn't like it when you include classes in the official Java package namespace - but then again, I wrote the original answer so I'm biased ;) ).

I believe the FactoryConfigurationError: Provider com.bea.xml.stream.MXParserFactory not found error is due to a bug in the Android build tools. In previous versions of ADT for Eclipse and Gradle plugin < 0.7.0 the /META-INF/* files are stripped from the JARs during the build process. It seems like >= v0.7.0 shouldn't have the problem according to Google, but from others' reports it sounds like it still may be problematic, and could potentially remove the META-INF/services/javax.xml.stream.XMLInputFactory file, which is required for the platform to register Aalto.

Try the workaround mentioned in AOSP issue 59658 comment 22:

  1. right click on /src/main (where you have /java and /res folders),
  2. select New > Folder > Java Resources Folder,
  3. click Finish (do not change Folder Location),
  4. right click on new /resources folder,
  5. select New > Directory
  6. enter "META-INF" (without quotes),
  7. right click on /resources/META-INF folder,
  8. select New > Directory
  9. enter "services" (without quotes)
  10. copy any file you need into /resources/META-INF/services

For you, in step 10 above you'd need to copy this file into /resources/META-INF/services. In case the file link is broken in the future, the name of the file is javax.xml.stream.XMLInputFactory and it consists of a single line:

com.fasterxml.aalto.stax.InputFactoryImpl

EDIT

If you get a "Error:duplicate files during packaging of APK... Path in archive: META-INF/services/javax.xml.stream.XMLInputFactory", you can try telling Gradle to keep the first occurrence with:

android {
  packagingOptions {
    pickFirst 'META-INF/services/javax.xml.stream.XMLInputFactory'
  }
}

EDIT 2

This bug may be affecting "pickFirst". Please make sure you're running the latest version of Android Studio, and update your local tools and Android Gradle plugin to make sure you're running the most recent version of the tools. This may be fixed in Android Studio 1.3 RC1.



回答2:

I have attempted to add XmlPull support to jackson xml. Find the forked project here:

https://github.com/finvu/jackson-dataformat-xml

Currently, only supported for version 2.9.6. (clone the branch jackson-dataformat-xml-2.9.6-XmlPull)

Sorry, I am not able to provide detailed documentation due to time constraints. If you have knowledge of git and maven to pull a specific branch and build the jar, then it should be relatively easy.



回答3:

To those who will be in need of this in the future: first integrate Jitpack in Your Android app, following their instructions: https://jitpack.io/

Then paste teh GitHub url of jackson-dataformat-xml on Jitpack sites' corresponding text box. GitHub url is: https://github.com/FasterXML/jackson-dataformat-xml. That's it! Enjoy the result. :)