I have 2 different Java projects, one has 2 classes: dynamicbeans.DynamicBean2 and dynamic.Validator.
On the other project, I load both of these classes dynamically and store them on an Object
class Form {
Class beanClass;
Class validatorClass;
Validator validator;
}
I then go ahead and create a Validator object using validatorClass.newInstance() and store it on validator then I create a bean object as well using beanClass.newInstance() and add it to the session.
portletRequest.setAttribute("DynamicBean2", bean);
During the lifecycle of the Form project, I call validator.validate() which loads the previously created bean object from the session (I'm running Websphere Portal Server). When I try to cast this object back into a DynamicBean2 it fails with a ClassCastException.
When I pull the object back out of the session using
faces.getApplication().createValueBinding("#{DynamicBean2}").getValue(faces);
and check the class of it using .getClass() I get dynamicbeans.DynamicBean2. This is the class I want to cast it to however when I try I get the ClassCastException.
Any reason why I'm getting this?
I am not quite following your description of the program flow, but usually when you get ClassCastExceptions you cannot explain you have loaded the class with one classloader then try to cast it to the same class loaded by another classloader. This will not work - they are represented by two different Class objects inside the JVM and the cast will fail.
There is an article about classloading in WebSphere. I cannot say how it applies to your application, but there are a number of possible solutions. I can think of at least:
Change the context class loader manually. Requires that you can actually get a reference to an appropriate class loader, which may not be possible in your case.
Thread.currentThread().setContextClassLoader(...);
Make sure the class is loaded by a class loader higher in the hierarchy.
Serialize and deserialize the object. (Yuck!)
There is probably a more appropriate way for your particular situation though.
I was getting this problem after adding a dependency to spring-boot-devtools in my Springboot project. I removed the dependency and the problem went away. My best guess at this point is that spring-boot-devtools brings in a new classloader and that causes the issue of class casting problems between different classloaders in certain cases where the new classloader is not being used by some threads.
Reference: A dozer map exception related to Spring boot devtools
The class objects were loaded in different classloaders, therefore the instances created from in each of classes are seen as 'incompatible'. This is a common issue in a an environment where there are many different classloaders being used and objects are being passed around. These issues can easily arise in Java EE and portal environments.
Casting an instance of a class requires that the Class linked to the object being casted is the same as the one loaded by the current thread context classloader.
I got the A2AClassCastException problem when trying to create a List of objects from XML using Apache Commons Digester.
List<MyTemplate> templates = new ArrayList<MyTemplate>();
Digester digester = new Digester();
digester.addObjectCreate("/path/to/template", MyTemplate.class);
digester.addSetNext("/path/to/template", "add");
// Set more rules...
digester.parse(f); // f is a pre-defined File
for(MyTemplate t : templates) { // ClassCastException: Cannot cast mypackage.MyTemplate to mypackage.MyTemplate
// Do stuff
}
As stated above, the cause is that the digester doesn't use the same ClassLoader as the rest of the program. I ran this in JBoss, and it turned out that commons-digester.jar was not in JBoss's lib directory, but rather in a webapp's lib directory. Copying the jar into mywebapp/WEB-INF/lib also solved the problem. Another solution was to casll digester.setClassLoader(MyTemplate.class.getClassLoader()), but that feels like quite an ugly solution in this context.
Had the same my.package.MyClass cannot be cast to my.package.MyClass on WildFly 10.1 and, as I understand, I did the opposite to what #Emil Lundberg described in his answer.
I have added the module (which contains my.package.MyClass) to my.war/WEB-INF/jboss-deployment-structure.xml as a dependency
<dependencies>
...
<module name="my.package"/>
</dependencies>
and removed the corresponding jar from my.war/WEB-INF/lib, re-deployed the WAR and then the code worked as expected.
Thus, we made sure it solves the issue. Now, we need to make sure the issue won't come back, for example, when the updated version of WAR will be assembled and deployed.
For this, in the sources of those WAR, it is required to add <scope>provided</scope> for those jar in pom.xml, so that when my.war is re-assembled next time with the fix/enhancement code injected, it will not bundle this jar into my.war/WEB-INF/lib.
I had the same issue while using several JBoss instances on different machines. To bad I didn't stumble across this post earlier.
There were artifacts deployed on different machines, two of them declared class loaders with identical name.I changed one of the classloader names and everything worked fine => Beware of Copy&Paste!
Why doesn't the ClassCastException thrown mention the involved class loaders? - I think that would be very useful information.
Does anyone know if there will be anything like this available in the future? Needing to check the class loaders of 20-30 Artifacts is not that pleasant. Or is there something I missed in the exception text?
EDIT: I edited the META-INF/jboss-app.xml file and changed the name of the loader, the idea is to have a unique name. At work we use the artifact id(unique) combined with the version inserted by maven({$version}) during the build. Using dynamic fields is only optional but helps if you want to deploy different versions of the same application.
<jboss-app>
<loader-repository>
com.example:archive=unique-archive-name-{$version}
</loader-repository>
</jboss-app>
You can find some info here: https://community.jboss.org/wiki/ClassLoadingConfiguration
I had the same issue, and I finally found a workaround on java.net :
Copy all org.eclipse.persistence jar files from glassfish4/glassfish/modules to WEB-INF/lib. Then go in your glassfish-web.xml, and set class-delegate to false.
Worked for me !
I had a similar issue with JAXB and JBoss AS 7.1. The issue and solution are described here: javax.xml.bind.JAXBException: Class *** nor any of its super class is known to this context. The exception that was given was org.foo.bar.ValueSet cannot be cast to org.foo.bar.ValueSet
I had the same issue on a wildfly EJB, The EJB was returning a list of Objects and has an remote and a local interface. I used the Local interface by mistake what was working just fine up until the point you try to cast the objects in the list.
Local/Remote interface:
public interface DocumentStoreService {
#javax.ejb.Remote
interface Remote extends DocumentStoreService {
}
#javax.ejb.Local
interface Local extends DocumentStoreService {
}
The EJB bean:
#Stateless
public class DocumentStoreServiceImpl implements DocumentStoreService.Local, DocumentStoreService.Remote {
The correct spring wrapper around the EJB:
<bean id="documentStoreService" class="org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean">
<property name="jndiName" value="java:global/dpc/dpc-ejb/DocumentStoreServiceImpl!santam.apps.dpc.service.DocumentStoreService$Remote"/>
<property name="businessInterface" value="santam.apps.dpc.service.DocumentStoreService$Remote"/>
<property name="resourceRef" value="true" />
</bean>
Note the $Remote, You can change this to $Local and it will find the Local interface just fine, and also execute the methods without any issue (from a separate application on the same container), but the model objects are not marshaled and are from a different class loader if you use the local interface by mistake.
Another option:
Happened to me in weblogic, but I guess it can happen in other servers as well - if you do (just) "Publish" and therefor some of your classes are re-loaded. Instead do "Clean" so all the classes will re-loaded together.
I had same problem with an EJB lookup from another EJB.
I solved adding #Remote(MyInterface.class) to EJB class configuration
Related
I am getting a java.lang.NoClassDefFoundError when trying to instantiate some class
I will try to simplify the structure of my projects: I have 2 jar files A (with a.class inside) and B (with b.class) I am trying to instantiate a 'b' class inside 'a' code. JAR A is dependant on JAR B. JAR A is a regular JAR file which is located in application/lib and JAR B is packaged as an EJB_JAR.
I am using glassfish and J2EE with maven I am new to J2EE and I have tried to look up a little for it. I have figured out it might be a class loaders issue, as the Classloader that loads classes from lib ( A) is the Ancestor of the Classloader that loads EARs WARs and EJB_JARs hence because of visibility issues I cannot load class 'b' from 'a'
Also, when I'm trying invoke (using the "expression evaluator") Class.forName("com.package.SomeClass") in the debugger from classes located in Jar-A to load class in JAR-A I get a class, but when I try to load classes located in Jar-B I get the java.lang.NoClassDefFoundError exception.
The thing is, that the passed EJB in the constructor has all the EJB fields properly, so I thought it should work, and, everything was compiled successfully.
How do I solve this problem?
The weirdest thing:
I am using drools which resides in JAR_A and JAR_A has some regular class which tries to call b.class (in JAR_B)
calling b.class from a.class doesnt work,
but calling b.class directly from a rule (which got b.class from CommandFactory.newSetGlobal("Bclass",b))works just fine.
How Could it be?
when I pass it as an Object from JAR_B it works and invokates fine.
Recap
You say:
I am trying to instantiate a 'b' class inside 'a' code. JAR A is dependant on JAR B. JAR A is a regular JAR file which is located in application/lib and JAR B is packaged as an EJB_JAR.
From what I understand, you have a pom.xml to build jar A, which states that jar B is its <dependency/>.
Then I see two possible cases for your deployment scenarios: you are either deploying the jars to the application server as an EAR, where jar A is contained inside this EAR as a library and jar B is a deployment inside it, or you are trying to use B from another, unrelated application.
In either deployment case, this is an error, but it might be due to expressing your dependencies incorrectly, or accessing the EJB incorrectly.
Nested Deployment case
If this is a nested deployment, where jar A is contained in the EAR as a library, you have a dependency expression problem. An EAR library can not have a dependency on the EAR itself, it can only be the other way around. After all, this is the definition of a library, right? :)
You have to refactor your application to match the use case you are trying to implement here. For more info, see the excellent Patterns of Modular Architecture RefCard from DZone.
Application client case
If what you are writing is an isolated (might even be a standalone) client that is going to invoke some operations on the EJB, what you should do is create an interface (local or remote, depending on how you are deploying the client) and package it with the client application and your EJB.
Then use a JNDI lookup in your client application to obtain a reference to the remote EJB and use it via the interface:
Context foo = new InitialContext(remoteJndiServiceProperties);
MyBeanInterface bar = (MyBeanInterface)foo.lookup("com.mycompany.MyBeanInterface");
bar.doStuff();
The remote JNDI registry properties and your bean's business interface name have to be expressed properly, of course. See the EJB FAQ for Glassfish for more info.
It is even simpler if your client is running in the same deployment unit - you can just use the #EJB annotation in that case and inject a no-interface EJB reference.
For more information on standalone clients with GlassFish, see the Developing Application Clients with ACC guide which covers all possible deployment scenarios.
Some theory behind this
Run the application in a debugger (or look at the heap dump taken while your client is invoking methods on the EJB, passing it objects as parameters).
What you will see is that the EJB container (that is, your EJB) is not working with the actual class you think it is, but rather with something called a static proxy class, which is generated on the fly by the container.
Because of this, when you invoke the instanceof operator inside the EJB, checking if the class you're working with is of the correct type, it will evaluate to true, but when you try to typecast it, you will get a ClassCastException.
This is required by the EJB specification and there is not much you can do about it, except pass the objects not as references, but rather as serialized data (which is going to cost you).
It works the other way around, too, because the container must be able to intercept anything done to the EJB from outside of it, and react (such as unauthorized use of restricted methods, transaction handling, etc.).
BTW, a lot of what you are describing above is illegal. ;)
Manually loading classes using Class.forName() inside an EJB container, for example - the EJB container should manage the lifecycle of your objects and anything you can not obtain using a factory method, or even better, using "compatible" mechanisms such as CDI producers and dependency injection, should be passed to your EJBs as a parameter.
What is also questionable is the way you try to pass an instance of the EJB to an application running outside of the container. If you need to access your EJBs to invoke methods on them, you should do it by means of an EJB client, in your case most probably through a remote interface.
Also, look up the definition of classloader hell if you still want to pursue your approach - you might want to start with this article, but I guess it's just as good as any other.
I'm currently working on a project, trying to insert additional Log4j logging statements into a running webapp. To realise that, I start a Java agent via
JVM parameter when launching WildFly:
-javaagent:path/to/agent.jar
The agent's premain method receives the Instrumentation object and establishes a MBean for remote access. The logging insertion is achieved using Instrumentation and Javassist. So far, this works perfectly.
However, to keep that working, the agent.jar also has to reside in the webapp's WAR file on deployment, since the log4j Logger class used for logging ships with this JAR. If not, I get a VerifyError when the class definition is updated by Instrumentation API. But trying to load e.g. classes from java.lang by inserting code like "Math.random()" works as expected.
It's important to notice that the agent classes are loaded with an AppClassLoader which is also the parent of the application's ModuleClassLoader.
Therefore I'm wondering why classes residing in agent.jar can't be loaded by delegation through the ModuleClassLoader.
These observation brought me to the assumption that the webapp module needs to declare an explicit dependency on external JARs, even if the classes are known to the parent AppClassLoader. For security issues this would make sense to me.
Can anyone confirm these assumptions or does anyone have another idea or experience what causes this behavior?
Thanks!
---------------- EDIT ---------------------
Playing around with the WildFly classloading mechanism helped me to describe my problem more in detail. Assuming I want to load a class named com.example.LoggerClass (residing in agent.jar!) using the ModuleClassLoader in a ManagedBean belonging to my webapp:
Class<?> aClass = this.getClass().getClassLoader().loadClass("com.example.LoggerClass");
This results in a ClassNotFoundExxception!
But delegating this to the underlying AppClassLoader manually works perfectly:
Class<?> aClass = this.getClass().getClassLoader().getParent().loadClass("com.example.LoggerClass");
Now the JBoss docs concerning ModuleClassLoader's loadClass method tell the following:
Find a class, possibly delegating to other loader(s)
This may explain the behavior I showed above, assuming that ModuleClassLoader does not delegate class loading because of security issues. Is there any way to override this and make ModuleClassLoader delegate to AppClassLoader in certain cases?
An Java agent is always loaded by the system class loader. All of its dependencies must be available on the class path. If you are howver experienceing a verifier error, your byte code is illegal as verification happens before loading completes. This means, your problem is not class loader related.
Working on an existing application, it runs on Weblogic as a massive ear file.
There is custom code, written by my organization, as well as code written by the vendor that all runs on one classpath when weblogic starts up.
Some of our custom code uses spring 1.2, in the latest version of the vendors code, they use spring3. So we cannot get the ear to completely work unless we can get each component the spring version it needs in order to function. But since they are both using the classpath that weblogic is started on, either spring1.2 or spring 3.0 will be first depending on the order in the classpath.
Am I stuck? Missing something? I've never had to deal with classpaths at this level.
Thanks
Classloaders use a delegation model when loading a class. The classloader implementation first checks its cache to see if the requested class has already been loaded. This class verification improves performance in that its cached memory copy is used instead of repeated loading of a class from disk. If the class is not found in its cache, the current classloader asks its parent for the class. Only if the parent cannot load the class does the classloader attempt to load the class. If a class exists in both the parent and child classloaders, the parent version is loaded. This delegation model is followed to avoid multiple copies of the same form being loaded. Multiple copies of the same class can lead to a ClassCastException.
Think setting the following in weblogic.xml might help
prefer-web-inf-classes Element
The weblogic.xml Web application deployment descriptor contains a prefer-web-inf-classes element (a sub-element of the element). By default, this element is set to False. Setting this element to True subverts the classloader delegation model so that class definitions from the Web application are loaded in preference to class definitions in higher-level classloaders. This allows a Web application to use its own version of a third-party class, which might also be part of WebLogic Server. See "weblogic.xml Deployment Descriptor Elements".*
When using this feature, you must be careful not to mix instances created from the Web application's class definition with issuances created from the server's definition. If such instances are mixed, a ClassCastException results.
Refer to the URL below
Oracle Weblogic Server
I am working on an Eclipse 3.7 RCP-based application with multiple modules. Module A is a bunch of libraries including mybatis-3.2.2.jar. Module B depends on module A (Require-Bundle in the manifest.mf) and has code that uses MyBatis to access data in a database. I have exported packages with mapper classes and XML in module B and imported them in module A. I am building SqlSessionFactory in the code, and it works fine if I add all Mapper classes by name, e.g.
configuration.addMapper(MyMapper.class);
however when I try to add all Mappers in the package:
configuration.addMappers(MyMapper.class.getPackage().getName());
MyBatis does not see them.
I tried changing the default classloader but this did not help.
Resources.setDefaultClassLoader(this.getClass().getClassLoader());
I suspect the problem has to do with visibility of classes in an OSGI environment. If that's the case, are there any ways to fix it in the application?
Have you tried
Resources.setDefaultClassLoader(Activator.class.getClassLoader()). I think that will use the OSGi class loader for the bundle. Hopefully that will help.
configuration.addMappers uses its own ResolverUtil that uses the Thread context class loader. (At least in mybatis3).
Best bet would be to write your own scanning code and use addMapper directly. There are my references and examples below:
http://grepcode.com/file/repo1.maven.org/maven2/org.mybatis/mybatis/3.1.1/org/apache/ibatis/session/Configuration.java?av=f#518
http://grepcode.com/file/repo1.maven.org/maven2/org.mybatis/mybatis/3.1.1/org/apache/ibatis/io/ResolverUtil.java#148
EDIT: Here are some for mybatis 3.2.2
http://grepcode.com/file/repo1.maven.org/maven2/org.mybatis/mybatis/3.2.2/org/apache/ibatis/io/ResolverUtil.java#147
http://grepcode.com/file/repo1.maven.org/maven2/org.mybatis/mybatis/3.2.2/org/apache/ibatis/binding/MapperRegistry.java#86
Same thing applies, though.
I ran into a similar problem with Spring Data JPA in a Felix OSGi environment. In that case I was able to override a factory class and add this into the offending methods:
ClassLoader pre = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(context.getClassLoader());
// add mappers here or call super method
} finally {
Thread.currentThread().setContextClassLoader(pre);
}
In this case "context" was a Spring context, but you should be able to get Module B's classloader from a BundleWiring.
Bundle bundle; //get this by symbolic name if you don't have a reference
BundleWiring bundleWiring = bundle.adapt(BundleWiring.class);
bundleWiring.getClassLoader();
Hopefully the addMappers method doesn't need to access Module A's classloader in the same call. If that's the case, there's not a ton you'll be able to do unless there's a way to extend and inject a different Configuration or MapperRegistry class.
I'm creating an MVC Spring webapp.
Using: Jetty (servlet container), DataNucleus (dao platform), DB4O (embedded datastore).
When I persist an object (done from within a Spring Controller) using JDO from DataNucleus, it stores to the DB fine.
#PersistenceCapable
public class Test {
#Persistent
private String testString;
//getter-setters implemented
}
When I do a simple query for the objects I previously added I get a ClassCastException on my Test class (can't cast a.b.c.Test to a.b.c.Test).
The classloader of Test returned by JDO is (toString) [sun.misc.Launcher$AppClassLoader#5acac268], the classloader of the Test class before I persisted it to the DB is [WebAppClassLoader#1593275665]
I've gotten this far, but I don't really know what to do with a classloader issue like this, I've never spent much thought on classloaders before. Any direction is helpful.
There doesn't need to be two different versions of the class for a class cast exception to appear. Even the same class definition is seen as two different classes when loaded by two distinct classloaders. Which seems to be the case here.
Unfortunately I am not familiar with the platforms you use, so I can't give more concrete advice than this: try to experiment with moving the jar containing your Test class to different places on your web app classpath, and/or reconfiguring the Spring and Jetty classloaders so that both delegate the loading of Test to the same parent classloader.
I think that your problem might be similar to the one described here.
If so, the cure would appear to be to make sure that the jdo jarfile is loaded by a common ancestor of the classloaders.