Byte Buddy - java.lang.NoClassDefFoundError: javax/servlet/ServletRequest - java

I am trying to instrument service method of javax.servlet.Servlet interface implementations as following:
.transform(
new AgentBuilder.Transformer.ForAdvice()
.include(MyAgent.class.getClassLoader())
.advice(
named("service")
.and(takesArgument(0, ServletRequest.class))
.and(takesArgument(1, ServletResponse.class))
, "com.MyAdvice"
)
)
Now, if I attach this agent to an already running Spring boot application via agentmain - I see below exception on trying to access any web page
java.lang.LinkageError: loader constraint violation: when resolving method 'void javax.servlet.http.HttpServletRequestWrapper.<init>(javax.servlet.http.HttpServletRequest)'
the class loader org.springframework.boot.loader.LaunchedURLClassLoader #18be83e4 of the current class,
org/springframework/web/servlet/resource/ResourceUrlEncodingFilter$ResourceUrlEncodingRequestWrapper, and the class loader 'app' for the method's defining class, javax/servlet/http/HttpServletRequestWrapper,
have different Class objects for the type javax/servlet/http/HttpServletRequest used in the signature (org.springframework.web.servlet.resource.ResourceUrlEncodingFilter$ResourceUrlEncodingRequestWrapper is in unnamed module of loader org.springframework.boot.loader.LaunchedURLClassLoader #18be83e4, parent loader 'app'; javax.servlet.http.HttpServletRequestWrapper is in unnamed module of loader 'app')
I understand its because javax/servlet/http/HttpServletRequest instance is loaded from 2 different jars - one that came through agent and another through spring boot embedded tomcat. If I try to set scope as provided in agent's pom.xml [ since I do not want to include servlet-api in agent bundled jar and try use already provided servlet-api implementation from Spring boot ], I get Caused by: java.lang.NoClassDefFoundError: javax/servlet/ServletRequest - possibly because the classloader loading the agent can't see spring boot provided servlet api.
Is there any possible workaround or fix to resolve this situation? Thank you for your time and feedback.

Ideally, your agent does not contain such classes. Rather, match classes by their name: takesArgument(0, named("javax.servlet.ServletRequest")), for instance.

Related

org.springframework.boot.loader.LaunchedURLClassLoader attempted duplicate class definition for {class} is in unnamed module of loader

I am using a jar as a dependency in my Gradle Java sprint boot project. Get this error
Unexpected handler method invocation error; nested exception is java.lang.LinkageError: loader org.springframework.boot.loader.LaunchedURLClassLoader #7fb9f71f attempted duplicate class definition for xxx.class. (xxx.class is in unnamed module of loader org.springframework.boot.loader.LaunchedURLClassLoader #7fb9f71f, parent loader 'app')
this looks like the class is being loaded twice. first on the sprint boot app start up and then again when the a method is invoked which then uses that xxx.class.
The LaunchedURLClassLoader works as a url class loader which loades classes/jar at startup i assume. why it tries to load a class again?

IllegalAccessError: ClassA and class B are in unnamed module of loader 'app'

I have a spring #Configuration bean which initializes a class A. This class A, in its constructor, calls another static method in class B. When spring initializes class A it eventually fails with
java.lang.IllegalAccessError: class A tried to access method in class B (class A and classB are in unnamed module of loader 'app')
The class A and B are in present in different libraries, and I don't get any compilation issue at all.
Java version is 11, and the app uses spring boot 2.3.4-RELEASE.
I tried searching for answers but seem to find nothing on it.
Can somebody please assist here?
Adding the following to the module-info.java did the trick for me:
requires spring.core;
requires spring.beans;
requires java.instrument;
Class B is loaded by a jar which is coming as a transitive dependency to the project. Added the jar, which has class B, as a direct dependency solved the issue.

java.lang.LinkageError: loader constraint violation for Spring MVC and Thymeleaf

I am building my application using Spring MVC and Thymeleaf. I am also using Log4j for Logging.
While invoking one of the service where the Thymeleaf Template is getting loaded I get the following Error:
Handler dispatch failed; nested exception is java.lang.LinkageError: loader constraint violation: when resolving method "org.slf4j.impl.StaticLoggerBinder.getLoggerFactory()Lorg/slf4j/ILoggerFactory;" the class loader (instance of org/apache/catalina/loader/ParallelWebappClassLoader) of the current class, org/slf4j/LoggerFactory, and the class loader (instance of java/net/URLClassLoader) for the method's defining class, org/slf4j/impl/StaticLoggerBinder, have different Class objects for the type org/slf4j/ILoggerFactory used in the signature
This error is thrown when the following line of code is executed:
ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
If I invoke the same Service Again(without making any changes or restart/clean of Server) I am getting a different Error:
Handler dispatch failed; nested exception is java.lang.NoClassDefFoundError: Could not initialize class org.thymeleaf.templateresolver.ClassLoaderTemplateResolver
The gradle config file is:
compile group: 'org.thymeleaf', name: 'thymeleaf', version: '3.0.11.RELEASE'
compile group: 'org.thymeleaf', name: 'thymeleaf-spring4', version: '3.0.11.RELEASE'
Server used - Tomcat.
Any help is highly appreciated.
It would seem that you have the slf4j jar file in both the root class loader, and your webapp's WAR file. Try using maven to mark it as 'provided', so it doesn't get in the WAR. Then java won't get confused about the same classes being loaded in multiple class loaders.

How to select version of library to use in OSGI bundle

I develop jira plugin, where I should send email with images.
There is one bug with javax.mail-1.4.5, that was fixed in javax.mail-1.4.7
I tried a lot, but was not able when plugin deployed on jira tell to use my version of javax.mail (1.4.7). It all the time use javax.mail-1.4.5 from root class loader.
I all the time recieve next Exception:
java.lang.LinkageError: loader constraint violation: when resolving overridden method "javax.mail.internet.MimeMessage.getDataHandler()Ljavax/activation/DataHandler;" the class loader (instance of org/apache/felix/framework/ModuleImpl$ModuleClassLoader) of the current class, javax/mail/internet/MimeMessage, and its superclass loader (instance of org/apache/catalina/loader/WebappClassLoader), have different Class objects for the type getDataHandler used in the signature
at com.solarwinds.MailSenderJob.buildSimpleMessage(MailSenderJob.java:163)
My question is next: how to tell OSGi, that here I would like to use another version of library?
Add the specific library to the class path of your project. Or if you're using Maven, simply edit the pom.xml file.

Hibernate ENVERS Classloading issue

I am trying to integrate Hibernate Envers in an already developed application.
I ship the Hibernate Envers JAR inside an EAR package, and it throws an ugly exception regarding to class loader and some kind of conflict.
If I avoid shipping the Envers JAR inside the EAR and I place it in the "lib" directory of JBoss, then everything works fine, but I need to ship the library along with the application, since I have no access to this global "lib" directory.
I am deploying on JBoss 5.1.0.GA, using Hibernate 3.3.GA and Envers 1.2.2.GA.
Any clue?
The exception is this one:
15:31:21,621 WARN [arjLoggerI18N] [com.arjuna.ats.arjuna.coordinator.TwoPhaseCoordinator_2] TwoPhaseCoordinator.beforeC
ompletion - failed for com.arjuna.ats.internal.jta.resources.arjunacore.SynchronizationImple#84697f
java.lang.LinkageError: loader constraint violation: when resolving interface method "org.hibernate.Transaction.register
Synchronization(Ljavax/transaction/Synchronization;)V" the class loader (instance of org/jboss/classloader/spi/base/Base
ClassLoader) of the current class, org/hibernate/envers/synchronization/AuditSyncManager, and the class loader (instance
of org/jboss/classloader/spi/base/BaseClassLoader) for resolved class, org/hibernate/Transaction, have different Class
objects for the type javax/transaction/Synchronization used in the signature
at org.hibernate.envers.synchronization.AuditSyncManager.get(AuditSyncManager.java:56)
at org.hibernate.envers.event.AuditEventListener.onPostUpdate(AuditEventListener.java:163)
at org.hibernate.action.EntityUpdateAction.postUpdate(EntityUpdateAction.java:200)
at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:179)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:168)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:32
1)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1027)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:365)
at org.hibernate.ejb.AbstractEntityManagerImpl$1.beforeCompletion(AbstractEntityManagerImpl.java:504)
at com.arjuna.ats.internal.jta.resources.arjunacore.SynchronizationImple.beforeCompletion(SynchronizationImple.j
ava:101)
at com.arjuna.ats.arjuna.coordinator.TwoPhaseCoordinator.beforeCompletion(TwoPhaseCoordinator.java:269)
at com.arjuna.ats.arjuna.coordinator.TwoPhaseCoordinator.end(TwoPhaseCoordinator.java:89)
at com.arjuna.ats.arjuna.AtomicAction.commit(AtomicAction.java:177)
at com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionImple.commitAndDisassociate(TransactionImple.ja
va:1423)
at com.arjuna.ats.internal.jta.transaction.arjunacore.BaseTransaction.commit(BaseTransaction.java:137)
at com.arjuna.ats.jbossatx.BaseTransactionManagerDelegate.commit(BaseTransactionManagerDelegate.java:75)
at org.jboss.aspects.tx.TxPolicy.endTransaction(TxPolicy.java:170)
at org.jboss.aspects.tx.TxPolicy.invokeInOurTx(TxPolicy.java:87)
at org.jboss.aspects.tx.TxInterceptor$Required.invoke(TxInterceptor.java:190)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
This looks like the classic Java inheritance issue when dealing with multiple classloaders. Have you tried adding jboss-classloading.xml to your EAR META-INF/lib directory?
<classloading xmlns="urn:jboss:classloading:1.0"
parent-first="false"
domain="DefaultDomain"
top-level-classloader="true"
parent-domain="Ignored"
export-all="NON_EMPTY"
import-all="true">
</classloading>
You'll probably have to start packaging Hibernate as well as any other 3rd party libraries that you rely on being provided by the application server.
This also appears to be a good resource http://phytodata.wordpress.com/2010/10/21/demystifying-the-jboss5-jboss-classloading-xml-file/

Categories

Resources