Compiler runs class outside build path instead of class inside build path - java

I'm developing a java application that uses a range a parallel projects. In one of the projects I have a class that is the implementation of an interface. A problem I'm having though is that this class seems to be represented in two ways, both as a class in the build path and as a class outside the build path.
In Eclipse I can have the class open as a tab with both "path-versions", one with a "filled in J" and one with a "hollow J". This isn't a problem for me, I don't care about that, the thing is though that the compiler always seem to run the class as the "not-being-part-of-the-build-path"-version. When I debug the debugger always ends up in the class outside the build path. This causes errors and the application crashes.
I have no idea how I should solve it. In my understanding this shouldn't even be a problem, the compiler should always run classes inside the build path, right..?
Does anyone have any idea of what the problem might be?
Here's the stack trace, though I don't think it will be of much use... =\
Caused by: java.lang.NullPointerException: null
at com.smarttrust.m2m.core.services.inventory.InventoryServiceImpl.getNetworks(InventoryServiceImpl.java:244) ~[m2m-core-services-1.0.0-A-SNAPSHOT.jar:1.0.0-A-SNAPSHOT]
at com.smarttrust.m2m.ui.admin.inventory.InventoryAssignSubscription.populateDropdown(InventoryAssignSubscription.java:211) ~[classes/:na]
at com.smarttrust.m2m.ui.admin.inventory.InventoryAssignSubscription.init(InventoryAssignSubscription.java:115) ~[classes/:na]
at com.smarttrust.m2m.ui.admin.inventory.InventorySimCardTable$ActionColumnGenerator$1.buttonClick(InventorySimCardTable.java:352) ~[classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.6.0_26]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) ~[na:1.6.0_26]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) ~[na:1.6.0_26]
at java.lang.reflect.Method.invoke(Method.java:597) ~[na:1.6.0_26]
at com.vaadin.event.ListenerMethod.receiveEvent(ListenerMethod.java:490) ~[vaadin-6.6.3.jar:6.6.3]
... 23 common frames omitted

Go to project build path, in Order and Export tab.
you see all source codes which is related to your project, You should move up the class that is right (as you say the one which is in build path)

Related

error tried to access method sun.security.rsa.RSAPublicKeyImpl

Hi I try to execute my Spring application with dependency of JWT package and I found this error:
Caused by: java.lang.IllegalAccessError: tried to access method sun.security.rsa.RSAPublicKeyImpl.<init>([B)V from class com.agospass.OAuth2ResourceServerConfig
at com.agospass.OAuth2ResourceServerConfig.accessTokenConverter(OAuth2ResourceServerConfig.java:87)
at com.agospass.OAuth2ResourceServerConfig$$EnhancerBySpringCGLIB$$e9e14628.CGLIB$accessTokenConverter$3(<generated>)
at com.agospass.OAuth2ResourceServerConfig$$EnhancerBySpringCGLIB$$e9e14628$$FastClassBySpringCGLIB$$e622f9ed.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:358)
at com.agospass.OAuth2ResourceServerConfig$$EnhancerBySpringCGLIB$$e9e14628.accessTokenConverter(<generated>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162)
... 50 common frames omitted
My jdk version 8u241 and Maven 3.8.1
someone who can help me solve this problem or replace the dependency?
public class IllegalAccessError extends IncompatibleClassChangeError
Thrown if an application attempts to access or modify a field, or to
call a method that it does not have access to. Normally, this error is
caught by the compiler; this error can only occur at run time if the
definition of a class has incompatibly changed.
https://docs.oracle.com/javase/8/docs/api/java/lang/IllegalAccessError.html
Edited: For JDK 11
https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/IllegalAccessError.html
Certainly, your class OAuth2ResourceServerConfig's method accessTokenConverter is trying to invoke the method from a different class available in different jar than one it compile with. This behaviour is often seen when the same class (with same package) is present in different jars with difference in the accessibility of fields/methods.
To put it simply, one can say that at compile time your code has access to public method of class available in jar one but at runtime, thanks to classloader, your code is trying to access the private method of same class available in jar two.
You can look for RSAPublicKeyImpl class inside the dependencies present on the classpath and update/adjust the dependencies accordingly to get rid of the issue.

In java runtime, class not found exception

I am building the jar and I'm using this jar in one the my .war. When I run the program I am getting the below exception. But in that jar file, that particular class is there.
Error: java.lang.RuntimeException: java.lang.ClassNotFoundException: Class com.itc.zeas.custominputformat.CustomTextInputFormat not found
at org.apache.hadoop.conf.Configuration.getClass(Configuration.java:2195)
at org.apache.hadoop.mapreduce.task.JobContextImpl.getInputFormatClass(JobContextImpl.java:174)
at org.apache.hadoop.mapred.MapTask.runNewMapper(MapTask.java:749)
at org.apache.hadoop.mapred.MapTask.run(MapTask.java:341)
at org.apache.hadoop.mapred.YarnChild$2.run(YarnChild.java:168)
at java.security.AccessController.doPrivileged(Native Method)
at
A quick search turned this up.
Your classpath is broken (which is a very common problem in the Java world).
Depending on how you start your application, you need to revise the argument to -cp, your Class-Path entry in MANIFEST.MF or your disk layout.
Maybe you should post more information? Which tools are you using to develop the program, which parameters when compiling, etc..

Java: Two jars in project with same class.

I have a java project that is using two imported jars with the same class (com.sun.mail.imap.IMAPFolder). Is there a way to explicitly say which jar to use when importing the class? Using:
import com.sun.mail.imap.IMAPFolder;
would seem to use the class in order of build path order but this does not seem to be the case for some reason causing
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:616)
at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:58)
Caused by: java.lang.NoSuchMethodError: com.sun.mail.imap.IMAPFolder.idle()V
at com.woodbury.GCM.HelperGmailMonitor.doEmail(HelperGmailMonitor.java:104)
at com.woodbury.GCM.Launch.listen(Launch.java:16)
at com.woodbury.GCM.Launch.main(Launch.java:10)
... 5 more
at runtime. I am building the project in eclipse.
When a class is loaded, the first implementation that matches the requested fully qualified name that is visible to the relevant ClassLoader is what gets returned. Any other implementations with the same fully qualified name are effectively hidden to that ClassLoader.
What this means in a standard Java SE application is that the first code base (e.g. a jar) listed on the classpath with the required class, provides it, and all other code bases' implementations of the same fully qualified class are hidden.
Example:
Assume that A.jar contains the compiled class
package com.stackoverflow.example;
public class Hello {
public static String getGreeting(){
return "Hello, A!"
}
}
Assume that B.jar contains the compiled class
package com.stackoverflow.example
public class Hello {
public static String getGreeting(){
return "Hello, B!"
}
}
Note that in both of the above classes have the same fully qualified name.
Assume main class is
import com.stackoverflow.example.Hello;
public class ExampleMain {
public static void main(String[] args){
System.out.println(Hello.getGreeting());
}
}
If I were to invoke my program with
java -cp A.jar:B.jar ExampleMain
the output is: Hello, A!
If I reverse the classpath like so
java -cp B.jar:A.jar ExampleMain
the output is: Hello, B!
You cannot do what you ask just in your Java source. Java was not designed for that.
This is a bad situation which can only be handled reliably with custom class loaders, each providing one of the jars you need. Since you are asking this question in the first place this is probably not the way you should go yet since that opens up a LOT of new time consuming problems.
I would strongly suggest you find out why you have two different versions of the same jar in your classpath and rework your program so you only need one version.
Yes, there is a way to fix the issue. In my scenario, I have two classes with same name and same path and eclipse always imports the wrong one. What I have done is changing the jar order in the build path and eclipse will pick the first one in the build path.
If you are using an IDE, you can set the order of exporting the files to the class loader.
I work on eclipse and I use maven. When I install the project using maven, it produced many extra jars (which i hadnt defined in my dependencies) and there was a file org.w3c.dom.Element which was present in 2 jar files and 3rd instance of the same file was also in JRE7.
In order to make sure the correct file is picked up, all I had to do was to go to Java Build Path -> Order and Export. Select the Jar file I wanted the classloader to give more preference and move it up with the button "Up".
This is how it looks.
Please note that this image is for eclipse. But for other IDEs there would definitely be a similar way to work this out.
1) In general: Yes you can have the same class in different .jar files: you just disambiguate them with a fully qualified package name. The "Date" class (present in java.util and java.sql) is a good example.
2) If you have two DIFFERENT .jar files that have the SAME fully qualified package names ... chances are, you've got a conflict. Even if you can hack around the InvocationTargetException by playing with the class loader, you might still encounter other problems. In this case, it sounds like maybe your two .jar files have two different implementations of the JavaMail API. I don't know.
3) The safest bet is to satisfy all your program's references WITHOUT risking a conflict. I believe if you took took the "official" .jar's from Oracle's JavaMail web page, you can do this:
https://java.net/projects/javamail/pages/Home
'Hope that helps!

When executing JAR, get ExceptionInInitializerError: version.properties not found

I've been writing a small project in Eclipse which runs perfectly within the IDE. Then I've build a runnable .jar file through Eclipse (which should include every dependency library inside the jar itself).
I use 3 library in my project:
derby.jar
qtjambi-4.7.1.jar
qtjambi-win32-msvc2008-4.7.1.jar
Then I use this command (in windows):
java -jar prova.jar
And I get this:
Connected to database
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoa
der.java:58)
Caused by: java.lang.ExceptionInInitializerError: version.properties not found!
at com.trolltech.qt.Utilities.<clinit>(Unknown Source)
at com.trolltech.qt.QtJambi_LibraryInitializer.<clinit>(Unknown Source)
at com.trolltech.qt.QtJambiObject.<clinit>(Unknown Source)
at WAAAGH.main(WAAAGH.java:52)
... 5 more
As you can see the derby.jar is working as expected ("Connected to database"), but there's an error with Qt-Jambi that I can't understand. Any idea?
EDIT: WAAAGH is the class containing the main method, line 52 consists in:
QApplication.initialize(args);
How is QtJambiObject getting loaded? Have you packeged it inside your prova.jar? The missing file version.properties should be part of the same jar at top level (not in any subdir). It seems you have not packaged it inside prova.jar at top level. See this for explanation of how it is loaded.
You might be better off specifying all jars and main class on command line:
java -classpath prova.jar;derby.jar;qtjambi-4.7.1.jar;qtjambi-win32-msvc2008-4.7.1.jar <your main class>
replace ; with : if you are running on *nix
FWIW the location of version.properties has recently been changed to be inside the package namespace of the bundles com/trolltech/qt/version.properties. The old location was a poor design choice and that has now been corrected. The issue is that if you have another JAR in your classpath that also has a toplevel file then the ClassLoader is entitled to think that the JAR with that file is authorative for the package and it does not need to search another JAR for the file. A package is a minimum deployable unit in Java, only specialist ClassLoaders (such as those use in OSGi) have features to work around this part of the Java design.
Usually your toplevel (application JAR) will be first in the list and I bet in that JAR you have one or more files like /log4j.properties /commons-logging.properties etc... it is because one or more file exists it then masks (hides) the file in the qtjambi-X.Y.Z.jar from being seen at runtime. Which is why the problem might not exist when you test a certain scenario but then appear when you try another (when you changed ClassPath in some way).
My commit to the project at http://qt.gitorious.org/qt-jambi/qtjambi-community/commit/f18ce5da3e30b43424bf94e49adf8c4cac0d9862 better explains in code the very recent change to make life better.
It should never have been the case that you have to copy the version.properties file from the QtJambi redistributable JARs into some other part of the Class Path (like the toplevel project prova.jar in your case) this is a bug that has been corrected for the next release. It is the long term intention to remove the need for the file completely and I am 80% there with that goal, as part of that work making multiple native JARs co-exist in the same Class Path will greatly simplify deployment and getting started guides; as well as making them play with OSGi and Eclipse nicely out-the-box.
However no releases have been made yet to include this change but I am very close (within 30 days of doing so for Qt 4.7.4).
Open Source plug alert: Please consider joining the mailing list at http://lists.qt.nokia.com/pipermail/qt-jambi-interest/ from http://lists.qt.nokia.com/mailman/listinfo for announcements.

How to unit test JSON parsing

I'm working on an Android app in which I download JSON data from a web service. The class parsing the data looks something like this:
public class JsonCourseParser implements CourseParser {
public Course parseCourse(String courseData) {
Course result;
try {
JSONObject jsonObject = new JSONObject(courseData);
...
result = new Course("foo", "bar");
} catch (JSONException e) {
result = null;
}
return result;
}
}
This builds just fine and it works when I call parseCourse() from within my app, but when I try to test this method in a unit test I get this exception:
java.lang.NoClassDefFoundError: org/json/JSONException
at JsonCourseParserTest.initClass(JsonCourseParserTest.java:15)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:27)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: java.lang.ClassNotFoundException: org.json.JSONException
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
... 16 more
It seems that the classes of the org.json package which come with the Android Framework are not available in Java by default.
Is there a way I can fix this so I can unit test the classes which parse JSON?
All you need to do is add the following line to the dependency section in your build.gradle:
testImplementation 'org.json:json:20180813'
Note that you also need to use Android Studio 1.1 or higher and at least build tools version 22.0.0 or above for this to work!
testImplementation means that the dependency is included as a test dependency will only be used when your project is being compiled for executing unit tests. The supplied jar will not be included in your APK and will only be used to replace the missing classes in the org.json package.
Edit: see updated answer at the end
I've found the answer to this one. It doesn't solve my problem, but at least it explains why there is a problem.
First, I made the faulty assumption that the JSONObject (imported from the org.json package) was included as a part of the JRE. It isn't - in an Android project, this resides in android.jar (classic "duh" moment).
This discovery boosted my self confidence a bit. This could easily be solved by adding a reference to the android.jar in my unit test project - or at least so I thought for a brief moment. Doing so only gave me another error when running my test:
java.lang.RuntimeException: Stub!
at org.json.JSONObject.<init>(JSONObject.java:8)
...
At least this gave me something more to google for. What I found however, wasn't really encouraging (yet another classic "duh" moment)...
This blog describes the problem pretty well: Why Android isn’t ready for TDD, and how I tried anyway. If you don't bother to read the whole thing, the brief explanation is as follows:
The problem here is that the
android.jar supplied with the SDK is
stubbed out with no implementation
code. The solution that seems to be
expected is that you should run your
unit tests on the emulator or a real
phone.
When further doing some googling with this in mind, I found several articles, blogs and also questions here on SO regarding the issue. I'll add a few links here at the end, for those that might be looking:
android.jar In The SDK Only Has The API And Not The Implementation?
Can I use android.os.* libraries in a standalone project?
AndroidTesting
Eclipse + Android + JUnit test references android.os class = NoClassDefFoundError (not sure why on earth I didn't find this one when I initially wrote my question, I must have been completely lost...)
And there are plenty more if you look around.
There are several suggestions/solution/alternative approaches to unit testing in Android in many of those links, but I won't bother to try to make a good answer based on that (as there is obviously way too much I still don't know about Android development). If anybody has any nice tips though, I'll be glad to hear about them :)
UPDATE:
After experimenting a bit more, I actually managed to find a working solution to this specific problem. The reason why I didn't try this in the first place, was that I thought I had read somewhere that it would be problematic to include "normal" java libraries in my Android app. I was trying so many different things to get around my problem, so I thought I'd just give this a try as well - and it actually worked! Here is how:
I downloaded the source for the "real" org.json package from here: http://www.json.org/java/index.html
Next I compiled the source code and packed it together in my own json.jar
I added the newly created json.jar to the build path of my project (the main project of my Android application, not the test project)
No changes to my code, no changes to my test, only adding this library. And everything works, both my Android app and my unit tests.
I also tested stepping through the code in debug mode, and when debugging the Android app the JSONObject in my JsonCourseParser is fetched from the Android SDK (android.jar), but when debugging my unit test it is fetched from my own json.jar. Not sure if this means that the json.jar isn't included when my app is built, or if the runtime intelligently selects the correct library to use. Also not sure if this extra library might have any other effects on my final app. I guess only time will tell...
I'm using Björn Quentin's Unmock Gradle plugin, which allows you to replace stubbed classes in the default android.jar with real versions from another android.jar (e.g. Robolectric).
I had the same problem but I found a better way. The framework Roboelectric does the job. At first I just added the roboelectric.jar as external library (because I don't use Maven) to the build path of my Java JUnit test project and as "class annotation" I added #RunWith(RobolectricTestRunner.class). But then I got a NoClassDefFoundError: android/net/Uri. After I still added the android.jar itself used by the corresponding Android project (although the Android library with its android.jar was already a part of my build path), it works.
I had this exact problem in my JSON tests. Your updated answer led me to try a simpler approach, which worked for my project. It allows me to run JUnit tests, using the 'real' org.json JAR, on my non-Android classes from within Eclipse:
Download org.json's json.jar from here (or wherever): http://mvnrepository.com/artifact/org.json/json
Add a folder 'libs-test' to your project, copy the json.jar file to it
In Eclipse open: Run / Run Configurations, select JUnit / YourTestClass
On the Classpath tab, remove "Google APIs" from Bootstrap entries
Click "Add JARs", navigate to /libs-test/json.jar and add it.
Click "Close"
Run your tests

Categories