Red Hat

In Relation To Weld

In Relation To Weld

CDI Portable extension examples

Posted by    |       |    Tagged as CDI Weld

One of the nicest features of CDI is the portable extension SPI. According to the spec:

A portable extension may integrate with the container by:
  • Providing its own beans, interceptors and decorators to the container
  • Injecting dependencies into its own objects using the dependency injection service
  • Providing a context implementation for a custom scope
  • Augmenting or overriding the annotation-based metadata with metadata from some other source

We've got plenty of examples of CDI application code floating about, but not much in the way of examples for framework developers who want to integrate with CDI, or augment the built-in functionality. So here's a little taste of the what a CDI portable extension looks like.

Let's start with an example of an extension that provides support for the use of @Named at the package level. The package-level name is used to qualify the EL names of all beans defined in that package.

Portable extensions implement the marker interface Extension and observe container lifecycle events, in this case ProcessAnnotatedType, an event that is fired by the container when it discovers a class or interface in a bean archive. The portable extension wraps the AnnotatedType object and overrides the value() of the @Named annotation of the bean.

public class QualifiedNameExtension implements Extension {

    <X> void processAnnotatedType(@Observes ProcessAnnotatedType<X> pat) {

        //wrap this to override the annotations of the class
        final AnnotatedType<X> at = pat.getAnnotatedType();

        AnnotatedType<X> wrapped = new AnnotatedType<X>() {

            @Override
            public Set<AnnotatedConstructor<X>> getConstructors() {
                return at.getConstructors();
            }

            @Override
            public Set<AnnotatedField<? super X>> getFields() {
                return at.getFields();
            }

            @Override
            public Class<X> getJavaClass() {
                return at.getJavaClass();
            }

            @Override
            public Set<AnnotatedMethod<? super X>> getMethods() {
                return at.getMethods();
            }

            @Override
            public <T extends Annotation> T getAnnotation(final Class<T> annType) {
                if ( Named.class.equals(annType) ) {
                    class NamedLiteral 
                            extends AnnotationLiteral<Named> 
                            implements Named {
                        @Override
                        public String value() {
                            Package pkg = at.getClass().getPackage();
                            String unqualifiedName = at.getAnnotation(Named.class).value();
                            final String qualifiedName;
                            if ( pkg.isAnnotationPresent(Named.class) ) {
                                qualifiedName = pkg.getAnnotation(Named.class).value() 
                                      + '.' + unqualifiedName;
                            }
                            else {
                                qualifiedName = unqualifiedName;
                            }
                            return qualifiedName;
                        }
                    }
                    return (T) new NamedLiteral();
                }
                else {
                    return at.getAnnotation(annType);
                }
            }

            @Override
            public Set<Annotation> getAnnotations() {
                return at.getAnnotations();
            }

            @Override
            public Type getBaseType() {
                return at.getBaseType();
            }

            @Override
            public Set<Type> getTypeClosure() {
                return at.getTypeClosure();
            }

            @Override
            public boolean isAnnotationPresent(Class<? extends Annotation> annType) {
                return at.isAnnotationPresent(annType);
            }
            
        };

        pat.setAnnotatedType(wrapped);
    }
    
}

We need to deploy this portable extension in a jar containing a file named javax.enterprise.inject.spi.Extension in the META-INF/services directory. This file should contain the full name of our QualifiedNameExtension class.

Here's a second example, of a portable extension that creates Bean objects for each class in a set of classes and registers the beans with the container. This is similar to what the container does for classes it discovers in bean archives.

public class RegisterExtension implements Extension {
    
    List<Class<?>> getBeanClasses() { 
        //get some classes from somewhere
    }
    
    void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) {
        for ( final Class c: getBeanClasses() ) {
            
            //use this to read annotations of the class
            AnnotatedType at = bm.createAnnotatedType(c); 

            //use this to create the class and inject dependencies
            final InjectionTarget it = bm.createInjectionTarget(at); 

            abd.addBean( new Bean() {
    
                @Override
                public Class<?> getBeanClass() {
                    return c;
                }
    
                @Override
                public Set<InjectionPoint> getInjectionPoints() {
                    return it.getInjectionPoints();
                }
    
                @Override
                public String getName() {
                    return null;
                }
    
                @Override
                public Set<Annotation> getQualifiers() {
                    Set<Annotation> qualifiers = new HashSet<Annotation>();
                    qualifiers.add( new AnnotationLiteral<Default>() {} );
                    qualifiers.add( new AnnotationLiteral<Any>() {} );
                    return qualifiers;
                }
    
                @Override
                public Class<? extends Annotation> getScope() {
                    return Dependent.class;
                }
    
                @Override
                public Set<Class<? extends Annotation>> getStereotypes() {
                    return Collections.emptySet();
                }
    
                @Override
                public Set<Type> getTypes() {
                    Set<Type> types = new HashSet<Type>();
                    types.add(c);
                    types.add(Object.class);
                    return types;
                }
    
                @Override
                public boolean isAlternative() {
                    return false;
                }
    
                @Override
                public boolean isNullable() {
                    return false;
                }
    
                @Override
                public Object create(CreationalContext ctx) {
                    Object instance = it.produce(ctx);
                    it.inject(instance, ctx);
                    it.postConstruct(instance);
                    return instance;
                }
    
                @Override
                public void destroy(Object instance, CreationalContext ctx) {
                    it.preDestroy(instance);
                    it.dispose(instance);
                    ctx.release();
                }
                
            } );
        }
    }
    
}

UPDATE: I've finally got a proper chapter on portable extensions written up in the Weld reference documentation. Check out chapter 16 of this version if this post piqued your interest.

Oops-a-daisy

Posted by    |       |    Tagged as CDI Seam Weld

Gavin pointed out to me that my script to build the Weld distribution was broken, so I've create Weld 1.0.0 SP1 (Service Pack 1) which remedies this. You can now find Weld's sources and binaries in artifacts/weld and the CDI API source, javadoc and binary in artifacts/cdi. Download it from here.

At the same time, Shane and I realized that the signature test definition for the TCK had been generated against a slightly out of date API. So I've posted 1.0.0 SP1 of the TCK here.

Granite DS and CDI

Posted by    |       |    Tagged as CDI Weld

William Drai has blogged about his experience integrating Granite DS and CDI.

Our feeling is that JCDI is a perfect fit for Flex RIAs with an event-driven architecture. JCDI applications look extremely clean and even though JBoss Seam provides a lot more features, they do not necessarily make sense with a RIA front-end.

The mapping to Flex does look very clean to me. I especially like what William has done with mapping CDI events into the client. Very nice, and very faithful to CDI.

Modular dependencies

Posted by    |       |    Tagged as CDI Weld

I've written a couple of posts about using @Alternative to achieve deployment-time polymorphism. What I've never really talked about is its role in CDI modularity.

Modularity and alternatives

From our point of view, support for modularity in dependency management means that injection points of the same type, in different modules, can resolve to different beans. For example, suppose I have an interface Supplier, with two implementations. Let's say they are beans like BookSupplier and CameraSupplier, but they could easily be something more exotic. Now, in one module, bookshop.war, of my application, I have a BookShop:

class BookShop {
   @Inject
   BookShop(Supplier supplier) { ... }
   ...
}

In another module, camerashop.war, I have a CameraShop:

class CameraShop {
   @Inject
   CameraShop(Supplier supplier) { ... }
   ...
}

Now, how does the container tell that the Supplier in BookShop is a BookSupplier, but the Supplier in CameraShop is a CameraSupplier?

Well, there's two possibilities:

BookSupplier and CameraSupplier are deployed in different modules

Suppose that BookSupplier and CameraSupplier are deployed in separate modules, books.jar and cameras.jar respectively. Then the solution is easy. Just declare that bookshop.war depends on books.jar and that camerashop.war has a dependency to cameras.jar, and we're done. That's enough information for CDI to know what to inject where.

So bookshop.war would contain the following line in MANIFEST.MF:

Class-Path: books.jar

Meanwhile, camerashop.war would contain this line in its MANIFEST.MF:

Class-Path: cameras.jar

BookSupplier and CameraSupplier are deployed in the same module

But what if BookSupplier and CameraSupplier are both deployed in suppliers.jar? Well, there's a solution in this case, too.

First we need to add the @Alternative annotation to BookSupplier and CameraSupplier. @Alternative tells CDI not to inject a bean into a module that does not explicitly declare its dependency to the bean.

Next, we need to declare the appropriate alternative in each module. In bookshop.war, we specify:

<beans>
   <alternatives>
      <class>org.mydomain.supplier.BookSupplier</class>
   </alternatives>
</beans>

In camerashop.war, we specify:

<beans>
   <alternatives>
      <class>org.mydomain.supplier.CameraSupplier</class>
   </alternatives>
</beans>

And now each module has it's own, private, implementation of Supplier.

What if BookShop and CameraShop are deployed in the same module?

I suppose, at this point, you're wondering what happens if the clients, BookShop and CameraShop are deployed in the same module. Well, in this case we need to look for another solution. CDI doesn't support more granular alternative activation. There are no bean-level or package-level alternatives. (At least not in this release of CDI.)

Instead we need to add a qualifier, for example:

class BookShop {
   @Inject
   BookShop(@Supplies(Book.class) Supplier supplier) { ... }
   ...
}

or, more likely, add a generic type parameter to Supplier:

class BookShop {
   @Inject
   BookShop(Supplier<Book> supplier) { ... }
   ...
}

Unified EL

The example we've worked with involves Java classes using injection to obtain their dependencies. But what about JSP or JSF pages, which use Unified EL expressions to interact with beans. Well, happily, exactly the same rules apply during EL name resolution.

Modularity beyond Java EE

I've given examples from the Java EE environment. In this environment, a module is a Java EE module like a war, EJB jar or rar, or a library jar. But what about other module architectures like OSGi or a future Java language-level module system?

Well, the CDI spec is slightly future-proof in this respect. This functionality is defined for an abstract notion of a module in an abstract module architecture. So it's more or less well-defined what a CDI implementation should do in an OSGi architecture, if it wanted to support OSGi.

Weld 1.0.0 :-)

Posted by    |       |    Tagged as CDI Seam Weld

I'm pleased to announce the release of Weld 1.0.0 - the announcements have been flowing in over the last few days, but this is my favorite!

You can find some quick download links below or you can pull the artifacts from the maven central repository.

Weld is used in GlassFish V3 and the upcoming JBoss AS EE 6 Preview release release (watch Jason's blog for more!). We also have support for Servlet containers such as Tomcat and Jetty. JSF support is built in, but with Weld you could use Wicket as your view layer, and Swing, or even JavaFX is supported via the Java SE support. If you are an OSGi fan, there's a bundle.

If you are just getting started, there are a few examples in the distribution to guide you (look for instructions in the reference guide, and each example has a readme.txt). If you are looking for help, try our forums, or perhaps join us on IRC.

I intend to do regular releases of Weld from now on (around 8-10 weeks apart), and for 1.0.1 we'll be concentrating on running an indepth performance and scalability analysis (as well as fixing those bugs you report!). Those of you who follow us closely will know that we've been concentrating on Weld/JSR-299 recently, but with 1.0.0 out, you can expect to see our attention swing back to Seam 3 - so watch this space, as soon as we have nightly builds to try out, I'll post instructions :-)

One omission from the CR1 release was the reference documentation -- since then a lot of effort has been put into the reference guide and the JavaDoc for the CDI API - make sure you check it out!

[Weld Download] | [Weld JIRA] | [CDI Javadoc] [ Reference Guide] | [Weld Release Notes] ]

Mark Little, the CTO of JBoss, blogged about our vision for component models in JBoss platforms - he gives a great overview, describing how Seam (and JSR-299/Weld) will form the core programming model.

JSR-299 Final Draft Submitted

Posted by    |       |    Tagged as CDI Seam Weld

Today, Red Hat submitted the final draft of JSR-299[1], which now goes under the moniker CDI (Contexts and Dependency Injection), along with the Reference Implementation and TCK. Check out the spec[1] and Javadoc.

This specification defines a powerful set of complementary services that help improve the structure of application code.
  • A well-defined lifecycle for stateful objects bound to lifecycle contexts, where the set of contexts is extensible
  • A sophisticated, typesafe dependency injection mechanism, including the ability to select dependencies at either development or deployment time, without verbose configuration
  • Support for Java EE modularity and the Java EE component architecture - the modular structure of a Java EE application is taken into account when resolving dependencies between Java EE components
  • Integration with the Unified Expression Language (EL), allowing any contextual object to be used directly within a JSF or JSP page
  • The ability to decorate injected objects
  • The ability to associate interceptors to objects via typesafe interceptor bindings
  • An event notification model
  • A web conversation context in addition to the three standard web contexts defined by the Java Servlets specification
  • An SPI allowing portable extensions to integrate cleanly with the container

I would like to take this opportunity to thank the Expert Group and everyone else who contributed ideas and criticism to this specification. Folks outside the JCP probably can't really imagine the incredible investment of time and emotional energy that it takes to create a spec like this. I would really, really like to single out a couple of individual members of the EG for their great ideas and totally uncompensated work, but I guess there's no way to do that without leaving someone feeling unrecognized.

On a more personal note, I believe (and hope) that we've done right by the community, and created something beautiful.

Tomorrow we'll be releasing Weld 1.0.

Attachments

  1. JSR-299-FD-EVAL.pdf

Writing a properties file in Java?

Posted by    |       |    Tagged as CDI Weld

I just noticed that CDI makes it possible to write properties files in Java, instead of plain text. I'm not sure if this is useful, but it is cute.

We define our properties in a class. Of course, since the properties are going to be deployment-specific, we should declare the class @Alternative. (Unless it holds the default values, I suppose.)

@Alternative 
class TestSettings {
   @Produces @Named String adminUser = "admin";
   @Produces @Named String adminPassword = "nimda";
   @Produces @Named int maxRetries = 100;
}

Now, we can inject these properties. Into fields:

@Inject @Named int maxRetries;

Or even into constructors or methods:

@Inject 
Connection(@Named("adminUser") String user, 
           @Named("adminPassword") String pass) { 
   ... 
}

To select the right settings class for a deployment, we list it in beans.xml:

<beans>
   <alternatives>
      <class>settings.TestSettings</class>
   </alternatives>
</beans>

You could even write a really simple portable extension that would weave in the necessary @Alternative, @Produces and @Named annotations to the following class:

@Properties 
class TestSettings {
   String adminUser = "admin";
   String adminPassword = "nimda";
   int maxRetries = 100;
}

(If you want to know how to do this, go read up on the ProcessAnnotatedType event that is part of the CDI portable extension SPI.)

Well, I suppose it would be more typesafe to create a Settings interface with getter methods for all the properties, and inject that. Still, for an accidental feature, this is kinda cool.

UPDATE: hrrrm ... this feature makes somewhat more sense, when you realize that TestSettings is also a perfect place to declare all your deployment specific resources.

CDI Javadoc

Posted by    |       |    Tagged as CDI Seam Weld

I put a whole bunch of work into the Javadoc for CDI recently. You can see it here. There's a good overview of the spec in the package doc for javax.enterprise.inject.

Oh, I also did the Javadoc for javax.interceptor, but that's not available anywhere yet.

It's not about dependency injection

Posted by    |       |    Tagged as CDI Weld

I'm trying really hard to emphasize to the community that CDI and Weld are not just a dependency injection solution. We did not come at this from the point of view of trying to solve dependency injection, or of trying to build a better Spring.

What I was really thinking about when I started working on Seam was state management in event driven architectures. How can you ensure that an event is processed with the correct set of state for the context(s) it carries with it? I wanted to get away from the awful front controller pattern, where some big stupid stateless method is responsible for coordinating everything involved in processing the event, from state retrieval and storage, to service location, to orchestration.

There were a couple of frameworks which were ahead of their time in this respect. The one that got me started was XWork, a dependency injection solution that was part of earlier versions of WebWork. That's why I was kind of excited when I saw the same ideas in JSF (setting aside many other problems with JSF 1.0).

It's also why I pushed back so hard when some people questioned the existence of the event notification facility in CDI. Though it appeared to some folks to be a kind of cute feature stuck on the side of a dependency injection container, that's not what it was to me at all. Indeed, the idea of event processing was right at the core of what we were trying to achieve in JSR-299.

back to top