
Yesterday, Joris and I gave a session at the Dutch Java Users Group. We did the session twice and had about 250 people in total attending the sessions. A lot of people asked for the code for the demos we did during the sessions. Attached you'll find the code for the AOP and Dependency Injection demos. It shows a simple aspect flushing the Hibernate session before every JDBC operation (not as robust as you'd want it in production code, but it's a start) and it also shows the CarPlant system (demo'd before in other sessions and previously attached to another blog entry) configured using the various to do Dependency Injection in Spring 2.1 (i.e. using <bean>, @Bean and @Autowired).
It's a Maven2 project, so you'll need to have Maven2 installed. To prepare an Eclipse project including all libraries, run mvn eclipse:eclipse at the command line in the carplant directory.
The sources: carplant.zip
During the session a question came up about multiple <aop:config> blocks inside one application contexts. The guy in the audience wasn't sure if two or more blocks of AOP configuration showed the expected result (advising two or more times). I don't have the guys email address, so I wanted to clarify this here a little bit. Consider the following code. The doIt() will be advised. The actual advice (for simplicity) is kept in the same class, just as the main method bootstrapping the ApplicationContext.
public void doIt() {
}
public void log() {
System.out.println("Log!");
}
public static void main(String args[]) {
ApplicationContext context =
new ClassPathXmlApplicationContext(
new String[] {"com/carplant/context1.xml", "com/carplant/context2.xml"});
Logger logger = (Logger)context.getBean("logger");
logger.doIt();
}
}
The file context2.xml is empty in this case, whereas context1.xml contains the following code:
<aop:config>
<aop:pointcut id="doItOperation" expression="execution(* doIt(..))"/>
<aop:aspect ref="logger">
<aop:before pointcut-ref="doItOperation" method="log"/>
</aop:aspect>
</aop:config>
As expected, upon calling the doIt() method we'll only get one line of output from the logger (it's only advised once).
context2.xml now is identical to context1.xml (in the example above) with the only difference that in context2.xml we don't have bean called logger. When running this scenario, we'll see two Log! output entries. The doIt() method is advised twice.
context2.xml is empty again. context1.xml on the other hand now contains two <aop:config> blocks. The only difference between the two is the pointcut identifier (this is an XML ID, so should be unique in the XML file).
<aop:config>
<aop:pointcut id="doItOperation" expression="execution(* doIt(..))"/>
<aop:aspect ref="logger">
<aop:before pointcut-ref="doItOperation" method="log"/>
</aop:aspect>
</aop:config>
<aop:config>
<aop:pointcut id="doItOperation2" expression="execution(* doIt(..))"/>
<aop:aspect ref="logger">
<aop:before pointcut-ref="doItOperation2" method="log"/>
</aop:aspect>
</aop:config>
Running this will also show that the bean will be advised twice.
Note that I'm using a 2.1 milestone release here.

Yesterday, Joris and I gave a session at the Dutch Java Users Group. We did the session twice and had about 250 people in total attending the sessions. A lot of people asked for the code for the demos we did during the sessions. Attached you'll find the code for the AOP and Dependency Injection demos. It shows a simple aspect flushing the Hibernate session before every JDBC operation (not as robust as you'd want it in production code, but it's a start) and it also shows the CarPlant system (demo'd before in other sessions and previously attached to another blog entry) configured using the various to do Dependency Injection in Spring 2.1 (i.e. using <bean>, @Bean and @Autowired).
It's a Maven2 project, so you'll need to have Maven2 installed. To prepare an Eclipse project including all libraries, run mvn eclipse:eclipse at the command line in the carplant directory.
The sources: carplant.zip
During the session a question came up about multiple <aop:config> blocks inside one application contexts. The guy in the audience wasn't sure if two or more blocks of AOP configuration showed the expected result (advising two or more times). I don't have the guys email address, so I wanted to clarify this here a little bit. Consider the following code. The doIt() will be advised. The actual advice (for simplicity) is kept in the same class, just as the main method bootstrapping the ApplicationContext.
public void doIt() {
}
public void log() {
System.out.println("Log!");
}
public static void main(String args[]) {
ApplicationContext context =
new ClassPathXmlApplicationContext(
new String[] {"com/carplant/context1.xml", "com/carplant/context2.xml"});
Logger logger = (Logger)context.getBean("logger");
logger.doIt();
}
}
The file context2.xml is empty in this case, whereas context1.xml contains the following code:
<aop:config>
<aop:pointcut id="doItOperation" expression="execution(* doIt(..))"/>
<aop:aspect ref="logger">
<aop:before pointcut-ref="doItOperation" method="log"/>
</aop:aspect>
</aop:config>
As expected, upon calling the doIt() method we'll only get one line of output from the logger (it's only advised once).
context2.xml now is identical to context1.xml (in the example above) with the only difference that in context2.xml we don't have bean called logger. When running this scenario, we'll see two Log! output entries. The doIt() method is advised twice.
context2.xml is empty again. context1.xml on the other hand now contains two <aop:config> blocks. The only difference between the two is the pointcut identifier (this is an XML ID, so should be unique in the XML file).
<aop:config>
<aop:pointcut id="doItOperation" expression="execution(* doIt(..))"/>
<aop:aspect ref="logger">
<aop:before pointcut-ref="doItOperation" method="log"/>
</aop:aspect>
</aop:config>
<aop:config>
<aop:pointcut id="doItOperation2" expression="execution(* doIt(..))"/>
<aop:aspect ref="logger">
<aop:before pointcut-ref="doItOperation2" method="log"/>
</aop:aspect>
</aop:config>
Running this will also show that the bean will be advised twice.
Note that I'm using a 2.1 milestone release here.

I was working on Spring 2.1 stuff this week with Joris. We were preparing a sample using all three ways of doing dependency injection. The sample does not only highlight dependency injection, but also features a back-end based on Hibernate.
Several features in Spring 2.1 require the ASM byte code manipulation framework. Hibernate also uses ASM, through CGLIB. There is a binary incompatibility between ASM 1.5.3 and 2.2.3. The former is used by Hibernate, the latter is used by Spring in various scenarios; specifically in some of the AOP functionality and the new @Autowired features.
The first solution is to explicitly replace the CGLIB jar for Hibernate with a nodep version (one is available from the Spring distribution) which contains a re-packaged version of ASM version 1.5.3. With Maven, this requires you to put in a few exclusions alongside your Hibernate dependency and to explicitly put in the ASM 2.2.3 dependency in your pom.
I haven't tried this, but according to the Hibernate JIRA you can change the byte code provider for Hibernate to Javassist, as commented by Max Rydahl Andersen in the bug report.

As most of you already know by now, Spring is not just about XML as lately, a number of 'official' extensions to the core offer alternatives way for configuring the container.
Spring Java Configuration 1.0 M2 was among the products released around JavaOne and, while still marked as a milestone, had an important number of updates and bugfixes:
In fact, most of the work done for 1.0 M2 was incorporating the feedback received to the initial announcement; thanks a lot to everybody involved!
In this entry, I'd like to give some examples of Java Configuration, as a true IoC annotation-based configuration.
Let's start off with Mark's example, used in his entry on Spring 2.1 annotation-driven dependency injection.
To recap, below is a diagram of the interfaces and classes used by Mark:

The wiring is done through @Autowired while some methods are marked as being part of the lifecycle, through @PostConstruct and @PreDestroy.
Translating the annotation-driven configuration to Java Configuration is pretty straight forward:
@Bean (destroyMethodName = "tearDownDatabase")
public JdbcMessageRepository messageRepo() {
JdbcMessageRepository repo = new JdbcMessageRepository();
repo.createTemplate(dataSource());
// call custom init method
repo.setUpDatabase();
return repo;
}
@Bean
public GreetingService greetService() {
GreetingServiceImpl impl = new GreetingServiceImpl();
impl.setMessageRepository(messageRepo());
return impl;
}
@ExternalBean
public abstract DataSource dataSource();
}
First, the configuration is created using a Java class marked with @Configuration. In it, 2 beans are being declared and an external one referenced.
The first bean declared is messageRepo (same as the method name) which defines also a destruction method. Notice that the custom init method is invoked through the code and thus doesn't need any annotation or declaration. You can still use Spring InitializingBean interface or the @Bean initMethodName parameter though I would recommend against that. The code above is much clearer and concise not to mention that you can pass in arguments, something unavailable when using declarative init methods.
The second bean defined is greetService which uses messageRepo as a dependency. This is where the Java Configuration magic occurs since each time greetService will be created, the Spring container will supply the bean instance behind messageRepo. That is, if messageRepo is a singleton, the same instance will be returned each time. However, if a different scope is specified, then, when a new instance has to be created, your code will be invoked. Rod already explained this so please refer to his blog entry for more information.
One addition to 1.0 M2 is the @ExternalBean annotation which references beans declared outside the current configuration while still relying on Java strong-typeness and thus, your IDE validation. @ExternalBean overrides at runtime the method it is declared on with a getBean() lookup, like this:
Of course, one can do the same thing manually especially when using ConfigurationSupport class but @ExternalBean makes things a lot more easier. Note that in the initial example I have used an abstract method to emphasize externalization, however any type of non-final method can be used:
Now that the configuration has been created, declare it as a normal bean along with the JavaConfiguration post processor:
<bean id="config" class="blog.javaconfig.JavaCfg" />
<bean id="processor"
class="org.springframework.config.java.process.ConfigurationPostProcessor" />
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
</beans>
and you are ready to go (if you are running Mark's test, make sure to use the Java Configuration xml file).
Since a picture is worth a thousands words, see below the same setup through SpringIDE:

I've used the latest SpringIDE snapshot which offers visualization, navigation and also validation for Java Configuration annotations (for example the plugin checks that destroyMethodName points to a proper method on the bean creation method return type).
Java Configuration supports most of the XML declaration features, that is you can specify scopes, autowire strategies, lazyness, depends-on as well as custom metadata at bean level (through @Bean) and as defaults (through @Configuration). In 1.0 M2 you even get the @ScopedProxy annotation, a direct replacement for <aop:scoped-proxy/>.
However, one new feature that Java Configuration offers over the traditional XML container is "bean visibility" - the ability to define beans which cannot be used outside their configuration. Again, let's look at some code:
@Bean(scope = DefaultScopes.PROTOTYPE)
public Object publicBean() {
List list = new ArrayList();
list.add(hiddenBean());
list.add(secretBean());
System.out.println("creating public bean");
return list;
}
@Bean(scope = DefaultScopes.SINGLETON)
protected Object hiddenBean() {
System.out.println("creating hidden bean");
return new String("hidden bean");
}
@Bean(scope = DefaultScopes.PROTOTYPE)
private Object secretBean() {
List list = new ArrayList();
// hidden beans can access beans defined in the 'owning' context
list.add(hiddenBean());
System.out.println("creating secret bean");
return list;
}
}
Java Configuration will use the method visibility to determine if a certain bean is public (that is if it can be used outside its declaring configuration) or private (non-public). Thus any @Bean annotated method, which is non-public, will create a hidden bean. This allows you to provide bean definition encapsulation, forbidding access whether accidental or not.
It is very important to note that hidden beans are not transformed into nested beans - they are fully featured, top-level beans: they have their own lifecycle and support custom scopes as opposed to inner beans which depend on the parent bean.
To prove this, I've marked the hiddenBean as singleton and secretBean as prototype.
Let's test the behavior with the following test:
@Override
protected void setUp() throws Exception {
context = new AnnotationApplicationContext("**/VisibilityConfiguration.class");
}
@Override
protected void tearDown() throws Exception {
context.close();
}
public void testApplicationContext() {
assertNotNull(context);
System.out.println(Arrays.toString(context.getBeanDefinitionNames()));
// I don't belive you container! I know you are hidding something
context.getBean("hiddenBean");
}
}
The test should print:
after which should fail with something like:
The first line in the console shows that secretBean and hiddenBean are not defined in the context that we hold. However, the following lines, show that the hidden bean is created once (since it is a singleton) while secretBean twice, for each publicBean, as it is a prototype.
So where are the hidden beans then? Inside a child container.
The parent container (context in our case) is completely unaware of it and thus, of any beans declared inside it. Nevertheless, beans declared inside the child context can access any beans declared inside the parent but not vice-versa. Public beans (such as publicBean) on the other hand, are 'pushed' by Java Configuration inside the parent container, but since they are declared in the same configuration as the hidden bean, they can reference the 'secret' beans during instantiation.
For those who want to ditch XML completely, Spring Java Configuration offers the AnnotationApplicationContext which uses classes rather then XML files, as you could see from the test case above. While my example works,it is not ideal since, without any caching, the application context will be created and destroyed for each test.
An alternative is to reuse the existing AbstractDependencyInjectionSpringContextTests and override the context creation appropriately:
@Override
protected ConfigurableApplicationContext createApplicationContext(String[] locations) {
GenericApplicationContext context = new GenericApplicationContext();
customizeBeanFactory(context.getDefaultListableBeanFactory());
// use Java Configuration annotation-based bean definition reader
new ConfigurationClassScanningBeanDefinitionReader(context).loadBeanDefinitions(locations);
context.refresh();
return context;
}
@Override
protected String[] getConfigLocations() {
return new String[] { "**/*.class" };
}
public void testAppCtx() {
assertNotNull(applicationContext);
}
}
(this can be further simplified through SPR-3550).
Some of you might wonder what is the best annotation configuration approach: annotation-driver injection or Java Configuration? My answer is: "it depends".
Java Configuration stays true to the IoC principle as the configuration resides outside your code, which means you have true POJOs (i.e. no configuration annotations inside your code).
The annotation-driven injection presented previously on this blog, allows objects to be a little more aware of their configuration. They can ask for dependencies, for autowiring and can even specify their scope. The injection still occurs (that is the objects are still managed by the container), but some parts of your configuration are now contained by your objects.
With JavaConfig you can configure your objects without any restrictions as you are using pure Java. You can use any number of arguments, of any type and can call any number of methods. Since it is Java, your configuration is refactoring friendly and you can benefit from your IDE auto-completion. This is extremely flexible and powerful!
On the other hand, with annotation-driven injection, you have fine-grained (class, method and even field-level) control over your objects as well as a lot more contextual information.
Consider the @Autowire method:
Spring uses the annotation not just to determine the method on which the autowiring will occur, but also the required type(s). Moreover, multi-arg methods can be used, a feature not supported by 'traditional' autowiring which uses the JavaBeans convention and thus, setters.
At the end of the day, both approaches serve one purpose: to configure the Spring container. You can use one of them, or both along with some XML and properties on top if you'd like. In fact, the Java Configuration distribution, replaces the 'traditional' XML configuration for Petclinic with an XML, annotations and Groovy based configuration. Considering this blog entry, it won't be long until JRuby will be included.
The bottom line is that you have the choice to pick whatever fits your development style better.
P.S. If you are interested in this topic, you might want to attend the following SpringOne session for an in-depth discussion
Cheers,
Costin

NOTE: This post has been updated as of May 31, 2007 to reflect the state of the 2.1-M2 official release
Two weeks ago I blogged about the new annotation-driven dependency injection capabilities of Spring 2.1, and I mentioned that I would follow-up with more info "later in the week". It turns out that was a bit optimistic, but the good news is the functionality has evolved quite a bit in the meantime. Therefore, to follow along with the examples here you will need to download the 2.1-M2 official release (or if you are one of the first people to read this updated entry and M2 is not yet available, you should grab at least nightly build #115 which you can download here).
The first thing I want to demonstrate is how to create an application context without using any XML. For those who have used Spring's BeanDefinitionReader implementations, this will look very familiar. Before creating the context however, we need a few "candidate" beans on the classpath. Continuing with the example from my previous blog, I have the following two interfaces:
…and these corresponding implementations:
@Autowired
private MessageRepository messageRepository;
public String greet(String name) {
Locale locale = Locale.getDefault();
if (messageRepository == null) {
return "Sorry, no messages";
}
String message = messageRepository.getMessage(locale.getDisplayLanguage());
return message + " " + name;
}
}
Map<String,String> messages = new HashMap<String,String>();
@PostConstruct
public void initialize() {
messages.put("English", "Welcome");
messages.put("Deutsch", "Willkommen");
}
public String getMessage(String language) {
return messages.get(language);
}
}
Now as promised… to assemble this admittedly trivial "application" without any XML:
And the result:
Essentially, this is the exact same behavior as when using the component-scan XML element from the new "context" namespace (as demonstrated in my previous blog). However, I want to focus on some of the newer features as well as customization options. First, I will remove the @Repository annotation from the StubMessageRepository, and rerun the tests which produces the following exception:
Clearly the @Autowired annotation indicates a required dependency by default, but this can easily be switched by adding the 'required' parameter with a value of 'false', such as:
@Autowired(required=false)
private MessageRepository messageRepository;
…
The result after this modification:
To make things a bit more interesting, I will add the JDBC version of the MessageRepository (also from the previous post):
private SimpleJdbcTemplate jdbcTemplate;
@Autowired
public void createTemplate(DataSource dataSource) {
this.jdbcTemplate = new SimpleJdbcTemplate(dataSource);
}
@PostConstruct
public void setUpDatabase() {
jdbcTemplate.update("create table messages (language varchar(20), message varchar(100))");
jdbcTemplate.update("insert into messages (language, message) values ('English', 'Welcome')");
jdbcTemplate.update("insert into messages (language, message) values ('Deutsch', 'Willkommen')");
}
@PreDestroy
public void tearDownDatabase() {
jdbcTemplate.update("drop table messages");
}
public String getMessage(String language) {
return jdbcTemplate.queryForObject("select message from messages where language = ?", String.class, language);
}
}
As long as the stub version still does not contain the @Repository annotation, rerunning the tests will now produce the following exception:
Obviously a chain reaction of autowiring failures has resulted since no DataSource is available in the context. However, as a firm believer in test-driven development, I would like to unit test my implementation prior to setting up the infrastructure. Luckily, the scanner is fairly customizable, and I can provide filters, such as:
boolean useDefaultFilters = false;
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context, useDefaultFilters);
scanner.addExcludeFilter(new AssignableTypeFilter(JdbcMessageRepository.class));
scanner.addIncludeFilter(new AnnotationTypeFilter(Component.class));
scanner.addIncludeFilter(new RegexPatternTypeFilter(Pattern.compile("blog\\.Stub.*")));
scanner.scan("blog");
context.refresh();
GreetingService greetingService =
(GreetingService) context.getBean("greetingServiceImpl");
String message = greetingService.greet("Standalone Beans");
System.out.println(message);
As you can see, I disabled the 'defaultFilters' and explicitly added my own. In this case, that was not completely necessary since the default includes the @Component and @Repository annotations, but I wanted to show the various filtering options - including not only annotations, but also assignable types and even regular expressions. The main goal of course was to disable the JDBC version of MessageRepository in favor of the stub, and according to my result, that is exactly what happened:
Assuming that I am now ready to incorporate the JDBC version, I will likely need to include some XML configuration for the DataSource, such as:
Then, I can combine the scanning with an XmlBeanDefinitionReader (notice that I have reverted to the default filters only):
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
scanner.scan("blog");
BeanDefinitionReader reader = new XmlBeanDefinitionReader(context);
reader.loadBeanDefinitions("classpath:/blog/dataSource.xml");
context.refresh();
GreetingService greetingService = (GreetingService) context.getBean("greetingServiceImpl");
String message = greetingService.greet("Hybrid Beans");
System.out.println(message);
The context contains both the scanned beans as well as those defined in XML, and the result is:
Up to this point, you've seen that 0 candidate beans will cause the autowiring to fail unless the 'required' parameter of @Autowired is set to false. Given that the autowiring is following 'by-type' semantics, more than 1 bean will cause a failure regardless of the required parameter's value. For example, after adding the @Repository annotation back to the StubMessageRepository and rerunning the previous example, I receive the following exception:
This can be resolved by switching to 'by-name' semantics - accomplished via Spring 2.1's support for the JSR-250 @Resource annotation:
@Resource(name="jdbcMessageRepository")
private MessageRepository messageRepository;
…
You probably noticed in the previous example that the bean name (as specified in the @Resource annotation) defaults to the decapitalized non-qualified classname. To override this behavior, it is possible to add your own implementation of the BeanNameGenerator strategy, such as:
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
String fqn = definition.getBeanClassName();
return Introspector.decapitalize(fqn.replace("blog.", "").replace("Jdbc", ""));
}
}
Then providing this strategy to the scanner overrides the default:
And therefore, the name specified in the @Resource annotation can be modified accordingly:
NOTE: When relying on the container for autowiring, the default naming strategy is typically sufficient (i.e. it works "behind the scenes"). Therefore the naming strategy should only be considered for cases where you will be referring to beans by name elsewhere. Even then, for isolated cases it is much simpler to explicitly provide a bean name in the 'stereotype' annotation (e.g. @Repository("messageRepository")). Providing your own strategy can be useful if you are able to take advantage of naming conventions that are used consistently throughout your application (This particular example is a little contrived, but hopefully demonstrates that the strategy is very accommodating so that you can follow your own naming conventions).
So far all of the beans have been configured with the default 'singleton' scope, but scope resolution is another customizable strategy of the scanner. The default will look for a @Scope annotation on each component. For example, to configure the GreetingServiceImpl as a 'prototype', simply add the following:
While the default annotation approach is quite simple, scope is almost always a deployment-specific consideration. Therefore it often does not belong at the class-level or in the source code at all. For these reasons, the following strategy interface is available and may be specified on the scanner as with the BeanNameGenerator in the previous example:
Note that the name generation and scope resolution strategies may also be provided in the XML-based configuration, such as:
Likewise, custom filters can be added as sub-elements:
I realize this entry has already covered quite a bit of ground, but there is one last topic I would like to cover. In the previous post, I included an aspect with the <aop:aspectj-autoproxy/> element. Now I want to demonstrate how to add the autoproxy behavior with our standalone version. First, the aspect itself (same as last time):
private int invocationCount;
@Pointcut("execution(* blog.*Service+.*(..))")
public void serviceInvocation() {}
@Before("serviceInvocation()")
public void log() {
invocationCount++;
System.out.println("service invocation #" + invocationCount);
}
}
Next, I need to add an include filter for the @Aspect annotation (it is no longer included in the default filters):
And finally, I need to register the AspectJ annotation-based autoproxy creator (prior to calling refresh() on the context):
The result:
Hopefully this entry and the preceding one have provided a sufficient introduction to these new features of Spring 2.1. You should now have a decent understanding of how to combine the component scanning and annotation configuration in small doses alongside "traditional" Spring XML configuration if you prefer. Also, by providing your own filters, name generators, and scope resolvers, you can customize the configuration process. The official 2.1-M2 release contains more detailed information in the reference documentation.
Stay tuned to this Interface21 Team Blog to learn about more new features as we continue to progress from the current milestone phase toward the RC1 release of Spring 2.1, and if you are not particularly excited about the annotation-driven configuration, then you may want to keep an eye out for an upcoming blog by Costin Leau on Spring Java Configuration - which offers yet another alternative to XML but without the invasiveness of annotations in your application code.

Spring 2.0 introduced annotation support and annotation-aware configuration options that can be leveraged by Spring users who are developing with Java 5 (or later versions):
| for demarcating and configuring transaction definitions |
| for defining aspects along with @Pointcut definitions and advice (@Before, @After, @Around) |
| for indicating a class that is operating as a repository (a.k.a. Data Access Object or DAO) |
| for enforcing annotated bean properties are provided a value |
With Spring 2.1, this theme of annotation-driven configuration has been significantly extended and will continue to evolve as we progress toward the RC1 release. In fact, it is now possible to drive Spring's dependency injection via annotations. Furthermore, Spring can discover beans that need to be configured within an application context.
This blog entry will serve as a tutorial-style introduction to the basic features in 10 easy-to-follow steps. I will follow up later in the week with information on some more advanced features and customization options. If you are interested in alternative configuration options, you should also check out the Spring Java Configuration project and this blog.
This tutorial requires at least Java 5, and Java 6 is recommended (otherwise there is a single requirement at the end of step 1).
Grab spring-framework-2.1-m1-with-dependencies.zip. After extracting the archive, you will find the spring.jar and spring-mock.jar in the 'dist' directory. Add them to your CLASSPATH as well as the following (paths shown are relative to the 'lib' directory of the extracted 2.1-m1 archive):
(NOTE: If you are not running on Java 6, you will also need to add j2ee/common-annotations.jar)
Provide the interfaces and classes for the example. I have tried to keep it as simple as possible yet capable of demonstrating the main functionality. I am including all of the code and configuration in a single "blog" package. I would encourage following that same guideline so that the examples work as-is; otherwise, be sure to make the necessary modifications. First, the GreetingService interface:
Then, a simple implementation:
public void setMessageRepository(MessageRepository messageRepository) {
this.messageRepository = messageRepository;
}
public String greet(String name) {
Locale locale = Locale.getDefault();
String message = messageRepository.getMessage(locale.getDisplayLanguage());
return message + " " + name;
}
}
Since the service depends upon a MessageRepository, define that interface next:
And for now, a stub implementation:
public void initialize() {
messages.put("English", "Welcome");
messages.put("Deutsch", "Willkommen");
}
public String getMessage(String language) {
return messages.get(language);
}
}
Define the beans for a Spring application context. Notice, that I am including a new 'context' namespace (NOTE: the 'aop' namespace is also included here and will be used in the final step):
<bean class="blog.StubMessageRepository"/>
</beans>
Obviously this configuration looks a little sparse. As you can probably guess, the 'context' namespace will soon play a role.
Provide a simple test case leveraging Spring's base support class:
public void setGreetingService(GreetingService greetingService) {
this.greetingService = greetingService;
}
@Override
protected String[] getConfigLocations() {
return new String[] { "/blog/applicationContext.xml" };
}
public void testEnglishWelcome() {
Locale.setDefault(Locale.ENGLISH);
String name = "Spring Community";
String greeting = greetingService.greet(name);
assertEquals("Welcome " + name, greeting);
}
public void testGermanWelcome() {
Locale.setDefault(Locale.GERMAN);
String name = "Spring Community";
String greeting = greetingService.greet(name);
assertEquals("Willkommen " + name, greeting);
}
}
Try running the tests and notice that they fail with a NullPointerException. This is to be expected since the GreetingServiceImpl has not been provided a MessageRepository. In the next two steps, you will add annotations to drive the dependency injection and initialization respectively.
Provide an @Autowired annotation on the GreetingServiceImpl's setter method, such as:
Then, add the 'annotation-config' element (from the new 'context' namespace) to your configuration:
<bean class="blog.GreetingServiceImpl"/>
<bean class="blog.StubMessageRepository"/>
</beans>
Rerun th