Java and JBoss related stuff
RSS icon Home icon
  • New features in cdi-ext

    Posted on August 2nd, 2010 Adam Warski No comments

    Tomek Szymański just commited two new features to cdi-ext.

    The first is the ability to secure JSF pages when using the Nav component to handle navigation (more on it here). If you want to make a page accessible only if a certain EL expression is true, when defining a page, you can write:

    
    private final Page adminPage = new ViewIdPageBuilder("/admin.xhtml")
        .setRequiresLogin(true)
        .setSecurityEL("#{currentUser.isAdmin)").b();
    

    If the condition is not met, the user will get 403 Forbidden. Also, Tomek extended handling of setRequiresLogin(true), so that if a user is redirected to the login page, because he was not logged in and the page is secured, the page which the user tried to access is stored and after logging in, he is redirected back to the original page.

    The second is the ability to specify the transaction timeout using a @TransactionTimeout(timeout = 5) annotation on a method.

    Moreover, we have moved our repository infrastructure to Nexus. The new address where cdi-ext artifacts are deployed is http://tools.softwaremill.pl/nexus/content/repositories/snapshots.

    Adam

  • Ruby on Rails + CDI? Why not! Enter TorqueBox + Weld

    Posted on July 27th, 2010 Adam Warski 1 comment

    I guess many people are often “unsatisfied” with how JSF works and how much time it sometimes takes to do a simple thing. That’s why we are trying out a new combination: RoR for the frontend and CDI for the backend. How?

    Deploying RoR applications to JBoss AS is really easy thanks to the TorqueBox project. You just deploy a .yml file using the provided rake tasks and you can develop the application “live” – no redeploys, instant changes, and so on.

    Using RoR as a frontend to a CDI/Weld based application requries two more steps, so that RoR can see the business logic classes and share the same http session with CDI (so it’s possible to access @SessionScoped beans from RoR and CDI code).

    First you need to deploy your application in the DefaultDomain (at least until TORQUE-85 is fixed). To do this, add a jboss-classloading.xml file to the META-INF directory with this content:

    
    <classloading xmlns="urn:jboss:classloading:1.0"
                  domain="DefaultDomain"
                  top-level-classloader="true"
                  export-all="NON_EMPTY"
                  import-all="true">
    </classloading>
    

    Secondly, you need to add a filter to RoR’s web application, so that Weld and RoR share the same session. Just edit config/web.xml in your RoR application (the magic in the RoR deployer will add it to the virtual .war deployment it creates) and add the following:

    
    <web-app>
        <listener>
            <listener-class>org.jboss.weld.servlet.WeldListener</listener-class>
        </listener>
    </web-app>
    

    Now RoR and CDI share the same session (so you can use @SessionScoped beans etc, probably also @ConversationScoped, but I haven’t tried that). You can lookup CDI beans from RoR code using e.g. the BeanInject class from cdi-ext, or just by writing a very simple utility method which lookups the BeanManager.

    Adam

  • Object Services, or bridging anemic and rich models, in CDI/Weld

    Posted on May 27th, 2010 Adam Warski 3 comments

    Rich domain models are certainly a nice, object-oriented idea, but I always had one problem with them: what if they become bloated with completely unrelated methods? For objects that are frequently used in a system, we may want to add various methods, which depend on the actual class of the object. Also, what if we’d like to use some other (e.g. CDI) beans as part of the method logic? Normally in DI frameworks there’s no injection into model classes. Or we want to add a frontend-specific method, but we receive the instances from a backend service?

    Object Services try to address the issues above. Suppose we have a simple class hierarchy of animals:

    
    abstract class Animal
    class Elephant extends Animal
    class Ant extends Animal
    

    and we want to implement a paint method, which paints a picture of the given animal on a canvas. Quite obviously, painting an elephant is different from painting an ant. There are several solutions:

    • add a paint method to the Animal interface – problems outlined above
    • add a paint method, in which we check which Animal was passed using instanceof – quite ugly
    • use the visitor pattern – typesafe, but quite verbose

    I think the best solution would be to have type-safe “polymorphic extension methods”, so that in your code you could just add some methods to each class in a hierarchy, but unfortunately this isn’t supported by any Java (see also multiple dispatch).

    Another possibility is to use what I call “Object Services”. If we want to add some methods to a class hierarchy, we create a parallel hierarchy of “services” (which are normal classes):

    
    interface PaintService<T extends Animal> extends OS<T> {
       void paint(Canvas c);
    }
    
    // Implements OS<Elephant>
    class ElephantPaintService implements PaintService<Elephant> {
       // Here we can store the object, for which the service was invoked
       void setServiced(Elephant e) { ... }
       void paint(Canvas c) { ... }
    }
    
    // Implements OS<Ant>
    class AntPaintService implements PaintService<Ant> {
       // Injection works normally
       @Inject AnthillService anthill;
    
       void setServiced(Ant a) { ... }
       void paint(Canvas c) { ... }
    }
    

    OS is an interface marking some beans as object services; the class, to which the service corresponds is given as a type parameter.

    The ObjectServiceExtension will detect all beans that implement the OS interface, and register an OSP (Object Service Provider) bean which can be later injected to obtain a correct object service given an Animal:

    
    @Inject
    OSP<Animal, PaintService<Animal>> paintService;
    
    void paint(Animal a, Canvas c) {
       paintService.f(a).paint(c);
    }
    

    Each invocation of the f method will lookup the correct bean, based on the run-time type of the object passed, create a new instance of the found bean and set the object, for which the method was called. All beans created are CDI-managed, so injection etc works normally.

    
    void test(Canvas c) {
       // Will invoke paint(c) in AntPaintService
       paint(new Ant(), c);
    
       // Will invoke paint(c) in ElephantPaintService
       paint(new Elephant(), c);
    }
    

    The source code is available on GitHub in the cdiext project. To use it, just bundle the jar with your application.

    Thanks to Tomek Szymański for discussing the implementation.

    So what’s next? The code could use a couple of improvements, but the biggest next task is to add deploy-time checking if there’s an object service for each class in a hierarchy (e.g. we have a PrintService and an ElephantPrintService, but forget to add an AntPrintService).

    Adam

  • CDI & Weld Extensions in Git

    Posted on May 17th, 2010 Adam Warski No comments

    Hello,

    I’ve created a new cdiext project at github, initially with two extensions:

    1. Stackable Security Interceptors, about which I blogged here and here. Example usage:

    
    @SecureBinding
    @Secure("#{loggedInUser.administrator}")
    public @interface AdministratorOnly {
    }
    
    public class SecureBean {
        @AdministratorOnly
        @Secure("#{additionalSecurityCheck}")
        public void doSecret() { ... }
    }
    

    2. Injectable ELEvaluator, which works both during a faces request and outside of one (e.g. during invocation of an MDB). Example usage:

    
    @Inject
    private ELEvaluator elEvaluator;
    
    void someMethod() {
        // ...
        Integer result = elEvaluator.evaluate(
                "#{testParam1 + 10 + testParam2}", Integer.class, params);
        // ...
    }
    

    Thanks to Dan Allen for helping out with this one.

    There are also some tests done using Arquillian – looks like it’s going to be a great testing tool! :)

    Adam

  • Extending the security interceptor for Weld/JSF2

    Posted on April 13th, 2010 Adam Warski 2 comments

    In my previous post, I described how to create a simple security interceptor, which checks conditions defined using EL expressions, e.g.:

    
    @Secure("#{loggedInUser.name == arg0.name}")
    public List<Message> listMessages(User owner) { ... }  
    

    Now, it would be nice to be able to stack such annotations, so that they can be placed:
    * on methods
    * on classes – then the constraint applies to all methods
    * on other annotations, to create “security bindings”

    An example usage could be:

    
    @Secure("#{loggedInUser != null}")
    public class Messages {
       @AdminOnly
       public void deleteAllMessages() { ... }
    
       @Secure("#{loggedInUser.maxMessageListCount == count}")
       public List<Message> listMessages(@ELVar("user") User owner, @ELVar("count") int count) { ... }
    }  
    

    where @AdminOnly is defined as:

    
    @SecureBinding
    @Secure("#{loggedInUser.isAdministrator}")
    public @interface AdminOnly { }
    

    This way common security constraints can be expressed as annotations or on the class. I’m also using an improvement suggested by Dan Allen, to name the method arguments using @ELVar, instead of naming them arg0, arg1, etc. This also allows to refer to method arguments in the “security binding” annotations, whatever the position of the argument is.

    How to implement such annotations? Well, the first step is to create a portable extension (meaning it will work with any CDI implementation, not just Weld), which will gather, for each method, all the @Secure annotations, and their values, into one single annotation, @InterceptSecure. Having such a set of constraints to check for each method, we add the annotation to the method meta-data, using a utility class from Weld Extensions: the NewAnnotatedTypeBuilder. As the @InterceptSecure is an interceptor binding, the security interceptor will be called whenever the method is invoked.

    The extension observes the ProcessAnnotatedType event, which is fired for each bean type. If necessary, the type can be modified, to include the new annotations. The annotation is only added to Weld meta-data, not to the method itself (so there’s no bytecode manipulation or such).

    One last obstacle to overcome is to get the value of the generated @InterceptSecure annotation in the interceptor. Currently this is not possible using e.g. BeanManager, but should be address in CDI Maintenance Release (see here), so as a temporary solution all the generated annotations are stored in a map in the extension. All extensions are application-scoped beans, so the information can be accessed from the interceptor. One shortcoming of the solution is that one method may belong to several, differently annotated CDI beans.

    The code for the annotation and extension:

    
    @InterceptorBinding
    public @interface InterceptSecure {
        @Nonbinding
        String[]    value();
    }
    
    public class SecurityExtension implements Extension {
        private final Map<Method, InterceptSecure> interceptSecureForMethods = new HashMap<Method, InterceptSecure>();
    
        public InterceptSecure getInterceptSecure(Method m) {
            return interceptSecureForMethods.get(m);
        }
    
        public <T> void processAnnotatedType(@Observes ProcessAnnotatedType<T> event) {
            // A flag indicating if the builder was used to modify the annotations
            boolean used = false;
            NewAnnotatedTypeBuilder<T> builder = new NewAnnotatedTypeBuilder<T>(event.getAnnotatedType());
    
            // We need to read the values of the @Secure annotation that are present on:
            // 1. types (classes)
            // 2. methods
            // 3. arbitrarily nested on @SecureBinding annotations
    
            // Gathering the initial secure values from the type
            List<String> initialSecureValues = new ArrayList<String>();
            for (Annotation annotation : event.getAnnotatedType().getAnnotations()) {
                collectSecureValues(annotation, initialSecureValues);
            }
    
            for (AnnotatedMethod<?> m : event.getAnnotatedType().getMethods()) {
                // Gathering the secure values from the method
                final List<String> values = new ArrayList<String>(initialSecureValues);
                collectSecureValues(m, values);
    
                // If any values have been gathered, adding the annotation to the method and storing it
                // in the map.
                if (values.size() > 0) {
                    InterceptSecure is = new InterceptSecureImpl(values.toArray(new String[values.size()]));
                    builder.addToMethod(m.getJavaMember(), is);
                    used = true;
    
                    interceptSecureForMethods.put(m.getJavaMember(), is);
                }
            }
    
            // Setting the new annotated type, if any changed were made
            if (used) {
                event.setAnnotatedType(builder.create());
            }
        }
    
        private void collectSecureValues(AnnotatedMethod m, List<String> values) {
            for (Annotation annotation : m.getAnnotations()) {
                collectSecureValues(annotation, values);
            }
        }
    
        private void collectSecureValues(Annotation annotation, List<String> values) {
            if (Secure.class.isAssignableFrom(annotation.annotationType())) {
                values.add(((Secure) annotation).value());
            } else {
                if (annotation.annotationType().getAnnotation(SecureBinding.class) != null) {
                    for (Annotation nestedAnnotation : annotation.annotationType().getAnnotations()) {
                        collectSecureValues(nestedAnnotation, values);
                    }
                }
            }
        }
    
        private static class InterceptSecureImpl extends AnnotationLiteral<InterceptSecure> implements InterceptSecure {
            private final String[] values;
    
            private InterceptSecureImpl(String[] values) {
                this.values = values;
            }
    
            @Override
            public String[] value() {
                return values;
            }
        }
    }
    

    And for the interceptor:

    
    @Interceptor
    @InterceptSecure("")
    public class SecurityInterceptor {
        @Inject
        private SecurityExtension se;
    
        @AroundInvoke
        public Object checkSecurity(InvocationContext ctx) throws Exception {
            // Getting the generated @InterceptSecure annotation for the method.
            // After the CDI Maintenance Release is released, it should be possible to get the annotated
            // type of the currently invoked bean, see:
            // http://old.nabble.com/Retrieving-the-Bean-object-for-an-interceptor-td28147499.html
            // For now, we just use a map in the extension. One limitation is that this doesn't allow
            // different security annotations for methods which are used in several beans.
            InterceptSecure is = se.getInterceptSecure(ctx.getMethod());
            String[] toCheck = is == null ? null : is.value();
    
            // Check the el conditions as in the previous post
            // (...)
    
            return ctx.proceed();
        }
    }
    

    Adam

  • Simple security interceptor in Weld/JSF2

    Posted on March 31st, 2010 Adam Warski 7 comments

    Waiting for the Seam3 security module, I wrote a simple security interceptor (inspired by the Seam2 security annotation). You can use it like this:

    
    @Secure("#{loggedInUser.name == arg0.name}")
    public List<Message> listMessages(User owner) { ... }
    

    Here, loggedInUser is a @Named Weld (CDI) bean, and arg0 is the first argument of the method. This is a slight modification to the Seam2 security annotation, where it wasn’t possible to reference arguments. If the EL expression doesn’t evaluate to true, an exception is thrown.

    The implementation is pretty straightforward, as adding an interceptor in Weld is really simple. First, we need the annotation:

    
    /**
     * @author Adam Warski (adam at warski dot org)
     */
    @Retention(RUNTIME)
    @Target({TYPE, METHOD})
    @InterceptorBinding
    public @interface Secure {
        /**
         * @return The EL expression that should be evaluated. If it evaluates to
         * {@code true}, access will be granted. The EL expression may reference
         * any objects that are in any context, as well as the arguments of the method,
         * under the names {@code arg0, arg1, arg2, ...}.
         */
        @Nonbinding
        String  value();
    }
    

    The key components here is the @InterceptorBinding meta-annotation, and specifying the value of to be @Nonbinding. If the value element was binding, then we would need to define an interceptor for each possible String value.

    Next, the interceptor itself:

    
    @Interceptor
    @Secure("")
    public class SecurityInterceptor {
        private String getArgName(int index) { return "arg" + index; }
    
        @AroundInvoke
        public Object invoke(InvocationContext ctx) throws Exception {
            FacesContext facesCtx = FacesContext.getCurrentInstance();
            ELContext elCtx = facesCtx.getELContext();
    
            Secure secure = getSecureAnnotation(ctx.getMethod());
            String expression = secure.value();
    
            // Populating the request map so that parameters are available (arg0, ...)
            Map<String, Object> requestMap = facesCtx.getExternalContext()
                    .getRequestMap();
            for (int i = 0; i < ctx.getParameters().length; i++) {
                Object parameter = ctx.getParameters()[i];
                requestMap.put(getArgName(i), parameter);
            }
    
            Boolean expressionValue = (Boolean) facesCtx.getApplication()
                    .getExpressionFactory()
                    .createValueExpression(elCtx, expression, Boolean.class)
                    .getValue(elCtx);
    
            // Removing the parameters (arg0, arg1, ...)
            for (int i = 0; i < ctx.getParameters().length; i++) {
                requestMap.remove(getArgName(i));
            }
    
            if (expressionValue == null || !expressionValue) {
                throw new SecurityException();
            }
    
            return ctx.proceed();
        }
    
        private Secure getSecureAnnotation(Method m) {
            for (Annotation a: m.getAnnotations()) {
                if (a instanceof Secure) { return (Secure) a; }
            }
            for (Annotation a: m.getDeclaringClass().getAnnotations()) {
                if (a instanceof Secure) { return (Secure) a; }
            }
    
            throw new RuntimeException("@Secure not found on method " + m.getName() +
                    " or its class " + m.getClass().getName());
        }
    }
    

    And finally, we need an entry in beans.xml, enabling the interceptor:

    
    <interceptors>
       <class>util.security.SecurityInterceptor</class>
    </interceptors>
    

    One shortcoming is that it’s not currently possible to place one @Secure annotation on the class, and another on the methods (see this thread on the forum). The idea is that then the class-level annotation expresses general security constraints, which can be later refined on the method level.

    Another missing feature, which could be easily added, is a message parameter to the annotation, which would be included in the exception in case the check fails.

    Adam

  • JSF2 navigation: post->redirect->get

    Posted on March 11th, 2010 Adam Warski 2 comments

    JSF2 improves a lot both how navigation can be done (you can now return a view id from an action method, no need to describe every navigation case in faces-config.xml) and how URLs are handled (finally, GET support). JSF2 introduces view parameters (for those who know Seam: standardized page parameters). Each page can define a metadata section, where the view parameters are described, bound to bean values, converted and validated.

    As an example, a blog-entry-viewing page would define the id of the entry to be displayed as follows:

    
    <f:metadata>
       <f:viewParam name="entry_id" value="#{blog.entry}" required="true">
          <f:converter converterId="blog-entry-converter" />
       </f:viewParam>
    </f:metadata>
    

    Unfortunately I had some trouble with one thing: how to redirect to a page, including the view parameters, after a POST? This post->redirect->get pattern is very common. E.g. when you post a new comment for a blog entry and press submit, the data is persisted and you want to be redirected back to view.jsf?entry_id=819 (using the default JSF command-button behavior, you would land on a plain, non-bookmarkable view.jsf).

    Dan Allen wrote a series of very good introductory articles to JSF2 on DZone. There, he writes that what I described above should be possible to achieve by adding a <redirect include-view-params="true"/> tag to the appropriate <navigation-case> in faces-config.xml. Unfortunately, the xsd doesn’t allow such an attribute and it doesn’t work – I suppose that this construct didn’t make it into the final version of the spec (although somebody may correct me if I’m wrong).

    Another solution, this time working, can be found on Ed Burns’s blog. The trick is to return a string containing the view id and some additional parameters from the action method or use them as the command button/link action, e.g.:

    
    public String action() {
         // business logic ...
         return "view.xhtml?faces-redirect=true&includeViewParams=true"
    }
    

    However this way you’ll have to repeat the combination of the “magical parameters” a lot in your code. And it’s pretty easy to do a spelling mistake in one of the strings you return. Furthermore, it’s not possible to easily include one view parameter, without repeating the value mapping.

    The way I solved this is by introducing a Nav component (I’m using Weld), which holds information about pages. It contains a nested Page class, which has a “fluent” interface for building a link. Navigation then looks as follows:

    
    @Inject
    private Nav nav;
    
    public String action() {
         // business logic ...
         return nav.getViewEntry().redirect().includeViewParams().s();
    }
    

    Or, if you want to include only one parameter:

    
    public String action() {
         // business logic ...
         return nav.getViewEntry().redirect().includeViewParam("name").s();
    }
    

    In xhtml pages, you can also use the nav component to generate links:

    
    <h:link outcome="#{nav.manageIndex.s}">Manage</h:link>
    

    Notice that you completely abstract away from the actual names of the xhtml views (pages) – they are stored centrally only in the nav component! This makes any refactorings really easy.

    Speaking of the nav component, here’s the code:

    
    /**
     * @author Adam Warski (adam at warski dot org)
     */
    @Named
    @ApplicationScoped
    public class Nav {
        public static class Page {
            private final String viewId;
            private final Map<String, String> params;
    
            private Page(String viewId) {
                this.viewId = viewId;
                this.params = new LinkedHashMap<String, String>();
            }
    
            private Page(String viewId, Map<String, String> params) {
                this.viewId = viewId;
                this.params = params;
            }
    
            public Page redirect() {
                return includeParam("faces-redirect", "true");
            }
    
            public Page includeViewParams() {
                return includeParam("includeViewParams", "true");
            }
    
            public Page includeViewParam(String name) {
                // Getting the metadata facet of the view
                FacesContext ctx = FacesContext.getCurrentInstance();
                ViewDeclarationLanguage vdl = ctx.getApplication().getViewHandler()
                      .getViewDeclarationLanguage(ctx, viewId);
                ViewMetadata viewMetadata = vdl.getViewMetadata(ctx, viewId);
                UIViewRoot viewRoot = viewMetadata.createMetadataView(ctx);
                UIComponent metadataFacet = viewRoot.getFacet(
                      UIViewRoot.METADATA_FACET_NAME);
    
                // Looking for a view parameter with the specified name
                UIViewParameter viewParam = null;
                for (UIComponent child : metadataFacet.getChildren()) {
                    if (child instanceof UIViewParameter) {
                        UIViewParameter tempViewParam = (UIViewParameter) child;
                        if (name.equals(tempViewParam.getName())) {
                            viewParam = tempViewParam;
                            break;
                        }
                    }
                }
    
                if (viewParam == null) {
                    throw new FacesException("Unknown parameter: '" + name +
                         "' for view: " + viewId);
                }
    
                // Getting the value
                String value = viewParam.getStringValue(ctx);
                return includeParam(name, value);
            }
    
            public Page includeParam(String name, String value) {
                Map<String, String> newParams = new LinkedHashMap<String, String>(params);
                newParams.put(name, value);
                return new Page(viewId, newParams);
            }
    
            public String s() {
                StringBuilder sb = new StringBuilder();
                sb.append(viewId);
    
                String paramSeparator = "?";
                for (Map.Entry<String, String> nameValue : params.entrySet()) {
                    sb.append(paramSeparator).append(nameValue.getKey())
                          .append("=").append(nameValue.getValue());
                    paramSeparator = "&amp;amp;";
                }
    
                return sb.toString();
            }
    
            public String getS() { return s(); }
        }
    
        private final Page manageIndex = new Page("/manage/index.xhtml");
        private final Page manageUsers = new Page("/manage/users.xhtml");
        private final Page home = new Page("/home.xhtml");
        private final Page thisPage = new Page("");
        // other pages ...
    
        public Page getManageIndex() {
            return manageIndex;
        }
    
        // other getters ...
    }
    

    Looking forward, the Page class may also include e.g. security management, however that would require some more JSF bindings.

    Adam

  • Dependency Injection and replacing dependencies in CDI/Weld

    Posted on December 16th, 2009 Adam Warski 1 comment

    From time to time, in a system I develop, which uses EJB3 beans as the basic “component model”, I have a need to do some operations using a new entity manager (but still in the same transaction). The problem here is that if I invoke a method on another bean, which has an entity manager injected (using @PersistenceContext EntityManager em), the entity manager will be the original one. There is no way to temporarily replace it or any other dependency, just for the time of one invocation.

    That’s why I wanted to see if that would be possible to achieve using the recently released Weld framework, reference implementation of the CDI specification (part of JEE 6). Unlike in Seam, where injection is done whenever a method on a managed bean is invoked (which would theoretically make it easier to do the temporary replacement), in CDI injection happens once, when the objects are constructed. So the only way (at least the only way I see) to implement temporary replacement is to wrap the injected beans in some kind of an interceptor.

    In CDI, injected beans can either be “stand-alone”, or come from a producer (factory) method (annotated with @Producer). As EntityManagers are typically created by producer methods, in the example below I assume this scenario. It is possible to slightly change the code so that it works for normal beans, however I didn’t manage to create a nice universal solution (which wouldn’t simply do an “if” to check if the bean is created by a producer method).

    To test, we define a simple bean which will have a dependency injected via constructor injection:

    
    @ApplicationScoped
    public class FirstBean implements Serializable {
        private ISecondBean second;
        public FirstBean() { }
    
        @Inject
        public FirstBean(ISecondBean second) { this.second = second; }
    
        public void start(int c) {
            System.out.println("Type of second: " + second.getMessage(c));
        }
    }
    

    The interface ISecondBean has two implementations:

    
    public interface ISecondBean extends Serializable {
        String getMessage(int c);
    }
    
    @Alternative
    public class SecondBeanA implements ISecondBean {
        public String getMessage(int c) { return "variant A; " + c; }
    }
    
    @Alternative
    public class SecondBeanB implements ISecondBean {
        public String getMessage(int c) { return "variant B; " + c; }
    }
    

    The @Alternative annotation makes the bean disabled by default, so that Weld doesn’t try to inject an instance of it when there’s a matching injection point. That’s because we want to produce implementations of ISecondBean using a producer method:

    
    @ApplicationScoped
    public class SecondBeanProducer {
        @Produces
        public ISecondBean getSecondBean() {
            return new SecondBeanA();  // by default we use the A variant
        }
    }
    

    A very nice feature of Weld/CDI, especially for evaluation purposes, is that it’s possible to use it very easily in Java SE. To test our beans, all we need to do is run the org.jboss.weld.environment.se.StartMain, putting a jar with our classes in the classpath. One important thing is that the jar must contain a beans.xml file (it can be empty, but it must exist). We can observe the container startup-event to do some work:

    
    @ApplicationScoped
    public class Main {
        @Inject
        private FirstBean first;
    
        public void start(@Observes ContainerInitialized event) throws Exception {
            System.out.println("Welcome to Main!");
            first.start(1);
            first.start(2);
            first.start(3);
        }
    }
    

    The result will be:

    
    Welcome to Main!
    Type of second: variant A; 1
    Type of second: variant A; 2
    Type of second: variant A; 3
    

    Now we finally come to the point of implementing the replaceable dependencies. As you may have guessed, ISecondBean corresponds to EntityManager, and that’s the dependency that we will try to replace.

    To do that, we first have to define an interceptor. That’s quite easy and intuitive in CDI/Weld (documentation here). There are three steps:

    1. write an annotation, which will be an interceptor binding: all methods annotated with that annotation will be intercepted
    2. write the interceptor, annotating it with the annotation created earlier: that way Weld will know that the annotation binds the given interceptor
    3. enable the interceptor in beans.xml

    Here’s the code (full interceptor code below):

    
    @InterceptorBinding
    @Target({ ElementType.TYPE, ElementType.METHOD })
    @Retention(RetentionPolicy.RUNTIME)
    public @interface ReplaceableResult {
    }
    
    @Interceptor
    @ReplaceableResult
    public class ReplaceableResultInterceptor {
        @AroundInvoke
        public Object replace(InvocationContext ctx) throws Exception {
            ...
        }
    }
    
    
    <beans>
        <interceptors>
            <class>test.ReplaceableResultInterceptor</class>
        </interceptors>
    </beans>
    

    Adding an interceptor for a method is easy: if we want to be able to temporarily replace implementations of ISecondBean, all we need to do is annotate the producer method with the new annotation. SecondBeanProducer now takes the form:

    
    @ApplicationScoped
    public class SecondBeanProducer {
        @Produces @ReplaceableResult
        public ISecondBean getSecondBean() {
            return new SecondBeanA();  // by default we use the A variant
        }
    }
    

    We can now test the temporary replacement by modifying the Main bean that we used before:

    
    @ApplicationScoped
    public class Main {
        @Inject
        private FirstBean first;
    
        public void start(@Observes ContainerInitialized event) throws Exception {
            System.out.println("Welcome to Main!");
            first.start(1);
    
            // Here we replace the implementation of ISecondBean just for
            // the duration of one method call.
            ReplaceableResultInterceptor.withReplacement(
                    ISecondBean.class,
                    new SecondBeanB(), // we are using the B variant
                    new Callable<Void>() {
                        @Override
                        public Void call() throws Exception {
                            first.start(2);
                            return null;
                        }
                    });
    
            first.start(3);
        }
    }
    

    The result will now be:

    
    Welcome to Main!
    Type of second: variant A; 1
    Type of second: variant B; 2
    Type of second: variant A; 3
    

    So the dependency in FirstBean was swapped! Which was our goal: for the duration of the bean method invocation, whenever a ISecondBean dependency is injected, the temporary implementation will be used.
    Full code of the interceptor:

    
    @Interceptor
    @ReplaceableResult
    public class ReplaceableResultInterceptor {
        private static ThreadLocal<Map<Class<?>, Object>> replacements
            = new ThreadLocal<Map<Class<?>, Object>>() {
            @Override
            protected Map<Class<?>, Object> initialValue() {
                return new HashMap<Class<?>, Object>();
            }
        };
    
        @AroundInvoke
        public Object replace(InvocationContext ctx) throws Exception {
            Class<?> returnType = ctx.getMethod().getReturnType();
            if (!returnType.isInterface()) {
                throw new UnsupportedOperationException("Only results of methods " +
                   "which produce implementations of an interface can be replaced!");
            }
    
            // Getting the result of the producer method
            Object result = ctx.proceed();
    
            // Wrapping it in an interceptor, which on an invocation will check if
            // there's a replacement
            result = Proxy.newProxyInstance(
                    returnType.getClassLoader(),
                    new Class[] { returnType },
                    new ReplaceableInterceptor(returnType, result));
    
            return result;
        }
    
        public static <V> V withReplacement(Class<?> replacing, Object replacement,
            Callable<V> toCall) throws Exception {
            boolean hasOld = false;
            Object old = null;
            try {
                hasOld = replacements.get().containsKey(replacing);
                old = replacements.get().put(replacing, replacement);
                return toCall.call();
            } finally {
                if (hasOld) {
                    replacements.get().put(replacing, old);
                } else {
                    replacements.get().remove(replacing);
                }
            }
        }
    
        private class ReplaceableInterceptor implements InvocationHandler {
            private final Class<?> replacementsKey;
            private final Object delegate;
    
            private ReplaceableInterceptor(Class<?> replacementsKey,
                Object delegate) {
                this.replacementsKey = replacementsKey;
                this.delegate = delegate;
            }
    
            @Override
            public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
                if (replacements.get().containsKey(replacementsKey)) {
                    return method.invoke(replacements.get().get(replacementsKey),
                        args);
                } else {
                    return method.invoke(delegate, args);
                }
            }
        }
    }
    

    Overall, CDI/Weld works very well and I’m very satisfied with it. One thing I’m missing is being to able to do programmatic configuration (Guice-style), but it’s already in the list of ideas for future portable extensions. I think that programmatic configuration and the ability to run Weld in JavaSE will create a great mix for “semi-integration” testing.

    Adam