Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AspectJ Aspect under JBoss AS 7 throws Xlint:invalidAbsoluteTypeName

I have a set of WARs that worked without problems on JBoss 6.1.0.Final that use AspectJ 1.6.12 and Spring 3.1.2.RELEASE, built with Maven. We would like to move to JBoss AS 7 in the near future, so I compiled JBoss 7.1.3.Final from source.

I decided to repackage the application as an EAR file after I had problems with individual WAR files, and so all of our code would be in one, redistributable, deployable unit.

I am having trouble getting our profiling aspect working. It is an extremely simple aspect contained in a JAR in our EAR/lib directory, that times any method annotated with the @Timed annotation:

package com.mycompany.toplayer.perf;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;


@Component
@Aspect
public class MethodTimerAdvice {
    private Logger log = LoggerFactory.getLogger(getClass());

    @SuppressWarnings("unchecked")
    @Around(value="execution(@com.mycompany.toplayer.perf.Timed * *(..))")
    public Object timeMethod(ProceedingJoinPoint pjp) throws Throwable
    {
        String methodName = pjp.getSignature().toShortString();
        long start = System.currentTimeMillis();

        Object ret = pjp.proceed();

        long end = System.currentTimeMillis();

        long total = end - start;

        long used_mem = Runtime.getRuntime().totalMemory()
                - Runtime.getRuntime().freeMemory();
        long mem_gb = used_mem / (1024 * 1024);     

        log.trace("{} | {} | {}M | {} | {} | {}", 
                new Object[] {start, total, 
                        mem_gb, 
                        Thread.currentThread().getId(), 
                        Thread.currentThread().getName(),   
                        methodName}
        );

        return ret;
    }
}

Note that the annotation is in the same package.
Here is the relevant Spring configuration file for the aspect, again it is very simple:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <context:component-scan base-package="com.mycompany" />
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

</beans>

There are three WAR files included in the EAR, but right now only one of them is using this aspect, gdm-updater.WAR. When I attempt to start the server, I get errors like this:

Caused by: java.lang.IllegalArgumentException: warning no match for this type name: Timed [Xlint:invalidAbsoluteTypeName]
    at org.aspectj.weaver.tools.PointcutParser.parsePointcutExpression(PointcutParser.java:301) [aspectjtools.jar:]
    at org.springframework.aop.aspectj.AspectJExpressionPointcut.buildPointcutExpression(AspectJExpressionPointcut.java:207) [spring-aop-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.aop.aspectj.AspectJExpressionPointcut.getFallbackPointcutExpression(AspectJExpressionPointcut.java:358) [spring-aop-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.aop.aspectj.AspectJExpressionPointcut.getShadowMatch(AspectJExpressionPointcut.java:409) [spring-aop-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.aop.aspectj.AspectJExpressionPointcut.matches(AspectJExpressionPointcut.java:272) [spring-aop-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.aop.support.AopUtils.canApply(AopUtils.java:226) [spring-aop-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.aop.support.AopUtils.canApply(AopUtils.java:264) [spring-aop-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.aop.support.AopUtils.findAdvisorsThatCanApply(AopUtils.java:296) [spring-aop-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findAdvisorsThatCanApply(AbstractAdvisorAutoProxyCreator.java:117) [spring-aop-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findEligibleAdvisors(AbstractAdvisorAutoProxyCreator.java:87) [spring-aop-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean(AbstractAdvisorAutoProxyCreator.java:68) [spring-aop-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:359) [spring-aop-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:322) [spring-aop-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:407) [spring-beans-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.postProcessObjectFromFactoryBean(AbstractAutowireCapableBeanFactory.java:1598) [spring-beans-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:162) [spring-beans-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    ... 28 more

I also tried including AspectJ as a module, and here is the jboss-deployment-structure.xml file included with the EAR.

<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.0">
  <deployment>
    <exclusions>
      <module name="org.hibernate" slot="main"/>
    </exclusions>
  </deployment>
  <sub-deployment name="gdm-updater-1.2.0-SNAPSHOT.war"> 
      <exclusions>
          <module name="org.hibernate" slot="main"/>
        </exclusions>
        <dependencies>
          <module name="org.aspectj.tools" slot="main" />
          <module name="org.aspectj.weaver" slot="main" />
        </dependencies>
  </sub-deployment>   
</jboss-deployment-structure>

I even tried using the Maven AspectJ compiler plugin in gdm-updater.war to do compile-time weaving in gdm-updater.war's pom.xml:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>aspectj-maven-plugin</artifactId>
    <version>1.4</version>
    <configuration>
        <showWeaveInfo>true</showWeaveInfo>
        <source>${compiler.version}</source>
        <target>${compiler.version}</target>
        <Xlint>ignore</Xlint>
        <complianceLevel>${compiler.version}</complianceLevel>
        <encoding>UTF-8</encoding>
        <verbose>false</verbose>
        <aspectLibraries>
            <aspectLibrary>
                <groupId>org.springframework</groupId>
                <artifactId>spring-aspects</artifactId>
            </aspectLibrary>
        </aspectLibraries>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>compile</goal>
                <goal>test-compile</goal>
            </goals>
        </execution>
    </executions>
    <dependencies>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>${aspectj.version}</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjtools</artifactId>
            <version>${aspectj.version}</version>
        </dependency>
    </dependencies>
</plugin>   

I can't get anything working. I searched the web for answers and found a couple of links, but none seem to be relevant:

Has anyone run AspectJ with JBoss AS 7.1.1 final? - not relevant since I'm not using load-time weaving

https://issues.jboss.org/browse/AS7-3681 - not relevant since I'm not using load-time weaving or AspectJ as a Java agent

I've considered load-time weaving, but the aspect in question will soon be expanded to include some features present in the rest of that "common" jar file, and I can't break that out to the boot classpath. It would mean that every time we have a new aspect, we have to reconfigure the server.

What am I doing wrong?

like image 850
Brad Avatar asked Dec 18 '12 23:12

Brad


3 Answers

For me, for the most part this "just works". I have an example projects where I've been testing simple aspects without load-time-weaving working with JBoss AS7.

The part that doesn't work for me is that if I have specified an object like this:

<jee:jndi-lookup id="dataSource" jndi-name="jboss/datasources/ExampleDS"/>

this has problems, because JBoss internal modules are loaded with ModuleClassLoader, that has visibility only to that specific module. However Aspect-J tries to check my aspects on that and fails, because that specific classloader doesn't have my aspect class loaded. It's the same thing as explained here.

Workaround is to have a dependency on jdbc internals in module.xml / jboss-deployment-structure.xml:

<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.0">
<deployment>
  <dependencies>
    <module name="org.jboss.ironjacamar.jdbcadapters"/>
  </dependencies>
</deployment>
</jboss-deployment-structure>

If you use a debugger you can hook up on the exception java.lang.IllegalArgumentException and check which classloader is it using and what class it is trying to load from the call stack. That's what I did.

Another workaround I found was to do a JNDI lookup directly in the code and not on Spring context. That works as well.

I've also opened AS7-6305 / WFLY-826 on this issue.

Update: issue has been rejected on the JBoss side. They claim it's a problem on AspectJ. I've opened also a bug there, for which there has been no comments.

like image 87
eis Avatar answered Dec 21 '22 19:12

eis


We recently experienced a similar issue when upgrading from JBoss EAP 6.4.8 to 6.4.9.

It would appear that the DataSource implementation for our JNDI DataSources was changed from org.jboss.jca.adapters.jdbc.WrapperDataSource to org.jboss.as.connector.subsystems.datasources.WildFlyDataSource.

We added the following deployment dependency to our application's jboss-deployment-structure.xml file which has resolved the issue for us.

<module name="org.jboss.as.connector" slot="main"/>

This module contains the WildFlyDataSource implementation. Like other people in this thread we previously already had the org.jboss.ironjacamar.jdbcadapters dependency. It looks like the org.jboss.as.connector module can replace this.

As was discussed in @eis's answer the issue was related to JNDI datasources, AspectJ, Spring and classloading. The only way I was able to catch this was to run up JBoss locally and put a breakpoint on IllegalArgumentException.

An alternate fix was to proxy your DataSources using the proxy-interface in your Spring configuration - e.g.

<jee:jndi-lookup id="dataSource" jndi-name="some_jndi_name" proxy-interface="javax.sql.DataSource" />
like image 43
Ben J Avatar answered Dec 21 '22 19:12

Ben J


I found at least a partial solution here...

http://pushpendrasinghbaghel.blogspot.com/2013/01/spring-aop-and-jbossas-7.html

The problem seems to occur anytime that something needs to be advised that is loaded by the classloader that loads the core JBoss modules...

like image 34
Brad Avatar answered Dec 21 '22 17:12

Brad