Using jackson-dataformat-xml on android - java

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?

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:
right click on /src/main (where you have /java and /res folders),
select New > Folder > Java Resources Folder,
click Finish (do not change Folder Location),
right click on new /resources folder,
select New > Directory
enter "META-INF" (without quotes),
right click on /resources/META-INF folder,
select New > Directory
enter "services" (without quotes)
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.

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.

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. :)

Related

Including javax persistence in a Cordova/Android project

I am trying to incorporate ObjectBox in my hybrid Cordova/Android project. By dint of some trial and error I have managed to figure out two of the steps involved.
The app level build.gradle file has to be modified to include the ObjectBox Gradle plugin classpath "io.objectbox:objectbox-gradle-plugin:2.5.0"
Define a build-extras.gradle file to "apply" the ObjectBox plugin ext.postBuildExtras = {apply plugin: 'io.objectbox'}
The next step according to the ObjectBox docs is to define at least one Entity class
However, the issue here is that I need to import the javax.persistence.* classes into the project. It is not clear to me how I do this. I have run into suggestions along the lines of including
compile group: 'javax.persistence', name: 'javax.persistence-api', version: '2.2'
in the dependencies section of the app level build.gradle file. However, this causes gradle to complain that it does not know the compile() function. I'd be much obliged to anyone who might be able to tell me how this should be done.
For the benefit of anyone running into this thread - you can download the JAR file for javax.persistence here. Place this line in the folder src/android/libsof your custom plugin and then modify plugin.xmlwith the line
<lib-file src='src/android/libs/name-of-javax-persistence.jar'/>

In Buildship: how can I substitute a Gradle project with a built jar?

I would like to be a able to get Eclipse to ignore one Gradle project, and instead use a pre-built version of it.
Background
I have a project "parser" written in Scala, and a dozen others written in Java. The weakest link in my tool-set is Scala IDE. I use this plugin to edit & compile Scala code, but unfortunately it breaks the Java (JDT) tooling quite badly in mixed-language projects*.
Specifically: Call-hierarchy is missing results, searches crash and so on. Also Scala IDE appears to have lost funding and the issues sound fairly fundamental, so I'm not holding my breath for these issues to be fixed.
With Maven (m2e) I had a workaround I was quite happy with:
Build as a .jar put into my local .m2 repository:
cd parser; mvn install
In Eclipse, close the "parser" project
"Like magic", m2e simply picked up the most recent 'installed' .jar and used it in place of the closed project.
An awesome answer would be how to get Gradle to do that!
However all I wish for is any solution that meets these...
Requirements
That I can open Project parser when necessary (which is seldom),
to edit and build changes via the Gradle command-line.
I will close it when done.
Other projects use the built .jar from my local .m2 repo.
(It's fine if they always do so.)
The change must not affect others who don't use Eclipse
(ideally) the change can be used by other Eclipse users
Approaches
A similar question had this good answer by #lance-java with a number of general suggestions. I think I can rule out these ideas:
composite build support / multiple repos. Other team members wouldn't think it makes sense to build this project separately, as it is quite closely integrated with the others.
dependency substitution rules - doesn't appear to meet requirement 3.
Something along the lines of lance-java's idea #4 sounds viable. Paraphrasing...
"use the eclipse plugin [in conjunction with] Buildship, e.g. using the whenMerged hook to tweak the generated .classpath [of all the Java projects]."
UPDATE: [18 Apr]: I had hit a brick wall in this approach. Buildship was not putting the built .jar onto the runtime classpath. (UPDATE 2: Now resolved - see my answer.)
Questions
The main question: How can I structure a solution to this, that will actually work & avoid any major pitfalls?
Note that the project itself has a few dependencies, specifically:
dependencies {
compile 'org.scala-lang:scala-library:2.12.4'
compileOnly 'com.google.code.findbugs:jsr305:1.3.9'
antlr 'org.antlr:antlr4:4.5.3'
}
So a sub-question may be: How to pull these in into the other projects without duplicating the definition? (If that doesn't work automatically.)
So the solution was a bit involved. After adding 'maven-publish' to create the library, I then implemented the following to force Eclipse to use the prebuilt library:
subprojects {
// Additional configuration to manipulate the Eclipse classpaths
configurations {
parserSubstitution
}
dependencies {
parserSubstitution module("com.example:parser:${project.version}")
}
apply plugin: 'eclipse'
eclipse {
classpath {
plusConfigurations += [ configurations.pseLangSubstitution ]
file {
whenMerged { cp ->
// Get Gradle to add the depedency upon
// parser-xxx.jar via 'plusConfigurations' above.
// Then this here if we have a dependency on Project(':parser')
// - If so, remove it (completing the project -> jar substitution).
// - If not, remove the .jar dependency: it wasn't needed.
def usesParser = entries.removeAll {
it instanceof ProjectDependency && it.path.startsWith('/parser')
}
def parserJar =
cp.entries.find { it instanceof Library && it.path.contains('parser-') }
if (usesParser) {
// This trick stops Buildship deleting it from the runtime classpath
parserJar ?. entryAttributes ?. remove("gradle_used_by_scope")
} else {
cp.entries.remove { parserJar }
}
}
}
}
So there are 2 parts to this:
Using 'plusConfigurations' felt a bit round-about. I ended up doing this because I could not see how to construct class Library classpath entries directly. However it could well be that this is required to implement the 'transient dependencies' correctly anyway. (See the end of the question.)
The trick to stop Buildship removing the .jar from the runtime classpath (thus deviating from a Gradle command-line launch) was provided to me by a Gradle developer in this discussion.
Usage
The solution works just as I hoped. Every time some code in this library is modified, I execute the following task of mine on the command line (which also does some other code & resource generation steps, in addition to building the parser jar):
./gradlew generateEclipse
Then in Eclipse I press keyboard shortcuts for "Gradle -> Refresh Gradle Projects", Build.
And harmony is restored. :-)
Navigating to the (prebuilt) source of parser works.
If I need to edit the source, I can open the parser project and edit it. Scala-IDE still does a good job for this.
When I'm done I execute the command, close the project and my Java tools are happy.
In parser project
You shoud use the maven-publish plugin with the publishToMavenLocal task
apply plugin: 'maven-publish'
group = 'your.company'
version = '1.0.0'
publishing {
publications {
mavenJava(MavenPublication) {
from components.java
pom.withXml {
def root = asNode()
root.appendNode('name', 'Your parser project name')
root.appendNode('description', 'Your parser project description')
}
}
}
}
Everytime you make a modification, just change the version number if necessary and go with gradle publishToMavenLocal
In other java project using parser
Just use parser as a regular dependency :
repositories {
mavenLocal()
...
}
compile 'your.company:parser:1.0.0'
If my understanding of your situation is good, it should do the trick.

What to do as AndroidSlidingUpPanel Library is using some libraries not up to date

I was trying to use AndroidSlidingUpPanel in my app but when I was trying to build the Gradle file is giving me this warning.
All com.android.support libraries must use the exact same version specification (mixing versions can lead to runtime crashes). Found versions 26.0.0-alpha1, 23.4.0. Examples include com.android.support:animated-vector-drawable:26.0.0-alpha1 and com.android.support:recyclerview-v7:23.4.0 more...
I have seen the files in GitHub and saw that the file AndroidSlidingUpPanel/library/build.gradle is using a lower version of :
compile 'com.android.support:support-v4:23.4.0'
compile 'com.android.support:support-annotations:23.4.0'
compile 'com.android.support:recyclerview-v7:23.4.0'
which should be something like this:
compile 'com.android.support:support-v4:26.+'
compile 'com.android.support:support-annotations:26.+'
compile 'com.android.support:recyclerview-v7:26.+'
When I downloaded the library and imported it as module it was giving error too:
Error:(21, 0) Could not read script
'I:\ANDROID\Android_Studio_Projects\TRYS\Theme3\maven_push.gradle' as it
does not exist.
Open File
Even after copying maven_push.gradle to root it is giving this error:Error:Could not get unknown property 'GROUP' for object of type org.gradle.api.publication.maven.internal.deployer.DefaultGroovyMavenDeployer.
So what to do?
open android studio and get to this page
press this part
it will open a drop-down menu press git and then
press clone and your done
You have two options
Post an issue in the library on GitHub and wait for the creator to update.
Add it to your project manually by pulling​ the project from git and update the libraries your self.
Remove lines referring to maven_push.gradle from the build.gradle on the specified project.
Example:
apply from: 'https://raw.github.com/chrisbanes/gradle-mvn-push/master/gradle-mvn-push.gradle'
apply from: './mvn-push.gradle'
Just comment them out. I've got this solution after going through this

Can I force the order of dependencies in my classpath with Gradle?

A project runs on Google App Engine. The project has dependency that uses a class that can't be invoked on App Engine due to security constraints (it's not on the whitelist). My (very hacky) solution was to just copy a modified version of that class into my project (matching the original Class's name and package) that doesn't need the restricted class. This works on both dev and live, I assume because my source appears in the classpath before my external dependencies.
To make it a bit cleaner, I decided to put my modified version of that class into it's own project that can be packaged up in a jar and published for anyone else to use should they face this problem.
Here's my build.gradle:
// my jar that has 'fixed' version of Class.
compile files('path/to/my-hack-0.0.1.jar')
// dependency that includes class that won't run on appengine
compile 'org.elasticsearch:elasticsearch:1.4.4'
On my local dev server, this works fine, the code finds my hacked version of the class first at runtime. On live, for some unknown reason, the version in the elasticsearch dependency is loaded first.
I know having two versions of the same class in the classpath isn't ideal but I was hoping I could reliably force my version to be at the start of the classpath. Any ideas? Alternatively, is there a better way to solve this problem?
Not really sure if this is what people visiting this question were looking for, but this was what my problem and a solution that I reached at.
Jar A: contains class XYZ
Jar B: also contains class XYZ
My Project needs Jar B on the classpath before Jar A to be able to get compiled.
Problem is Gradle sorts the dependencies based on alphabetical order post resolving them which meant Jar B will be coming after Jar A in the generated classpath leading to error while compiling.
Solution:
Declare a custom configuration and patch the compileClasspath. This is how the relevant portion of build.gradle might look like.
configurations {
priority
sourceSets.main.compileClasspath = configurations.priority + sourceSets.main.compileClasspath
}
dependencies {
priority 'org.blah:JarB:2.3'
compile 'org.blah:JarA:2.4'
...
}
It's the app engine classloader I should have been investigating, not gradle...
App Engine allows you to customise the class loader JAR ordering with a little bit of xml in your appengine-web.xml. In my case:
<class-loader-config>
<priority-specifier filename="my-hack-0.0.1.jar"/>
</class-loader-config>
This places my-hack-0.0.1.jar as the first JAR file to be searched for classes, barring those in the directory war/WEB-INF/classes/.
...Thanks to a nudge in the right direction from #Danilo Tommasina :)
UPDATE 2020:
I just hit the same problem again and came across my own question... This time, live appengine was loading a different version of org.json than was being loaded in dev. Very frustrating and no amount of fiddling the build script would fix it. For future searchers, if you're getting this:
java.lang.NoSuchMethodError: org.json.JSONObject.keySet()Ljava/util/Set;
It's because it's loading an old org.json dependency from god-knows-where. I fixed it by adding this to my appengine-web.xml:
<class-loader-config>
<priority-specifier filename="json-20180130.jar"/>
</class-loader-config>
You'll also need a matching dependency in build.gradle if you don't already have one:
compile 'org.json:json:20180130'
According to gradle dependencies documentation, the order of dependencies defines the order in the classpath. So, we can simply put the libraries in the correct order in "dependencies".
But beware! here are two rules with higher priorities:
For a dynamic version, a 'higher' static version is preferred over a 'lower' version.
Modules declared by a module descriptor file (Ivy or POM file) are preferred over modules that have an artifact file only.

Could not find property 'allJava' on source set main

Hy, I am using Android Studio 0.6.0 as of this morning, during the upgrade process I had to switch to Gradle version 0.11 to compile my Android project.
Ever since I get this annoying error which prevents me from building my project.
Error:Could not find property 'allJava' on source set main.
This property is defined only for the 'java' plugin, but I am using the 'android' plugin in my build.gradle file, so I see no reason why I should receive this error.
Does anyone know how to get rid of this message?
UPDATE:
I solved it, it seems this property is no longer available in Gradle 0.11.1, and somebody somewhere in my project was using it.
I found this line in one of the build.gradle files:
apply from: 'https://raw.github.com/chrisbanes/gradle-mvn-push/master/gradle-mvn-push.gradle'
which made a reference to another gradle configuration file, that used this property to make a task of generating JavaDocs for every .java file.
So in order to solve this problem, just look everywhere in your code for a reference to this property.
In case anyone happens upon this thread, I did a little investigating into the Gradle Android plugin source.
It appears that the allJava property was removed as it was redundant with the java property. Swapping allJava out for 'java' seems to fix the issue.
https://android.googlesource.com/platform/tools/base/+/5e71a83f74258b85d7f5306bf743c4d69d6242f8%5E%21/#F2
Consequently, the allSource property was also removed, which will break the gradle-mvn-push script as well. I have submitted a bug report for that one, linked below.
https://code.google.com/p/android/issues/detail?id=71174

Categories

Resources