Can I use a new version of HttpClient in my Android project? - java

I need to work with HttpClient 4.2.5 in an Android project (added to the classpath). The problem is that at execution time, Android takes the default HttpClient registered in its APIs. This doesn't have all classes and methods, so I have errors like:
java.lang.NoSuchMethodError: org.apache.http.impl.client.DefaultHttpClient.setRedirectStrategy
How can I fix this issue and get execution with the version in the classpath and ignore the embedded version? I tried to change order of classpath libraries - that didn't work.

You can use HttpClientAndroidLib. As for now it is based on HttpClient 4.2.3, but I think it's quite sufficient for your needs. The author of this lib bypasses restrictions by renaming all the packages of the original HttpClient.

It sounds like Android is getting HttpClient via its bootclasspath. If that is the case, then the order of the JARs on the classpath is not relevant.
If this was "real Java(tm)", you would solve this by using an alternative bootclasspath when starting the JVM, but I don't think you can so this in an Android app1.
The best I can suggest is that you snarf the sources for HttpClient and its dependencies, tweak the package names throughout, and build new JARs. Then modify your app code to use the new classes by importing with the tweaked package names.
1 - If they allowed an app to specify an alternative bootclasspath, it would provide a new potential attack vector for malicious apps. I know that Android is supposed to implement security outside of the Davlik VM, but it is still a bad idea to remove a second line of defence implemented in the VM.

Related

Android - redefining class removed from support library (AsyncTaskCompat)

Firstly, apologies if I have not included all the required info for this question to be answered. I am somewhat new to Android development and am still getting my head around the build tools, API levels etc. So please let me know if there is any additional info I should provide to help you help me!
After updating my Android project compile sdk version to 27, I realised that version 27.0.2 of com.android.support:support-v4 no longer includes AsyncTaskCompat (that class has been deprecated & removed).
I have a third party library that is not open source, not easily replaceable, is no longer supported and still uses AsyncTaskCompat.
Since AsyncTaskCompat is open source, I was thinking I could simply reintroduce it somehow by redefining it in my project.
I've tried redefining it under my project in com.android.support.v4.os but even though the project compiles without any issues, when I run the section of the app that uses the third party library I get a crash with a class not found error for AsyncTaskCompat.
Is there something obvious I might be missing?
No need to add a specific Android Library module.
Only add the classes bellow to your project using the package name "android.support.v4.os":
AsyncTaskCompat
AsyncTaskCompatHoneycomb
Answering my own question here after another day of hacking away.
It is in fact possible to re-implement these deprecated/removed classes in a way that the dependency will be able to use it.
The steps are described here in case anyone needs it in the future
Create a new Android Library module for your app
Reimplement the missing classes using the appropriate namespace
In my case I needed to reimplement android.support.v4.os.AsyncTaskCompat which is open sourced so all I had to do was copy the code from source.
Add the module as a dependency of your main app module.

ClassCastException while sending soap request

I am working on a project which already had metro based web-service client implemented. Now, I needed to add another client for different service. I implemented new client, but now it throws exception when there are headers ( Headers are required). If I remove all metro jars, this new client works fine , but obviously my metro client fails. I need guidance on possible options,workarounds or resolutions.
Caused by: javax.xml.ws.WebServiceException: java.lang.ClassCastException: com.sun.xml.ws.message.saaj.SAAJHeader cannot be cast to com.sun.xml.ws.security.opt.impl.outgoing.SecurityHeader
at com.sun.xml.wss.jaxws.impl.SecurityClientTube.processRequest(SecurityClientTube.java:250)
at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:961)
at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:910)
at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:873)
at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:775)
at com.sun.xml.ws.client.Stub.process(Stub.java:429)
at com.sun.xml.ws.client.sei.SEIStub.doProcess(SEIStub.java:168)
at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:119)
at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:102)
at com.sun.xml.ws.client.sei.SEIStub.invoke(SEIStub.java:151)
at com.sun.proxy.$Proxy70.methodName(Unknown Source)
... 15 more
Caused by: java.lang.ClassCastException: com.sun.xml.ws.message.saaj.SAAJHeader cannot be cast to com.sun.xml.ws.security.opt.impl.outgoing.SecurityHeader
at com.sun.xml.ws.security.opt.impl.JAXBFilterProcessingContext.setJAXWSMessage(JAXBFilterProcessingContext.java:166)
at com.sun.xml.wss.jaxws.impl.SecurityTubeBase.secureOutboundMessage(SecurityTubeBase.java:381)
at com.sun.xml.wss.jaxws.impl.SecurityClientTube.processClientRequestPacket(SecurityClientTube.java:323)
at com.sun.xml.wss.jaxws.impl.SecurityClientTube.processRequest(SecurityClientTube.java:247)
I found few questions with similar problem like here, but they all end up suggesting to remove headers which is not an option for me.
P.S : For the existing webservice client that uses metro jars, we use a connector like client( its a jar that actually includes all metro related classes within itself) provided by the server parties to connect to their server (which I think is very weird). If I move anything from the connector , it voids the support agreement. So I prefer not to remove metro jars, but find alternate way to accommodate with it.
It seems fairly clear that what's happening is there are clashing versions of the metro library in the third party jar, vs the new metro libraries you are trying to use.
My first thought is, do you have any control over the ordering of the classpath? Could you put your own metro jars to either end of the classpath to see if that makes a difference?
Then perhaps it might be best to try and implement your own interface in terms of the metro libraries included in the third party library? I'm not sure if this kind of version information is available to you, but most modern IDE should be able to decompile the classes in the third party jar for you. If I were in your situation it would be the first thing I would try since it has the "least moving parts" and uses dependencies that are already available to you.
The other option is to run one or other client in a separate VM, and access through a basic RMI interface. Not ideal I know.
You might also try investigating the Maven shade plugin which supports repackaging of libraries so that they don't clash with other versions, though I'm not sure how well that works with precompiled binaries - in particular the kind of complexity that is involved in JAX-WS packages ...

WildFly RestEasy Version confusion

I want to build a REST API using RestEasy. The generated file should be deployed in a WildFly application server.
I face the issue described in the following SO-question:
AsynchronousDispatcher error
The marked solution tells me, to set the dependency to "provided". Which as far as I understand means, that the library is not included in my war file but taken directly from the app-server...
Isn't that just wrong?
My idea would be to build a self-containing war file which contains all the needed libraries in the version I need.
When provided from the app-server I do get the currently available version from there. I have not really a clue about the version... when someone has the idea to update the RestEasy library on the server, it might break my app.
I'm not sure whether I missed something or did something completely wrong?
One of the big advantages to Java EE is developing towards the API and not having to worry about the implementation. Java EE containers provide the API's and implementations for the API's. If you include implementation dependencies one of two things is likely to happen.
You're dependencies will be ignored making it pointless to include them in your deployment.
You'll get conflicts between the dependencies you included vs what the server is expecting. This could be things like:
ClassCastException because it's finding two of the same class on the class path.
MethodNotFoundException because there is a version mismatch
Various other issues with conflcts
Developing towards the API instead of the implementation also allows you to easily switch between Java EE compliant containers with no to minimal changes to your deployment. The API's are generally backwards compatible as well making version upgrades not as big of an issue.
If you want to use a fat WAR (including implementations) instead of a skinny WAR (not including the implementations) then a servlet container is probably a better solution. WildFly does have a servlet only download. I'd encourage you though to trust container to do the right thing with the implementation dependencies :). Usually the only time there is an issue with upgrading is if you're upgrading Java EE versions. Even then it's usually pretty safe.

How to use javax.xml.transform.stax in Android Studio?

I'm running into a strange problem in Android Studio. I'm also using latest JDK. I can't seem to import the following :
javax.xml.stream
javax.xml.transform.stax
They both are unavailable and I don't know why. In a non android project I'm able to import these. Any clue why these are missing in android?
If not, the simple solution is that I added these dependencies from maven. But after running I'm getting this error:
"Ill-advised or mistaken usage of a core class (java.* or javax.*) when not building a core library.
Android doesn't use the same Java JDK as what you use for a desktop or server app; it uses its own implementation of the JDK, which adds the android.* hierarchy but leaves out some packages that are in the standard JDK, especially in the javax.* Java extensions. Unfortunately for you, javax.xml.stream and javax.xml.transform.stax are among the things they didn't choose to implement. Moreover, the Android runtime won't allow you to load any java.* or javax.* classes from an external JAR file for security reasons**. This answer may describe the situation a little better.
Your best bets are probably: 1) use a different third-party library specifically built for Android, such as SimpleXML; 2) look for a repackaged version of the libraries, like this JAXB effort; or 3) use a tool like Jar Jar Links to do the repackaging for you.
Also see this excellent guide on parsing JSON and XML in Android.
** Note: I can't find any documentation from Google to substantiate this; it's just a commonly repeated "fact". If anyone can point to an authoritative statement about Android's handling of third-party java[x].* classes, please comment with a link, or edit this answer.

Why Maven requires same version of different dependencies?

I'm a student with quite some experience in Java but totally new to Maven.
I was trying to implement a RESTful service provider and client with jersey-server and jersey-client. Both also depends on jersey-json, to make use of automatic conversion between POJO and JSON. Both of them also depend on a service model I implemented myself, where the POJO definition resides.
However, the code doesn't work for me. I spent quite a few hours looking for solutions everywhere on the Internet. It turns out the reason of the failure is that I accidentally specified version of jersey-server and jersey-client as 1.14, but jersey-json as 1.9.1.
The server doesn't work at the beginning, but at some point suddenly starts working. (I have no idea how this happened.) The client never worked until I change jersey-json version to 1.14.
Why do I need to have the same version for these different dependencies?
Because one depends on the other or otherwise has a compatibility issue. This is what dependency management is all about. Run mvn dependency:tree to see exactly how these libraries relate to each other.
In this case, it seems Jersey libraries are all released together as a "bundle" - and you need to use the versions from those bundles together. See: http://jersey.java.net/nonav/documentation/latest/chapter_deps.html
Note that this is an attribute of the Jersey libraries, not Maven.
Often different jars from the same distribution are tested together and given the same version number.
If you try to mix different versions it might work, or it might not, as its not a combination which was intended or tested.

Categories