Compile Time Weaving Null Pointer Exception

2019-06-13 20:21发布

问题:

Edit 7:

The problem seems to be how to get @Configurable working with HttpSessionListener, a workaround is suggested, but I'dd prefer not to to interact with the WebApplicationContext directly:

   @Configurable(autowire = Autowire.BY_TYPE, preConstruction = true)
    public class SessionListener implements HttpSessionListener {

        private static final Logger log;

        @Autowired
        private A a;

        @Override
        public void sessionCreated(HttpSessionEvent se) {
            a.doSomething(); // <- Throws NPE
            log.info("New session was created");
        }

        @Override
        public void sessionDestroyed(HttpSessionEvent se) {
            log.info("A session was closed");
        }
    }

Edit 6:

I made the sample project simpler: you can now run it from CLI

  1. download and extract project: http://www.2shared.com/file/KpS5xeqf/dynatable.html
  2. run mvn clean aspectj:compile
  3. run mvn gwt:run
  4. You should see in your CLI that "Why is consumer NULL here?" is printed.
  5. Expected instead is:cunsumer is not NULL!

The end is near :D

Edit 5: Sample project in GWT: pls run this in GWT development mode

http://www.2shared.com/file/eai0PV-5/dynatable.html

You will get a NPE at sessionCreated()

Requirements to run are maven + gwt 2.5

Edit 4:

It seemed the sample project wasn't a very representative one. I should reformulate the problem:

In eclipse I use GWT Development mode when I run the project as a web application. In some way this doesn't call the aspectj compiler. At least that's the only reason I can think of.

Question: How to setup Compile Time Weaving to work with running as web application (GWT Development mode).?

Edit 3:

I made a small sample project in Eclipse 4.2.1, M2e 1.4.0, STS 3.1.0, AJDT 2.2.2 that demonstrates the problem: http://www.2shared.com/file/WZ1T9l9-/autowired.html

Edit 2:

As suggested by other similar topics I took the plugins of a standard generated Roo project to avoid conflicting versions. No success yet. (Updated the org.codehaus.mojo above)

Edit 1:

I'm not sure this is normal, but when I start up the web application, I get a long log of what spring is doing , but nothing mentions any weaving / anything related to Aspectj...

I think the problem is related to this plugin in pom.xml not being compiled as I don't get any feedback in my console(I tried many other similar plugins but none work) It seems the plugin is never called when I run the web application:

<plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>aspectj-maven-plugin</artifactId>
                    <version>1.2</version>
                    <!-- NB: do not use 1.3 or 1.3.x due to MASPECTJ-90 and do not use 1.4 
                        due to declare parents issue -->
                    <dependencies>
                        <!-- NB: You must use Maven 2.0.9 or above or these are ignored (see 
                            MNG-2972) -->
                        <dependency>
                            <groupId>org.aspectj</groupId>
                            <artifactId>aspectjrt</artifactId>
                            <version>1.7.0</version>
                        </dependency>
                        <dependency>
                            <groupId>org.aspectj</groupId>
                            <artifactId>aspectjtools</artifactId>
                            <version>1.7.0</version>
                        </dependency>
                    </dependencies>
                    <executions>
                        <execution>
                            <goals>
                                <goal>compile</goal>
                                <goal>test-compile</goal>
                            </goals>
                        </execution>
                    </executions>
                    <configuration>
                        <outxml>true</outxml>
                        <aspectLibraries>
                            <aspectLibrary>
                                <groupId>org.springframework</groupId>
                                <artifactId>spring-aspects</artifactId>
                            </aspectLibrary>
                        </aspectLibraries>
                        <source>1.6</source>
                        <target>1.6</target>
                    </configuration>
                </plugin>

Original Post:

I've been searching stackoverflow and many other resources, but none of their standard solutions help me to find why an @autowired field yields to Null Pointer Exception (NPE) when accessed.

@Configurable(autowire = Autowire.BY_TYPE, preConstruction = true)
public class SessionListener implements HttpSessionListener {

    private static final Logger log;

    @Autowired
    private A a;

    @Override
    public void sessionCreated(HttpSessionEvent se) {
        a.doSomething(); // <- Throws NPE
        log.info("New session was created");
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        log.info("A session was closed");
    }
}

The A class is declared as follows:

@Service
public class B implements A {
// some implementation
}

my application context has the relevant parts:

<context:spring-configured />
<context:annotation-config />
<context:component-scan base-package='some.package' />

All necessary libraries are there. I use Spring 3.0.2. Due to my environment, I'm only able to use compile time weaving. I'm also using the Google Plugin to start GWT Development Mode. I'm using ADJT, the Spring Tool Suite, m2Eclipse and Google Plugin. I also installed AJDT configurator for m2e v1.0.

回答1:

Your App.main() method doesn't create an ApplicationContext to begin with (the JUnit test is fine, since it's annotated with @ContextConfiguration). In order to create it programmatically add the following line to your main method:

public class App {      
    public static void main( String[] args ) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("foo/application-context.xml");

        new ServiceTest().doSomething();
    }
}

EDIT1: Static solution below.

There are 2 dependencies missing:

<dependency>
  <groupId>org.springframework.security</groupId>
  <artifactId>spring-security-aspects</artifactId>
  <version>${org.springframework.version}</version>
</dependency>
<!-- https://jira.springsource.org/browse/SPR-6819 -->
<dependency>
  <groupId>javax.persistence</groupId>
  <artifactId>persistence-api</artifactId>
  <version>1.0</version>
  <scope>provided</scope>
</dependency>

I've also replaced ajdtBuildDefFile plugin parameter (the file wasn't included in the archive) with:

<includes>
  <include>**/*.java</include>
</includes>

After adjusting pom.xml that way, the compilation and the test passes:

mvn clean aspectj:compile test

EDIT1: This solution relates to dynamic weaving, which isn't the case.

To answer your specific question, add this to your application-context.xml:

<context:load-time-weaver />

An additional runtime argument for the VM will be required as well:

-javaagent:/full/path/to/spring-instrument-3.0.5.RELEASE.jar

EDIT2: In relation to the GWT app

Frankly, I'm not sure why the aspectj plugin doesn't work with your configuration. If you don't mind a quick workaround, then just use the WebApplicationContextUtils:

@Override
public void sessionCreated(HttpSessionEvent se) {       
  consumer = WebApplicationContextUtils.getWebApplicationContext(se.getSession().getServletContext()).getBean(IConsumer.class);
  ...
}