News

Weld 3.0.0.Alpha16

2016-4-28   release , cdi2   Martin Kouba

The next experimental Weld version has been released! See also the release details. Thanks to everyone involved in this release!

This release includes a lot of bugfixes and improvements (e.g. all the notable tasks implemented in the latest stable version: Weld 2.3.4.Final). However, the main goal of this release is to align with CDI API 2.0.Alpha4, and in particular to implement the current version of "metadata builders" API (CDI-558). So that everyone can play with the API, discover possibilities and find potential issues. Note that this release also introduces a non-standard experimental feature: Weld SE synthetic container lifecycle event observers. So it should be even easier to get started - no extension class is needed in Weld SE.

Metadata configurators - basic ideas

Note that we don’t use the term "builder" because there is no build() method in the API. Also note that the API is not intended to cover every possible case. Instead, we would like to help with common tasks. And if necessary, an extension developer can always use the original replacement methods for more complicated stuff.

IMPORTANT POINTS:

  • an extension developer receives a configurator instance from a container lifecycle event

  • a configurator instance is always automatically processed at the end of the observer invocation

  • for bean discovery events (all events starting with Process):

    • configureX() methods return the same configurator instance (for the given observer method invocation)

    • the configurator is initialized/preconfigured with the component being processed, e.g. ProcessAnnotatedType.configureAnnotatedType() returns a configurator initialized with ProcessAnnotatedType.getAnnotatedType()

    • the result of the configurator will automatically replace the original component (e.g. AnnotatedType in case of ProcessAnnotatedType)

    • replacement methods (e.g. ProcessAnnotatedType.setAnnotatedType()) should not be used together with configurators (CDI-596)

  • for application lifecycle events (e.g. AfterBeanDiscovery):

    • addX() methods always return a new configurator instance

    • the configurator is always uninitialized/empty, but we should probably define some default values wherever it makes sense (e.g. Reception for observer methods)

    • the result of the configurator will be automatically added (e.g. Bean in case of AfterBeanDiscovery.addBean())

We have prepared some simple examples - see below. More advanced examples can be found in the TCK test cases. And as usual - feel free to add comments to this blog post. Any feedback is appreciated!

BeforeBeanDiscovery example

@Singleton
    class MyService {
        // This class is not placed in a bean archive
    }
    
    class MyExtension implements Extension {
    
        void beforeBeanDiscovery(@Observes BeforeBeanDiscovery event) {
            // Add MyService to the set of discovered classes and replace @Singleton with @ApplicationScoped
            event.addAnnotatedType(MyService.class.getName(), MyService.class)
                   .remove(Singleton.class)
                   .add(ApplicationScoped.Literal.INSTANCE);
        }
    }

ProcessAnnotatedType example

class MyExtension implements Extension {
    
        void processAnnotatedType(@Observes @WithAnnotations({ Observes.class, ObservesAsync.class }) ProcessAnnotatedType<?> event) {
            // Add interceptor binding to all methods annotated with @Observes or @ObservesAsync
            event.configureAnnotatedType()
                    .filterMethods(MyExtension::isObserver)
                    .forEach(methodConfigurator -> methodConfigurator.add(Monitored.Literal.INSTANCE))
        }
    
        static boolean isObserver(AnnotatedMethod<?> annotatedMethod) {
            return annotatedMethod.isAnnotationPresent(Observes.class) || annotatedMethod.isAnnotationPresent(ObservesAsync.class);
        }
    }

ProcessBeanAttributes example

class MyExtension implements Extension {
    
        void processBeanAttributes(@Observes ProcessBeanAttributes<?> event) {
            // For all beans remove the IllegalBeanType from the set of bean types
            if (event.getBeanAttributes().getTypes().contains(IllegalBeanType.class)) {
                Set<Type> legalTypes = new HashSet(event.getBeanAttributes().getTypes());
                legalTypes.remove(IllegalBeanType.class);
                event.configureBeanAttributes().types(legalTypes);
            }
        }
    }

AfterBeanDiscovery example

class MyExtension implements Extension {
    
        void afterBeanDiscovery(@Observes AfterBeanDiscovery event) {
            //  Add a new synthetic observer method - no need to use the fluent API
            ObserverMethodConfigurator<Foo> configurator = event.<Foo>addObserverMethod();
            configurator.observedType(Foo.class);
            configurator.reception(Reception.ALWAYS);
            configurator.transactionPhase(TransactionPhase.IN_PROGRESS);
            configurator.notifyWith((foo) -> System.out.println("Foo observed: " + foo));
    
            // Add dependent bean - Integer between 0 and 999
            event.addBean().addType(Integer.class).addQualifier(Random.Literal.INSTANCE)
                    .produceWith(() -> new java.util.Random().nextInt(1000))
        }
    }

WildFly Patch

As usual, a patch for WildFly is available. This time the target platform is WildFly 10.0.0.Final. If you’re not familiar with patching WildFly, check Markus’s tutorial.


Weld 2.3.4.Final

2016-4-22   release   Martin Kouba

Weld 2.3.4.Final the next version of the stable 2.3 branch has been released! See also the release details. Thanks to everyone involved in this release!

Notable bugfixes and improvements:

  • log important actions performed by extensions (WELD-2134)

    • for example, if you want to track down all extensions modifying AnnotatedType definitions, then enable the debug logging for Weld and look for messages containing ProcessAnnotatedType.setAnnotatedType() called by …​

  • Conversations - allow to configure the default timeout and the concurrent access timeout (WELD-2113)

  • recover if a transaction is in progress but a JTA Synchronization callback cannot be registered (WELD-2120)

  • EJB proxies do not implement private methods anymore (WELD-2119)

  • interceptor instances used for @AroundConstruct are now reused for other types of interception (WELD-2131)

  • Weld Servlet

    • fixed handling of archives from WEB-INF/lib on Tomcat 8 with unpackWARs=false (WELD-2122)

    • WeldTerminalListener should not throw NPE if injection into listeners is not supported (WELD-2123)

  • Weld SE

    • improved support of implicit bean archives (WELD-2129)

    • there are two new built-in interceptor bindings - @ActivateRequestScope and @ActivateThreadScope - to activate the request scope or the thread scope within a business method invocation

    • Weld builder allows to configure bean archive isolation, development mode and registration of shutdown hook manually (WELD-2135)

    • a basic nested archive support was added (WELD-1930)

WildFly Patch

As usual, a patch for WildFly is available. This time the target platform is WildFly 10.0.0.Final. If you’re not familiar with patching WildFly, check Markus’s tutorial.


Weld meets Vert.x

2016-4-11   vertx , integration   Martin Kouba

Vert.x defines itself as "a toolkit for building reactive applications on the JVM". Sounds cool and trendy. Weld, on the other hand, comes from the Java EE world, based on standards and traditional concepts. But wait, what if we try to combine the two worlds to get the best of them?

Vert.x makes use of a light-weight distributed messaging system to allow application components to communicate in a loosely coupled way. This should sound familiar to all CDI users where beans may produce and consume events as well. Weld team developed a working prototype of Weld/Vert.x integration that allows to automatically register certain observer methods as Vert.x message consumers. A simple echo message consumer could look like this:

import org.jboss.weld.vertx.VertxConsumer;
    import org.jboss.weld.vertx.VertxEvent;
    
    class Foo {
        public void echoConsumer(@Observes @VertxConsumer("test.echo.address") VertxEvent event) {
            event.setReply(event.getMessageBody());
        }
    }
  • @VertxConsumer - a qualifier used to specify the address the consumer will be registered to: test.echo.address

  • VertxEvent - a wrapper of a Vert.x message

Since we’re working with a regular observer method, additional parameters may be declared (next to the event parameter). These parameters are injection points. So it’s easy to declare a message consumer dependencies:

public void consumerWithDependencies(@Observes @VertxConsumer("test.dependencies.address") VertxEvent event, CoolService coolService, StatsService statsService) {
        coolService.process(event.getMessageBody());
        statsService.log(event);
    }
Note
If you inject a dependent bean, it will be destroyed when the invocation completes.

Last but not least - an observer may also send/publish messages using the Vert.x event bus:

public void consumerStrikesBack(@Observes @VertxConsumer("test.publish.address") VertxEvent event) {
        event.messageTo("test.huhu.address").publish("huhu");
    }

And how does it work under the hood? First of all, it’s necessary to deploy org.jboss.weld.vertx.WeldVerticle. This Verticle starts Weld SE container and automatically registers org.jboss.weld.vertx.VertxExtension to process all observer methods and detect observers which should become message consumers. Then a special handler is registered for each address to bridge the event bus to the CDI world. Handlers use Vertx.executeBlocking() since we expect the code to be blocking. Later on, whenever a new message is delivered to the handler, Event.fire() is used to notify all relevant observers.

The prototype is surely missing some features. Nevertheless, it shows the CDI programming model might be applicable to the "reactive" world even if not a first class citizen. Moreover, the prototype demonstrates the flexibility of the CDI extension mechanism.

If you want to try it out, you’ll have to clone the https://github.com/weld/weld-vertx repository and build it from source (i.e. run mvn clean install). And if you find it useful feel free to add comments to this blog post. Any feedback is appreciated!


Weld 2.3.3.Final

2016-2-12   release   Martin Kouba

Weld 2.3.3.Final the next bug-fix version of the stable 2.3 branch has been released! See also the release details. Thanks to everyone involved in this release! Notable improvements:

WildFly Patch

As usual, a patch for WildFly is available. This time the target platform is WildFly 10.0.0.Final. If you’re not familiar with patching WildFly, check Markus’s tutorial.


Weld SE and synthetic container lifecycle event observers

2016-2-8   api , draft   Martin Kouba

Last week Weld 3.0.0.Alpha15 was released and so it’s time to reveal the features that should go into the next experimental release. The main goal of Weld 3.0.0.Alpha16 is to reflect the output of CDI-558. However, we would also like to continue to deliver experimental prototypes so that users could test a new functionality (that we find interesting and useful) and the CDI EG could eventually include this into CDI 2.0.

It should be easier to start playing with extensions in Weld SE. Right now, it’s possible to pass an Extension instance to the Weld builder so that it’s not necessary to configure service providers (i.e. META-INF/services/javax.enterprise.inject.spi.Extension file). In such case, the extension class is automatically scanned for observer methods and the instance is used as the receiver of the notifications. We would like to make this even easier. It is now possible to add a synthetic container lifecycle event observer without declaring an extension class. The observer logic is represented as a lambda expression. This might be especially useful for prototyping and/or for discovering how extensions work.

The starting point is the org.jboss.weld.environment.se.ContainerLifecycleObserver class. There are few static methods, each corresponding to a specific container lifecycle event (e.g. beforeBeanDiscovery()). Some variants return a builder so that it’s possible to customize the observer (observed type, priority, etc.). Others accept a lambda and return an observer instance direcly.

A synthetic observer may be added to the builder directly - see Weld.addContainerLifecycleObserver() - or grouped in a synthetic extension - see ContainerLifecycleObserver.extensionBuilder().

Extension testExtension = ContainerLifecycleObserver.extensionBuilder()
        .add(afterBeanDiscovery((e) -> System.out.println("Bean discovery completed!")))
        .add(processAnnotatedType().notify((e) -> {
                if (e.getAnnotatedType().getJavaClass().getName().startsWith("com.foo")) {
                    e.veto();
                }
            })).build();
    
    try (WeldContainer container = new Weld().addExtension(testExtension).initialize()) {
        // Use the container...
    }

This feature is merged in the master branch. If you want to try it out, you’ll have to use a 3.0.0-SNAPSHOT version or build the Weld from source: mvn clean install. Do you find it useful? Any feedback is appreciated! Feel free to add comments to this blog post or to the corresponding issue: WELD-2012.