commons.testing
For me, this is the best April fool’s joke for this year.
For me, this is the best April fool’s joke for this year.
Seam provides a number of features to help programmers with the tedious but necessary logging. One of them is the @Logger annotation that is used to inject a Seam Log instance into a Seam component. For example instead of writing:
private Log log = LogFactory.getLog(MyClass.class);
you can write:
@Logger private Log log;
and Seam will inject an appropriate logger. Below we will try to to implement this feature using the Spring Framework for objects managed by the Spring DI container (actually a BeanFactory).
The Spring DI container provides a number of extension interfaces that beans can implement to get callbacks from the container in various stages of the container operation. One callback interface is the BeanPostProcessor. BeanPostProcessors are called before and after the initialization of each bean and allow the custom modification of bean instances (for example wrapping an instance with a dynamic proxy).
The only thing we have to do to implement the @Logger injection (besides defining a @Logger annotation) is to write a BeanPostProcessor that, before each bean gets initialized (right after it gets constructed), will iterate over the fields of the bean to detect any @Logger annotations and construct and inject a new logger instance.
Let’s define the annotation:
package com.tzavellas.spring.logger; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; @Retention(RUNTIME) @Target(FIELD) @Documented public @interface Logger { }
and now the BeanPostProcessor:
package com.tzavellas.spring.logger; import java.lang.reflect.Field; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.util.ReflectionUtils; import static org.springframework.util.ReflectionUtils.FieldCallback; public class LoggerPostProcessor implements BeanPostProcessor { public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; } public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException { ReflectionUtils.doWithFields(bean.getClass(), new FieldCallback() { public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException { if (field.getAnnotation(Logger.class) != null) { Log log = LogFactory.getLog(bean.getClass()); field.set(bean, log); } } }); return bean; } }
Below I have a small JUnit test to verify that it works:
package com.tzavellas.spring.logger; import static org.junit.Assert.*; import org.apache.commons.logging.Log; import org.junit.Before; import org.junit.Test; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.RootBeanDefinition; public class LoggerPostProcessorTest { DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); @Before public void setupFactory() { RootBeanDefinition bean = new RootBeanDefinition(Bean.class, true); factory.addBeanPostProcessor(new LoggerPostProcessor()); factory.registerBeanDefinition("bean", bean); } @Test public void injectLogger() { Bean b = (Bean) factory.getBean("bean"); assertNotNull(b.log); b.doSomething(); } } class Bean { @Logger Log log; public void doSomething() { log.debug("message"); } }
This is a very simple implementation since the goal of this article is to demonstrate the extensibility of the Spring DI container and not to implement a complete solution. One limitation is that this implementation only injects loggers (actually commons-logging Logs) to public fields (Seam can inject Seam Logger to private fields).
To use the above in a Spring XML file you simply define a bean with class com.tzavellas.spring.logging.LoggerPostProcessor (the id/name is not needed). The BeanFactory/ApplicationContext will automatically detect all beans that implement the BeanPostProcessor interface at startup time and will initialize them and then call them every time a bean gets initialized.
Spring IDE 2.0M3 was released and the springframework.org site writes about the long-awaited Spring Webflow support. Spring IDE now includes graphical and XML editors for Spring WebFlow.
I believe that this major new feature hides 3 very important new features that IMHO programmers will find more useful, since people working with Spring spend more time editing Spring XML files than WebFlow XML files.
See the changelog of the 2.0M3 release for more information about changes and new features.
I am using the Spring IDE 2.0 milestones from the development update site and I am very satisfied with all the new features. The Spring IDE team is doing a great job (thanks guys) and I believe that the 2.0 release is going to be a huge step forward.
Oracle has released the Toplink O/R mapping framework as open source. They proposed a new persistence project, named Eclipse Persistence Platform (or EclipseLink for short), at the Eclipse Foundation and they are donating the Toplink source code to start the project.
The EclipseLink will be a runtime project offering only libraries and no IDE tooling. Other Eclipse projects, like Dali, offer tooling for JPA and O/R mapping. The project will include the Toplink O/R mapping tools and APIs, a JPA implementation, an OXM framework, a SDO implementation and other persistence related technologies.
Toplink is a very mature and successful product. It is maybe the fist successful O/R mapping product for Java and it is great to see Oracle donating it to the open source community.
For more information see:
On Saturday the 10th of March the 4th JHUG tech day took place. Dionysios and Paris have written excellent coverages of the event so I won’t write any details about it.
This was our best event so far and I am very happy that our JUG has sustainably organized events with great success. It is really amazing how the JHUG has evolved in the last couple of years. We were a small group of Java passioned people that just participated on an online discussion forum and now we organize events with above 150 attendees and world-class speakers. This time we even had our first non-European speaker, Patrick Linskey who came from the USA (San Francisco if I am correct) to speak to our event.
A huge thanks to Paris and Panos (our JUG leaders) for their hard work to organize the event. Guys… you rock! A huge thanks also to our guest speakers Dr Heinz Kabutz (Maximum Solutions), Tom Baeyens (JBoss/RedHat, JBPM lead developer), Patrick Linskey (BEA, EJB spec co-lead) and Rod Hardwood (Jetbrains).
The sponsor of the event was my previous employer. It was great to see old colleges and chat with them again. One of the best aspects of JUG events is the networking and discussions that you make with other people. Also the sponsor’s talk was (from the comments on other blogs and the JHUG forum) maybe the best so far. I was sure that it was going to be an interesting talk since I’ve worked on that system for a year and I know the the i-docs team does good and interesting work.
In conclusion, it was a great event and I hope that our next events will be even better (although this is easier said than done).