Sunday, 12 October 2008

Scanning classpath annotated classes with Spring 2.5

One of the common problems of using annotations as class markers, substituting configuration files for frameworks metadata is the processing phase of these annotations.

Even if this is not a big difficulty, problems, and potential bugs related to this task like those related to classpath scanning, and resources manipulation are significant and impose the use of low level frameworks like ASM or Javassist (to avoid class loading related problems) which are not very trivial to use nor well documented.

Fortunately Spring 2.5, provides a very nice framework which resolves ‘all’ these problems in a very clean way, using ASM under the woods. This is, more precisely, located in the core module which contains also the i/o and utilities frameworks and can be used without being in the context of using the whole spring container.

In fact, suppose that we have a custom annotation called Marker that have the attribute type. Now suppose that we want to scan the classpath and find all classes annotated by this annotation and having a particular value for the type attribute; In the following snippet of code I show how to satisfy this need.



package example.annotation.scan;

import java.io.IOException;

import java.util.HashSet;

import java.util.Map;

import java.util.Set;

import java.util.Map.Entry;

import org.springframework.core.io.Resource;

import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import org.springframework.core.io.support.ResourcePatternResolver;

import org.springframework.core.type.AnnotationMetadata;

import org.springframework.core.type.classreading.MetadataReader;

import org.springframework.core.type.classreading.MetadataReaderFactory;

import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;

import org.springframework.core.type.filter.AnnotationTypeFilter;

import org.springframework.core.type.filter.TypeFilter;

import org.springframework.util.ClassUtils;

/**

* Acts as a classpath scanner that finds classes annotated with

* the {@link Marker} annotation. It garantees that no scanned class

* is loaded by the {@link ClassLoader}.

*

* @author slim tebourbi

*

*/

public class MarkedClassFinder {

private final static String FOLDERS_SEPARATOR_AS_STRING = System

.getProperty("file.separator");

/*

* the base package wich represents the root of the scanned resources/classes folder.

*/

public final static String BASE_SCANNING_PACKAGE = "base\\scanned\\classes\\";

private final Class<Marker> MARKER_ANNOTATION = Marker.class;

private final String TYPE_MARKER_ATTRIBUTE = "type";

private final MetadataReaderFactory metadataReaderFactory;

private final TypeFilter annotationFilter;

private final ResourcePatternResolver resourceResolver;

public MarkedClassFinder() {

this.metadataReaderFactory = new SimpleMetadataReaderFactory();

this.annotationFilter = new AnnotationTypeFilter(MARKER_ANNOTATION);

this.resourceResolver = new PathMatchingResourcePatternResolver(

Thread.currentThread().getContextClassLoader());

}

public Set> findMarkedClassOfType(String type) {

Set> markedClasses = new HashSet>();

/*

* First of all we load all resources that are under a specific package by using a ResourcePatternResolver.

* By doing so we will use class files as simple resources without passing

* by the ClassLoader which can for example cause the execution of a static initialization block.

* It resolves also transparently resources in jars.

*/

String candidateClassesLocationPattern = "classpath*:" + BASE_SCANNING_PACKAGE + "**" + FOLDERS_SEPARATOR_AS_STRING + "*.class";

Resource[] resources = null;

try {

resources = resourceResolver.getResources(candidateClassesLocationPattern);

} catch (IOException e) {

throw new RuntimeException(

"An I/O problem occurs when trying to resolve ressources matching the pattern : "

+ candidateClassesLocationPattern, e);

}

/*

* then we proceed resource by resource, using a MetadataReaderFactory to create

* MetadataReader wich hides the ASM related interface and complexity.

*

*/

for (Resource resource : resources) {

MetadataReader metadataReader = null;

try {

metadataReader = this.metadataReaderFactory.getMetadataReader(resource);

/*

* the filter will pass only annotated classes

*/

if (this.annotationFilter.match(metadataReader, metadataReaderFactory)) {

/*

* the AnnotationMetadata is a simple abstaction of the informations

* that holds the annotation

*/

AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();

Map attrts = metadata.getAnnotationAttributes(MARKER_ANNOTATION.getName());

for (Entry attrt : attrts.entrySet()) {

if ((TYPE_MARKER_ATTRIBUTE.equals(attrt.getKey())) && (type.equals(attrt.getValue())))

{

String className = convertResourceToClassName(resource,BASE_SCANNING_PACKAGE);

try {

markedClasses.add(ClassUtils.forName(className));

} catch (Exception e) {

throw new RuntimeException("problems occurs when trying to load the annotated class : " + className,e);

}

}

}

}

} catch (IOException e) {

throw new RuntimeException("An I/O problem occurs when trying to process resource : " + resource,e);

}

}

return markedClasses;

}

static String convertResourceToClassName(Resource resource,String basePackage) throws IOException {

String path = resource.getFile().getPath();

String pathWithoutSuffix = path.substring(0, path.length()- ClassUtils.CLASS_FILE_SUFFIX.length());

String relativePathWithoutSuffix = pathWithoutSuffix.substring(pathWithoutSuffix.indexOf(basePackage));

String className = relativePathWithoutSuffix.replace('\\', '.');

return className;

}

}


Sunday, 17 August 2008

AspectJ or Spring AOP?

Although Aspect Oriented Programming is a mature technology nowadays, it is not so widely used in enterprise applications, and this is, sometimes, due to the ignorance of the benefits of using it and the strength of its implementations or let’s say tools.

After being convinced to apply AOP, we must make a choice for the tool to use and the list of java frameworks as for almost all the areas is long. Fortunately this choice in our case is relatively easy (imho) because there are two predominant actors which are the most used and active ones and are AspectJ and Spring AOP. But even if I start by speaking about choices which traditionally means that I’ll compare the two solutions and make an exclusive choice (like for persistence, IoC…), I think that Spring AOP and AspectJ are two ‘opposite’/complimentary solutions that can coexist and interact without any problems. That's why in this particular case the real solution when applying AOP is to take in consideration the two tools and to make the choice based on the particular problem that we try to solve and its imposed context.

In fact the principal source of this opposition / complementarity resides in the nature of the two solutions; while aspectJ is a full AOP solution, based on class-weaving and is considered as a language on his own; Spring AOP is a relatively limited solution based on proxies and aiming to provide the Springframework the capacity to resolve with simplicity and transparency most commons enterprise application problems that are resolvable with AOP.

Being faced on a situation that we decide to resolve a particular problem or need with AOP, we must principally take in consideration three factors to determine which of the two tools, Spring AOP or AspectJ, to use:

  • The targets to be aspectized.
  • The type of pointcut needed by the aspect.
  • The invasiness of the solution.

So, firstly we must take on consideration the targets of our aspect, and this is due to two important facts that are the limitation of Spring AOP to act only on Spring beans and its incapacity to aspectise another aspect. Based on this it’s obvious that AspectJ is the solution in these cases.

The second consideration is to see what kind of pointcut our aspect needs; because Spring AOP can only be applied on method execution, whereas AspectJ can be applied on practically all types of possible pointcut (call, get, set, preinitialization, staticinitialization, initialization, handler, adviceexecution, withincode,…). This can be seen as a big limitation for Spring AOP but in reality method execution based pointcuts are the most used ones in common enterprise application problematics; and this is simply because the major part of code fragments having meaningful (or important) business or technical logics are put into methods so it’s obvious that aspects are tied to these methods and are simply an externalisation and factorisation of what was put in these methods before using AOP.

The third consideration is our tolerance to the invasiveness of the adopted solution. Spring AOP being a pure java implementation presenting an xml based declarative solution (schema-based support) and offering a valuable @Aspect support, is perfectly transparent. On the other side, being a class weaving based tool, AspectJ is relatively invasive. In fact if we choose the compile-time solution we must use the AspectJ specific compiler to weave the target application; even if this compiler has made many evolutions to be able of weaving source code as well as already compiled classes (or aspects - for aspect libraries) (this is also said post-compile weaving or binary weaving) even in a packaged form (for third party libraries or legacy applications) and its performance was remarkably optimized. Personally, and based on my own experience I think that even if transparency is an important consideration, its not so prohibitive to use compile time weaving, because after all, this consecutive ‘pollution’ is localized in the build relative part and not propagated in our code; and tools like maven or Ant offers a big support for these needs; then I think that independently of what tool or support to use, the most important here, and more generally for all problems of this type, is the good modularisation of our application. AspectJ presents also an alternative to compile-time weaving, which is the Load-Time weaving; this feature is more transparent than the traditional one and can be enabled in different ways, but it still an exotic solution that must gain more maturity to be used as widely as compile-time weaving.

There are also some miscellaneous considerations that can be important in some situations. As for other factors of discrimination these particularities are imposed principally by the natures of the two tools. In fact due to its proxy based implementation Spring AOP can presents some unexpected behaviour when faced to the use of the ‘this’ java keyword in the target method which can be a serious limitation when consider to use the developed aspects on legacy code or on third party libraries. Always for the same reasons, Spring AOP aspects can be instantiated only as singletons with the schema based support; and also as with the ‘perthis’ and ‘pertarget’ AspectJ’s instantiation model when using the @Aspect way; while the ‘percflow’ and ‘percflowbelow’ instantiation models are not yet supported. Then, there are performance issues; personally I never find a case where this issue was prohibitive for the use of AOP, and I’ll limit myself to mention the AWBench for those who want to make more investigations on performance.

Finally, and as a conclusion of what was mentioned above, I think that the best approach to take when we are faced to the problem consisting in to choosing what AOP tool to use between these two solutions, is to see firstly if we are in the applicability scope of Spring AOP (a spring bean as a target and a method execution as a pointcut); based on this we obviously must choose AspectJ in the case where we are out of this scope, else, I recommend using Spring AOP with the @Aspect support, which gives us the possibility of changing our initial choice and to use AspectJ if our needs evolutes and can’t be satisfied by Spring AOP.

Thursday, 1 May 2008

The SPRINGSOURCE NEW PRODUCT

SpringSource announced yesterday a new product the SpringSource Application Platform which is simply said a J2EE server à la Spring and OSGI.

From a technical point of view I am very pleased about this new product, because I believe in OSGI and its benefits. I'm working on IBM Websphere 6.1 which is also based on OSGI but without giving the opportunity to access the target runtime from the application level, a feature that could simplify considerably the management (versioning, deployment, patching ...) and the non-web modules of the application like batches. This is not only the case of Websphere but all actual implementations of J2EE application servers choose this approach.

But, from another point of view, I want to reply to a question that asked an interviewer to Rod Johnson about the unusual discretion about the announcement of this new SpringSource product.

I think that the days when Spring was an implementation of some great ideas of Rod that he published in his two famous books Expert One-on-One J2EE Design and Development and J2EE without EJB and evolved only by the needs and the critics of its community and those when the framework is becoming a platform with a company like the SpringSource behind it with important economic issues there is a big gap. And like any other company SpringSource will not be driven by the simple needs and ideas of his customers but principally by a commercial model. And so all the romantics and the effervescence of the Spring community must give way to commercial and economic models. I hope that I am wrong but I think that we are in the same scenario of Hibernate/Gavin King/JBoss.