Java difference between two identical classes with identical name - java

I have a class A:
public class A implements I {}
Interface I is a class coming from a jar dependency.
I can compile this code to a jar without any compilation issues.
I deployed the jar file on our server so that an application can use it. The application runs the following code
I instance = (I) someObject.getImplementationViaJNDI();
The method uses JNDI and RMI to get an instance of my interface implementation and then throws a java.lang.ClassCastException my.domain.name.A cannot be cast to my.differentdomain.name.I
I am pretty sure the problem does not lie within JNDI or RMI because the application logs all the implemented methods of my class and the name, however it also logs the following
Object my.domain.name.A implements interface: java.lang.Class
The application that tries to cast my implementation has a version of the jar file containing Interface I on its classpath, however it does not recognize that it is implemented by class A.
I wonder how java differentiates between two identical classes with the same fqdn and how the application gets to think my class implements interface java.lang.Class.

Thanks to #Jens I found the solution to my problem.
The jar file I generated has all the dependencies packed within itself, including the package with the interface.
The application which loads my jar file has the interface already loaded. But then while my jar file is being loaded, it loads the interface again, but with another classloader.
I solved the error by not packing the interface in my jar so that it started using the interface class already loaded by the loading application.

Related

When do I need to mention the application class in the `#SpringBootTest` annotation?

So my test class cannot find the beans if I do not mention the application test in the test class annotations
#RunWith(SpringJUnit4ClassRunner::class)
#SpringBootTest(classes=[MySpringApplication::class])
#WebAppConfiguration
class MyFooIT{...}
I've seen (and written) other tests (in other projects and in this) where I did not need to mention the class explicitly.
I'm not sure why this is happening and I'm suspecting not knowing might result in my running into issues later on.
When do you need to provide a class with the #SpringBootTest annotation, and when don't you?
There are two situations when you may have to specify the application class you want to use in the #SpringBootTest:
When your test class is out of the root package of your application class (more details around the structure here)
When you have more than one application class under the package of your main application. This usually happens when you have dependencies using the same package (Module A use com.example as root package, and Module B depends on Module A and also use com.example as root package)
You may check if your MyFooIT is under the hierarchy of the root package (containing MySpringApplication), or if you have multiple application classes under the same root package.

Java package versions - getting it right

I would like to get deeper understanding on how Java deals with different versions of Classes/Packages/etc., but couldn't find any resources or at least the best way to google for it. The problem is as follows.
Imagine we have some external package com.external.package that contains a definition of SomeInterface.
Now I write a java class MyClass that implements SomeInterface, and using com.external.package v1.0.0. Next I package a (lean) jar containing MyClass.
Now I plug this jar in another program that is looking for implementations of SomeInterface, but in it's dependencies, it is using com.external.package v2.0.0.
Is the reason I get Failed to find any class that implements SomeInterface that versions of SomeInterface don't match in the program and in the jar that contains a class extending it?
Basically the question I would like to find an answer for is what info do jars store regarding external dependencies? Does it store the exact versions of them and if they don't match at the runtime it complains? But why does it even allow running the program with references to same dependency, but different versions?
Is the reason I get Failed to find any class that implements SomeInterface that versions of SomeInterface don't match in the program and in the jar that contains a class extending it?
There is no "versioning" happening here. Simply, the error states no such class exists on the classpath. For example, you didn't put a -cp in your java command to add that extra JAR/class file.
Other reasons this could happen is that an API marks a class as deprecated in v1, then decides to remove it from v2. In which case, you best try to compile and test your code against the proper library versions before you package your own code. If you made an uber JAR, the classes should get shaded, and you probably wouldn't have missing classes.
Maven projects do have the concept of transitive, versioned dependencies, but you've not said anything about that
Seeing that the original question has found an answer already, it seems somewhat relevant to mention that Java Packages and JARs could be used for specifying package version information as discussed in the following documentation:
https://docs.oracle.com/javase/8/docs/technotes/guides/versioning/spec/versioning2.html#wp89936
Also, the Oracle Java Tutorials discuss them and further concepts around deployment of programs as JAR Files as documented here:
https://docs.oracle.com/javase/tutorial/deployment/jar/index.html

Same class different version, dependencies, NoSuchMethod

I am working on a web project that has 2 different dependencies being pulled into war file of the same class
(different versions, different package)
One is :
com.google.common.collect, and the other is Guava API package. When I run this service on websphere application server, it throws NoSuchMethodFound Exception at ImmutableList.copyOf. It clearly is loading the earlier class instead of the class from Guava which has the required functions.
I cannot change any dependency, how ever is it possible for me to override a particular dependency by other using maven?
How should I solve this problem?
If you have control over the WebSphere installation, you can also try this:
locate the jre lib directory of your application server (/WebSphere/AppServer/java/jre/lib)
create a directory 'endorsed' put your required jars into this directory( Guava API).
The jars in this directory will be loaded first and override what you have in you war file.
This is not recommended but you can use it as patch to override the conflicting classes.
The first matched class found on the classpath is used. Therefore if you can specify the classpath in different ways to try and influence what class is picked up. (i.e. specify the class that you want loaded first in the classpath). This is not a good practice because the Java specification does not guarntee to use the classpath order.
A better solution would be to manage the classloading yourself in the code. This can be done by
`ClassLoader myClassLoader = new MyClassLoader(libPath);
Object1 obj1 = myClassLoader .loadClass("com.google.common.collect", true);'
Now if a classloader attempts to load classes from a library, the dependent classes would be loaded by the same classloader that does not have access to the other libraries and dependencies.
Note: That if you use this and want to move to OSGi in the future you will incure some pain having to remove this code. Therefore try to limit it's use or switch to OSGi early!

How to create a JAR with only the class files needed by a given class

I have a directory full of hundreds of class files that have been constructed by a previous compilation. Let's say I have a class which only depends upon a small subset of those generated class files. Is it possible to create a JAR which only has the dependencies for the given class?
EDIT: Please note that I am not speaking of the library level dependencies (i.e. JARs). When I refer to dependencies above, I am referring to the sort of dependency that results from class A calling class B. Perhaps an example would be good. Imagine I have the following classes in my project.
public class A {
B bField;
}
public class B {
C cField;
}
public class C {
B bField;
}
Now imagine I want to build a JAR with class B, then the JAR would also need to include the class file for C because the one depends upon the other. If I wanted to build a JAR from class A, then all three classes would be included. Is there a way to examine this dependency chain and build a JAR with the result?
Several products can do this, including ProGuard.
The danger is that without exhaustive run-time analysis, or a good understanding of your code and any frameworks it uses, some classes may be missed if they've instantiated via reflection. Plugin systems, dependency injection, scripting, and so on can all interfere with the accuracy of static analysis.
Yes it is possible. you can create a file with the list of classes that you do want to include and pass that file into the jar command. The details are documented here.

NoClassDefFoundError

I am using eclipse to develop my application. In my application i have few projects and those projects have reference in EAR project.
In one of project i have created a interface and impementation for that interface.
I am trying to craete object for that class
MyInterface myObj = new MyClass();
It was not working so i started server in debug mode. I am getting NoClassDefFoundError.
Any idea why i am getting this error. I have already added new project in my project build path. If i write
MyInterface myObj = null;
i do not get any error.
Check the classpath used by the runtime configuration you're running in Eclipse, which is normally defined by the project libraries and source folders.
Since you're working with an EAR, you probably use an app server, and you need to know that most of them work with one parent classloader and a child classloader per ear or war. That means that if a class loaded by a parent classloader tries to instantiate a class which is only in a child classloader you get a NoClassDefinedError (the other way around you don't).
This was happening to me. The problem was not that "MyClass" was missing from the classpath. What was missing in my case was one of the dependencies inside MyClass (i.e. an import) and when the constructor was called it failed.
Check my related question and the answer: Class Constructor fails throwing Exception on Class Loading as well as the question before that which is when all my problems started: Weird behavior with Constructor and Class. Application hangs `forever` on Constructor

Categories

Resources