With the advent of Java EE 6 it has become easier to build extensible applications. In this first post we will briefly explore how core components of standard applications can be customized with CDI @Specializes/@Decorator and more interestingly packaging the customized applications.

Specializes

Specialization in Java EE allows for simple customization of existing beans via inheritance. If a @Specializes bean is found on the classpath it will be injected instead of the original.

The specializing bean has to extend the original bean, it inherits all qualifiers and its name, if defined with @Named.

@RequestScoped public class CoreService { public void doStuff() { System.out.println("Default implementation is doing Stuff."); } } @Specializes public class MySpezializedService extends CoreService { @Override public void doStuff() { System.out.println("Spezialized implementation is doing Stuff."); } }

MySpezializedService will be injected instead of MyDefaultService in any place where MyDefaultService has been defined for injection.



This simple inheritance hierarchy, allows you to adapt the core applications functionality as and when required.

Depending on your application and customization strategy, hook methods can be defined in the standard implementation for enhanced customization purposes.

@RequestScoped public class FooProcessor { public void process(Foo foo) { Bar bar = calculateBar(foo); ... } private void calculateStuff(Foo foo) { foo = preCalculationHook(foo); ... return postCalculationHook(bar); } protected Foo preCalculationHook(Foo foo) { return foo; } protected Foo postCalculationHook(Bar bar) { return bar; } } @Specializes public class SpecializedFooProcessor extends FooProcessor { @Override public Foo preCalculationHook(Foo foo) { ... return foo; } @Override public Bar postCalculationHook(Bar bar) { ... return bar; } }

Decorator

Decorators allow for simple customization of business logic.

@Decorator public abstract class CoreControllorDecorator implements CoreController { @Inject @Delegate private CoreController coreControllor; @Override public String execute() { return "Decorator doing stuff before CoreControllor." + coreControllor.execute(); } }

Decorators may be abstract so that only methods that should be decorated have to be implemented.

Decorators may not extend the decorated managed bean (see CDI-224 for more details), therefor you need a common super type (abstract or interface).

public interface CoreController { public String execute(); public String randomMethod(); }

It is important to note that decorators are not active by default, just like interceptors they have to be defined in the beans.xml.

<?xml version="1.0" encoding="UTF-8"?> <beans ...> ... <decorators> <class>com.knitelius.customized.app.web.CoreControllorDecorator</class> </decorators> </beans>

Packaging

Sadly there is no “one size fits all” solution in terms of packaging the customization’s, depending on the targeted application server you are deploying to. As Mark Struberg points out in CDI in EARs, CDI bean discovery in EAR files in not specified and varies between application servers.

Ideally the customization’s should be packaged into a separate bean-archive compliant* JAR.

This works fine when customizing EJB-JAR’s, since the customizing bean archive that has a dependency on the EJB-JAR can be packaged into the EAR lib. Avoiding maven cyclic dependency issues.

ear ├── lib | └── customizations.jar └── core-ejb-jar └── ...

However this does not work for WAR’s, in this case you will need to extract all customizable core components into a separate bean archive, to avoiding cyclic dependencies.

war ├── ... └── WEB-INF | └── ... | └── lib | └── customizable-compontents.jar | └── customizations.jar └── ...

Alternatively Maven overlays offers a more versatile solution for customizing web applications.

In the simplest case it is sufficient to declare a runtime dependency on the core application WAR. Maven will overlay (overwrite or include) all resources in the core application with the once defined in the customized application.

<?xml version="1.0" encoding="UTF-8"?> ... <groupId>com.knitelius</groupId> <artifactId>CUSTOMIZED-App-Web</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <name>CUSTOMIZED-App-Web</name> <dependencies> <!-- WAR to be overlayed. --> <dependency> <groupId>com.knitelius</groupId> <artifactId>CORE-App-web</artifactId> <version>0.0.1-SNAPSHOT</version> <type>war</type> <scope>runtime</scope> </dependency> ... </dependencies> ...

To gain access to the core applications classes for customization a provided* dependency on the core applications classes has to be defined.

<?xml version="1.0" encoding="UTF-8"?> ... <!-- Makes CORE classes available for customization. --> <dependency> <groupId>com.knitelius</groupId> <artifactId>CORE-App-web</artifactId> <classifier>classes</classifier> <version>0.0.1-SNAPSHOT</version> <type>jar</type> <scope>provided</scope> </dependency> ... </dependencies> ...

In part 2 we will explore how a non-invasive extension mechanism can be implemented for Java EE applications.