Spring and Annotations

The Spring-Framework is a non-invasive framework. This means you can develop pure POJOs without any dependencies to the framework. You don’t need implement any interface nor you need to extend any base classes. However there are a lot of useful classes and interfaces provided by Spring – do you know the HibernateTemplate? – so you can use them if you want but you aren’t forced to use them.

If you remember the Spring 1.x stream without use of these templates make it very difficult to implement DAOs. This is much better with Spring 2 and JPA. For now you need only to inject an EntityManager and use the methods of them. That’s very nice, because of the EntityManager is a class out of the JPA/EJB3 standard.

Since Spring 2 there are annotation support. Not only standardized annotations are supported. Spring provides his own annotations. This is not so nice, because the use of this annotations makes your PoJos depend on Spring.

The Sample

There are a sample project to this article. You can download it here. The sample is an Eclipse Project. You need at least 3 plugins to get the sample running:

Additional to these plugins it is recommend to install a native Maven from http://maven.apache.org. The embedded Maven of the Maven Integration sometimes have problems with Groovy-based tests. To enable another Maven Installation you can add it in the Preferences (Window -> Preferences -> Maven -> Installations). After you have prepared your Eclipse you can import the sample and run it with Run As -> Maven install.

Spring and Annotations

Spring supports a lot of annotations. Additional to the standard Java 6 annotations like (@Resource, @PostConstruct, @PreDestroy,…) there are a number of Spring-Annotations:

  • @Autowired – injets a resource byType or byName
  • @Required – marks a property as mandatory
  • @Component – marks a class as Component. This you need for @Resource, @Autowired
  • @Service – similar to @Component
  • @Controller – marks a class as Controller for SpringMVC

If you want to use dependency injection with annotations you can

package testprojects.spring.annotations;

import javax.annotations.Resource;

public class Demo{
  @Resource(name="otherResource")
  private Other resource;
}

In this case the Java field named with resource should get a reference to another bean with the symbolic name otherResource. To get this work you must define a bean with this symbolic name:

import org.springframework.stereotype;

@Component("otherResource")
public class Other{}

Now we have configured our classes with annotations. But Spring doesn’t know that he should scan our classes for annotations. This we can do with the element context:component-scan in an applicationContext.xml:

At the start of the ApplicationContext of Spring all classes in the package testprojects.spring.annotations will be scanned for annotations. If Spring found any the context will be build – similar to the XmlApplicationContext

.

The Problem

If you take a closer look at the class Other you will see the import of¬† org.springframework.stereotype. This will make the class depend to the Spring Framework. Thats very bad, because we won’t have such a dependency. But what we can do? The solution is quite simple. Let us define our own annotation for this case and re-configure Spring in that way that our annotation instead teh Spring one will be used to mark classes as Components. The definition of the annotation is simple and a one-to-one copy of the original annotation provided by Spring:

package testprojects.spring.annotations;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.stereotype.Repository;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Component {

  /**
  * The value may indicate a suggestion for a logical component name, to be
  * turned into a Spring bean in case of an autodetected component.
  *
  * @return the suggested component name, if any
  */
  String value() default "";
}

The next step is to tell Spring that he doesn’t use its own @Component-Annotation but our annotation. This can do with the context:component-scan element, too:

The important changes are the attribute use-default-filters. If you set this to false, Spring ommit his own annotations. In this case you can define you own annotation classes with the context:include-filter element.

And now… a sample

Now we want it get together. To demonstrate the mechnism we want to create an own Annotation as replacement for the Spring @Service-Annotation. Then we mark a PoJo with this annotation and write a Unittest to verify that Spring use this class as Spring-Bean.

1. Create the Service-Annotation

package testprojects.spring.annotations.Service;

@Target( { ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface MyService {

  /**
  * The value may indicate a suggestion for a logical component name, to be
  * turned into a Spring bean in case of an autodetected component.
  *
  * @return the suggested component name, if any
  */
  String value() default "";
}

2. Add this annotation to our class

import testprojects.spring.annotations.Service;

@MyService
public class ServiceBean {

}

3. Re-configure Spring to use the @MyService-Annotation

<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:p="http://www.springframework.org/schema/p"
   xsi:schemaLocation="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.xsd">

   <context:component-scan
     base-package="testprojects.spring.annotations" use-default-filters="false">
     <context:include-filter
         expression="testprojects.spring.annotations.Service"
         type="annotation" />
    </context:component-scan>
</beans>

4. Write a Unittest to verify that Spring is using the annotated class as SpringBean

@RunWith(SpringJUnit4ClassRunner)
@ContextConfiguration
public class ServiceAnnotationTest{

  @Autowired
  ServiceBean serviceBean

  @Test
  final void testServiceAnnotation(){
    Assert.assertNotNull(serviceBean)
  }
}

bcbcbc



Related posts:

  1. Vortragsreihe Bonn 28.01.2007: Leichtgewichtige Architekturen mit Spring, JPA, Maven und Groovy Gute Software sollte sich an der entsprechenden Fachdomäne orientieren und...
  2. Vortragsreihe Dortmund 17.09.2007: Leichtgewichtige Architekturen mit Spring, JPA, Maven und Groovy Gute Software sollte sich an der entsprechenden Fachdomäne orientieren und...

1 Comments.

  1. I liked reading your blog…keep up the good work.