I am trying to get Load Time Weaving working with my Tomcat 7 webapp, in order to weave a class from an external jar file (located in WEB-INF/lib).
I have done the following:
Started Tomcat with the following parameters: -javaagent:/path/aspectjweaver-1.7.0.jar -classpath /path/aspectjrt-1.7.0.jar:etc
Placed aop.xml into WAR_ROOT/META-INF/, WEB-INF/lib/META_INF, WEB-INF/lib and WEB-INF/
aop.xml:
<aspectj>
<aspects>
<aspect name="ca.gc.agr.agrishare.web.jsf.chartlet.AgriShareGanttRendererAspect"/>
</aspects>
<weaver options="-verbose -debug -XnoInline">
<include within="org.jfree..*"/>
<dump within="org.jfree..*" />
</weaver>
</aspectj>
No matter where I place the file, my target class is not woven, and I keep seeing errors like this:
[WebappClassLoader#495b317b] error can't determine implemented interfaces of missing type javax.validation.ValidatorFactory
when weaving type org.hibernate.cfg.beanvalidation.TypeSafeActivator
when weaving classes
when weaving
[Xlint:cantFindType]
The fact that it is trying to weave a class outside of the package I specified, and considering that server startup time quadrupled, I think that it is trying to weave all classes.
What am I missing?
Figured it out.
WAR_ROOT/META-INF/ is the webapp metadata, looked up by servletContext.getResource("/META-INF/bla").
WAR_ROOT/WEB-INF/classes/META-INF is java classes metadata, looked up by getContextClassLoader().getResource("/META-INF/bla").
I created META-INF/aop.xml in my Config project (which is on the classpath), and everything is working properly now.
Related
We have few aspects, Aspect classes are defined with #Aspect and declared the same aspect in METAINFO/aop.xml:
aop.xml
<aspectj>
<weaver options="-Xset:weaveJavaxPackages=true">
<include within = "Test"/>
</weaver>
<aspects>
<aspect name = "Test"/>
</aspects>
</aspectj>
Below error is thrown only in IBM JDK environment with WebSphere.
Exception:
Error at Test.java::0 class {0} is already woven and has not been
built in reweavable mode [Xlint:nonReweavableTypeEncountered]
The same code works with Tomcat + Oracle JDK stack combination.
As per AspectJ Configuration.
Aspect does not require to add it to the Weaver tag, which was causing error to thrown in SystemOut.log of WAS.
<aspectj>
<weaver options="-Xset:weaveJavaxPackages=true">
// add only actual classes to be woven.
</weaver>
<aspects>
<aspect name = "Test"/>
</aspects>
</aspectj>
An aop.xml file contains two key sections: "aspects" defines one or more aspects to the weaver and controls which aspects are to be used in the weaving process; "weaver" defines weaver options and which types should be woven.
https://www.eclipse.org/aspectj/doc/next/devguide/ltw-configuration.html
I have added the line <context:load-time-weaver/>
to my application-context.xml,
and have created a META-INF\aop.xml file with the following:
<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
<weaver options="-verbose">
<!-- only weave classes in our application-specific packages -->
<include within="com.xxx.aspectj.*"/>
</weaver>
<aspects>
<aspect name="com.xxx.aspectj.StandardAspect"/>
</aspects>
</aspectj>
With the aspect including a catch-all to simply see if it is even working:
#After("call (public * *(..))")
public void interceptEverything() {
System.out.println("Hello");
}
But nothing seems to happen, any ideas?
Removing the include within tag solved my problem.
I realized that I have misinterpreted the include within tag, I thought it had meant only weave aspects in the package listed, but it meant only weave aspects into classes in the package listed.
After 12 hours of trying I don't seem to be able to get Spring load time weaving working on Tomcat.
Spring 4.2.1
Hibernate 4.3.11
Tomcat 8.09
I am trying to get an #Entity autowired.
The weaver output always says:
not weaving 'mypackage.MyEntity'
unless I also use a #Configuration annotation on it. It will then weave but I get back A SPRIGNCGLIB proxy where all the properties are null.
If I remove the #Configuration annotation (I don't think it should be there anyway) then I don't get any weaving and #Autowired property is always null.
This is my configuration:
applicationContext-beans.xml
<context:component-scan base-package="my.package" />
<context:spring-configured />
<context:load-time-weaver />
classes/META-INF/aop.xml
<aspectj>
<weaver options="-Xreweavable">
<include within="my.package.*"/>
</weaver>
<aspects>
<aspect name="org.springframework.beans.factory.aspectj.AbstractInterfaceDrivenDependencyInjectionAspect"/>
</aspects>
MyEntity.java
package my.package;
#Entity
#Table(name = "user")
#Configurable
public class User {
private Encrypter encrypter; // THE CLASS I WANT INJECTED
#Autowired
public void setEncrypter(Encrypter encrypter) {
this.encrypter = encrypter;
}
}
context.xml
<Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/>
The Tomcat lib folder has (I am not sure it needs both of these):
spring-instrument-4.2.1.RELEASE.jar
spring-tomcat-weaver-2.5.6.SEC03.jar
The apps WEB-INF/lib folder has:
aspectjweaver-1.8.6.jar
spring-aop-4.2.1.RELEASE.jar
spring-aspects-4.2.1.RELEASE.jar
I have tried starting Tomcat with
-javaagent:D:/my/path/to/server/apache-tomcat-8.0.9/lib/spring-instrument-4.2.1.RELEASE.jar
but it didn't help and according to the Spring LTW documentation the context.xml fragment is the preferred way to do this.
Does anyone have any ideas?
I have a Spring / Hibernate application. Custom type created by Hibernate needs Spring context, so I use Spring Aspects to provide it.
#Configurable(preConstruction = true)
public class EncryptedStringUserType implements EnhancedUserType {
...
#EnableSpringConfigured
#EnableLoadTimeWeaving
public class RootConfiguration {
...
After adding Spring Security, I got number of messages in stderr like this:
[AppClassLoader#14dad5dc] error can't determine implemented interfaces of missing type org.springframework.security.ldap.authentication.LdapAuthenticationProvider
when weaving type org.springframework.security.config.annotation.authentication.configurers.ldap.LdapAuthenticationProviderConfigurer
when weaving classes
when weaving
[Xlint:cantFindType]
Is it possible to specify packages of classes that should be weaved and avoid trying to weaving other ones?
SOLUTION
Put META-INF/aop.xml to resources root and exclude unnecessary packages:
<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
<weaver>
<exclude within="org.springframework.security.config.annotation.authentication.configurers.ldap.*"/>
<exclude within="org.springframework.security.config.annotation.web.configurers.openid.*"/>
</weaver>
</aspectj>
You can limit the scope of weaving by adding a <include within="your.package.here.*"/> tag to the META-INF/aop.xml file in your classpath. Here's a full example of META-INF/aop.xml taken from the Spring documentation:
<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
<weaver>
<!-- only weave classes in our application-specific packages -->
<include within="foo.*"/>
</weaver>
<aspects>
<!-- weave in just this aspect -->
<aspect name="foo.ProfilingAspect"/>
</aspects>
</aspectj>
<junit printsummary="on" fork="yes" forkmode="once"
haltonerror="false" haltonfailure="false"
failureproperty="junit.failure" showoutput="false" maxmemory="1024m">
<classpath>
<path refid="CLASSPATH_JUNIT"/>
<dirset dir="${TEST_BUILD_DIR}"/>
</classpath>
<batchtest fork="no" todir="${TEST_BUILD_DIR}">
<fileset dir="${COMP_TEST_SRC}">
<include name="**/*Test.java" />
<include name="**/Test*.java" />
<exclude name="**/EswTestCase.java" />
</fileset>
</batchtest>
<formatter type="xml" />
</junit>
this takes lot of time to generate xml report, and it thorws following error:
Caught an exception while logging the end of the build. Exception was:
java.lang.OutOfMemoryError: PermGen space
why it takes long time to genearte xml? how to resolve this error and make application to run fast. I have only max of 10 test files. I use command promt to execute ant script.
Analysis:
1)If i run batch test only for test calss which extends Junit test it execute very fast. eg:
public class ImpactsParserTest extends
TestCase{..
2)Now if i have test class which extends spring junit test as:
public class AddressLookupServiceTest
extends EswTestCase{..
public class EswTestCase extends
AbstractDependencyInjectionSpringContextTests{..
this causes junit target to run very slowly and causes outof memory error. why itis happening like this?
3) when I make batchtest fork="yes" instead of no, then build is quick and doesnt throw outof memory. But, it throws error like:
java.lang.NoClassDefFoundError
at org.apache.log4j.Logger.getLogger(Logger.java:118)
..
java.lang.NoClassDefFoundError: com.bgc.ordering.wizard.back.services.EswTestCase
even though, i have specified these jar file and class file in classpath element as:
and logger jar in
<path id="CLASSPATH_JUNIT">
<fileset dir="${BUILD_LIBS_HOME}">
<include name="*.jar" />
</fileset>
<pathelement location="${TEST_CLASSES_DIR}" />
<pathelement location="${TEST_BUILD_DIR}" />
<pathelement location="${COMP_BUILD}" />
<pathelement location="${COMP_CLASSES}" />
<path location="${APP_DIR}\bgc-esw-services\target\classes"/>
<pathelement location="${APP_DIR}\bgc-esw-web\target\classes" />
...
log4j.properties present at ${TEST_BUILD_DIR}
using: apache-ant-1.8.1 and junit-3.8.1.jar
This error occurs when the JVM runs out of space in the permanent generation heap. The memory in the Virtual Machine is divided into a number of regions. One of these regions is PermGen. It's an area of memory that is used to (among other things) load class files. The size of this memory region is fixed, i.e. it does not change when the VM is running. You can specify the size of this region with a commandline switch: -XX:MaxPermSize. The default is 64 Mb on the Sun VMs. To fix this issue you can give it a higher value like 256mb.
My guess is that you not only run unit tests you also run integration tests e.g. you have a class wired with Spring and you require their dependencies. That's why you have EswTestCase. If you just want to write unit tests I'd recommend you instantiate your class and mock the dependencies to other classes that you are not testing directly. This will minimize your memory footprint because you don't have to create your Spring application context.
This is what the JavaDoc says about AbstractDependencyInjectionSpringContextTests:
Really for integration testing, not
unit testing. You should not normally
use the Spring container for unit
tests: simply populate your POJOs in
plain JUnit tests!
As of Spring 3.0, the legacy JUnit 3.8 base class hierarchy (i.e., AbstractDependencyInjectionSpringContextTests, AbstractTransactionalDataSourceSpringContextTests, etc.) is officially deprecated and will be removed in a later release. It is recommended that you use the Spring TestContext Framework for writing integration tests. Instead of extending EswTestCase with AbstractDependencyInjectionSpringContextTests you should use the annotations.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class EswTestCase
{
...
}