Random Stuff About Stuff

Spring @Autowired and the new operator

August 09, 2012

So there I was happily shooting the breeze and added @Autowired to things like it was going out of fashion.  But I then added it to a normal bean, which I was creating using the new operator in a RowMapper. Something like this

private static final class MyBeanMapper implements RowMapper <MyBean>{  

  @Override  
  public CapSumLineBean mapRow(ResultSet resultSet, int rowNum) throws SQLException {  

    MyBean myBean = new MyBean();  
    myBean.setParam1(resultSet.getString("param1"));  
    myBean.setParam1(resultSet.getString("param1"));  
    return myBean;  
  }  
}

And MyBean looks something like

public class MyBean implements Serializable  
{  
    private static final long serialVersionUID = 1L;  
    @Autowired
    private transient SomeUtil someUtil;  
    private String param1;  
    private String param2;  
    public String getParam1() {  
        return someUtil.doSomething(this.param1);  
    }  
    public void setParam1(String param1) {  
        this.param1 = param1;  
    }  
    public String getParam2() {  
        return this.param2;  
    }  
    public void setParam2(String param2) {  
        this.param2 = param2;  
    }  
}  

So when you call getParam1 you will get a NullPointerException because the @Autowired didn’t do anything.  It didn’t do anything because this bean was created by me and not Spring and for @Autowired or any of its mates to work the bean must be Spring managed which something created by the new operator generally isn’t.

Getting MyBean Spring Managed

So ‘simple’ solution, make the bean one that’s managed by Spring.  A bit of googling and  I could create a factory class to produce these objects and tie that factory into Spring so the beans produced are Spring managed.  That seems clunky to me at the time, it may be the best approach as I started down the rabbit hole with the next bit.

It’s easy just use @Configurable

Found this
http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/aop.html#aop-atconfigurable
Add an annotation and some config and Spring will catch the new operator operation and do it’s magic, or something like that general Aspect Voodoo happens anyway.

Right… it’s never that easy I added @Configurable to MyBean and added
<context:spring-configured/> to my root-context.xml and I get the error

Caused by: java.lang.ClassNotFoundException: org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect   

Time to check the dependencies I already had

<dependency>  
  <groupId>org.aspectj</groupId>  
  <artifactId>aspectjrt</artifactId>  
  <version>${org.aspectj-version}</version>  
</dependency>  
<dependency>  
  <groupId>cglib</groupId>  
  <artifactId>cglib</artifactId>  
  <version>${cglib.version}</version>  
</dependency>

Which brought in spring-aop So I added

<dependency>  
  <groupId>org.springframework</groupId>  
  <artifactId>spring-aspects</artifactId>  
  <version>${org.springframework-version}</version>  
</dependency>  

Which stopped the errors anyway
But still getting the NullPointerException
Found something which suggested adding in
<context:annotation-config /> Which did no harm but didn’t solve anything
Next discovered was that @Configurable needs load time weaving, thought I had that I’m sure STS asked me about it, must have been compile time weaving?
Anyway I added in
<context:load-time-weaver/> Which resulted in

Caused by: java.lang.IllegalStateException: ClassLoader [org.apache.catalina.loader.WebappClassLoader] does NOT provide an 'addTransformer(ClassFileTransformer)' method. Specify a custom LoadTimeWeaver or start your Java virtual machine with Spring's agent: -javaagent:org.springframework.instrument.jar  

Turns out Tomcat isn’t that happy about load time weaving
http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/aop.html#aop-aj-ltw-environments
I got the jar from
http://mvnrepository.com/artifact/org.springframework/spring-instrument-tomcat
And added it into $CATALINAHOME_/lib
I went blunderbuss and added

<Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader" />  

to the Servers context.xml
Which lead to the error

java.lang.IllegalStateException: LifecycleProcessor not initialized - call 'refresh' before invoking lifecycle methods via the context   

Well time to throw more dependencies at this so

<dependency>  
    <groupId>org.aspectj</groupId>  
    <artifactId>aspectjweaver</artifactId>  
    <version>${org.aspectj-version}</version>  
</dependency>  

And it works!

Conclusion

Once setup with the dependencies and config elements @Configurable should just work like the rest of the magic annotations all be it there’s more Aspect Voodoo going on.  All in all it might be worth considering the factory option but this should be cleaner… I probably need to revisit the config and take out what’s not needed and I just started adding things in to try get it to work.


Written by David Kerwick who lives and works Dublin as a Java Technical Lead.