News

Weld Vert.x Next?

2017-8-7   vertx , integration   Martin Kouba

Last year Weld team announced the weld-vertx project (see also Weld meets Vert.x and Update on weld-vertx articles). The goal was clear - bring the CDI programming model into the Vert.x ecosystem. Since then, several things have changed. Two new modules were added, CDI 2 and Weld 3 is now used by default, and two final versions were released. I think it’s a good time to summarize the features and plans for future.

What Is It Good For?

First of all, it offers a mature component model for business logic in your Vert.x applications. A reasonable component model helps making your applications maintainable and scalable in terms of development and reusability. So the primary intention is to implement the business logic as CDI beans and use Vert.x APIs for everything else.

Modules

So far there are four modules available:

  1. The Core module starts/stops the Weld SE container and to notifies CDI observer methods when a message is sent via Vert.x event bus. Also you can inject io.vertx.core.Vertx and io.vertx.core.Context in any CDI bean.

  2. The Web module allows to configure the router (a component responsible to find the "logic" to handle an HTTP request) in a declarative way, using @org.jboss.weld.vertx.web.WebRoute annotation. Of course, you can register routes programatically. But what if there are hundreds of routes? The more complicated the REST API is the more difficult it is to maintain the code.

  3. The Service Proxy module makes it possible to inject and invoke service proxies (as defined in https://github.com/vert-x3/vertx-service-proxy).

  4. The Probe module enables Weld Probe development tool in a Vert.x application.

How Do I Use It In My Vert.x Webapp?

Let’s enhance an existing webapp in four simple steps.

1. Project Configuration

Jus add the following dependency to your pom.xml and beans.xml into src/main/resources/META-INF (this will enable CDI).

<dependency>
      <groupId>org.jboss.weld.vertx</groupId>
      <artifactId>weld-vertx-web</artifactId>
      <version>${version.weld-vertx}</version>
    </dependency>
Note
This also brings in org.jboss.weld.vertx:weld-vertx-core, Vert.x and Weld dependencies.

2. Start CDI Container

Deploy WeldWebVerticle and configure router:

class MyVertxApp {
    
         public static void main(String[] args) {
             final Vertx vertx = Vertx.vertx();
             // ...deploy other existing verticles
             final WeldWebVerticle weldVerticle = new WeldWebVerticle();
             vertx.deployVerticle(weldVerticle, result -> {
                 if (result.succeeded()) {
                     vertx.createHttpServer().requestHandler(weldVerticle.createRouter()::accept).listen(8080);
                 }
             });
         }
     }

3. Observe Events

Create a CDI observer method to consume messages from the Vert.x event bus. @VertxConsumer qualifier is used to specify the address the consumer will be registered to. VertxEvent is a wrapper of a Vert.x message.

@ApplicationScoped
    class HelloBean {
    
      void consumerWithDependencies(@Observes @VertxConsumer("hello.address") VertxEvent event, HelloService service) {
        // Reply to the message - io.vertx.core.eventbus.Message.reply(Object)
        event.setReply(service.hello());
      }
    }
Note
Since we’re working with regular observer methods, additional parameters may be declared (next to the event parameter) - these parameters are injection points.

4. Declare Routes

Annotate a class implementing Handler<RoutingContext> with @org.jboss.weld.vertx.web.WebRoute:

@WebRoute("/hello") // Matches all HTTP methods
    class HelloHandler implements Handler<RoutingContext> {
    
        @Inject
        HelloService service;
    
        @Override
        public void handle(RoutingContext ctx) {
            ctx.response().setStatusCode(200).end(service.hello());
        }
    }

This will be translated into something like:

void integrationPseudoCode() {
      HelloHandler hello = produceInjectedInstanceOfHelloHandler();
      Router router = obtainRouterInstance();
      router.route("/hello").handler(hello);
    }
Note
@WebRoute is repeatable, i.e. if multiple annotations are declared on a handler class a single handler instance is used for multiple routes.

5. Enjoy and Celebrate

And that’s it. Fairly straightforward, isn’t it?

Future and Plans

So far there are no new features on the roadmap. The plan is to provide bugfix releases as needed. But weld-vertx is an open source project and so the future is in hands of the community. Feel free to create issues, share ideas, throw feature requests and send pull requests!


Weld 2.4.4.Final

2017-6-14   release   Matej Novotny

We have been busy chasing down some annoying little bugs and it’s high time you got the fruits of those efforts into your hands. Say hello to Weld 2.4.4.Final.

Notable fixes and improvements:

  • Weld Core

    • Fixed bean discovery event ordering when processing producers (WELD-2393)

    • Eliminated an NPE for a corner case with abstract decorator (WELD-2273)

    • Corrected @Initialized(RequestScoped.class) event firing in @PostConstruct callbacks (WELD-2372)

    • Fixed BeanManager.isStereotype() behavior when checking a qualifier annotated with yet another qualifier (WELD-2390)

  • Weld SE

    • Added a convenience static method WeldContainer.current(), a shortcut for CDI.current() with no need to cast the result (WELD-2399)

    • Allowed to specify bean discovery mode for synthetic archives (WELD-2386)

    • Fixed bean class discovery problem when adding whole packages (WELD-2395)

  • Weld Servlet

    • Improved logging and make checks more lenient in case the container is not yet bootstrapped (WELD-2382)

  • Configuration options

    • In SE and Servlet environments, Jandex can now be forcibly prohibited from processing your archives. This is useful when a third-party dependecy brings in some unsupported Jandex version (WELD-2374)

  • Development tools

    • If a deployment validation fails and the development mode is enabled, a simple validation HTML report (which contains a lot of useful information) is generated

      • Users are encouraged to always attach this report when asking a question on the mailing list or any other communication channel

WildFly Patch

As usual, a patch for WildFly is available. Target platform is WildFly 10.1.0.Final. If you’re not familiar with patching WildFly, check the FAQ.


Tour around Weld 3

2017-5-19   Matej Novotny

This post briefly describes all the main CDI 2.0 features and elaborates on Weld-specific features we added on top of that. It is not intended as a deep-dive but rather to give you the overall idea of what is going on and what can the new release offer. So, enough talk, let’s get the show on the road!

Async Events and Notification Options

Up until now, the only way to send events was to do so synchronously. That meant stopping the work of your current thread to instead occupy it with observer resolution and subsequent notification of observer methods. Once all that was done, the thread resumed it’s work.

With CDI 2.0 there are asynchronous events - a 'fire & forget' way of handling things. Here is how to fire such and event and how to observe it:

[ source, java ]

// nothing new here, plain old Event is used
    @Inject Event<Payload> event;
    
    public void sendAsyncEvent() {
        // we use a new fireAsync method for asynchronous events
        CompletionStage<Payload> eventResult = event.fireAsync(new Payload()).thenAccept(...);
    }
    
    public void asyncObserver (@ObservesAsync Payload payload){ … }

Few things to note here - first of all, the return value of fireAsync is CompletionStage allowing you to chain the work for when the event is done. You can follow-up with more tasks, react on exceptional return value and so on. Another noticeable detail is that observers which are to be notified have to have @ObservesAsync annotation. As you might have guessed, an observer can be notified of either synchronous (@Observes) or asynchronous (@ObservesAsync) events but never both!

Apart from this very basic usage, async events allow you to specify NotificationOptions - an option allowing you to tweak the way notification works. From CDI perspective, there is currently only one standardized option and that enables usage of custom executors which will be used for notifications. But the API was designed in a generic way so that implementation can enrich it with its own options. Weld currently offers two more options - timeout and parallel execution - both of which are well described in Weld docs. And here is a snippet showing it in action:

[ source, java ]

public void sendAsyncEventWithOptions() {
        // we use a secondary version of fireAsync method with NotificationOptions parameter
        event.fireAsync(new Payload(), NotificationOptions.of("weld.async.notification.timeout", 2000));
    }

Configurators API

Another of the key features are Configurators. They are here to ease our work when doing small tweaks in extensions. Here is a snippet showing how easy it can be to register a new bean in AfterBeanDiscovery using configurator. You don’t have to create a new class implementing Bean<X> anymore:

[ source, java ]

public void addABean(@Observes AfterBeanDiscovery event) {
        // get an instance of BeanConfigurator
        event.addBean()
          // set the desired data
          .types(Foo.class)
          .scope(RequestScoped.class)
          .addQualifier(Custom.CustomLiteral.INSTANCE);
          //finally, add a callback to tell CDI how to instantiate this bean
          .produceWith(obj -> new Foo());
    }

Following configurators were added:

  • AnnotatedTypeConfigurator

  • InjectionPointConfigurator

  • BeanAttributesConfigurator

  • BeanConfigurator

  • ObserverMethodConfigurator

  • ProducerConfigurator

On top of that, Weld adds one additional configurator - InterceptorConfigurator. This one allows you to observe WeldAfterBeanDiscovery and then use this configurator to create and register a custom interceptor from scratch.

SE Bootstrap API

A big change in CDI 2.0 is the SE support. Of course, Weld fans have had this for years now, but it has gone official, so that still counts, right?

The official CDI API is very similar to that of Weld, here is how it looks like:

[ source, java ]

public void bootBasicContainer() {
        SeContainerInitializer initializer = SeContainerInitializer.newInstance();
        try (SeContainer container = initializer.initialize()) {
            Assert.assertTrue(container.isRunning());
        }
    }

This is the very basic way; you can also opt to use synthetic bean archive where you cherry-pick all the beans/interceptors/…​ in your archive. CDI spec describes this fairly well, so how about we instead shift our attention to what Weld SE offers on top of that?

A small reminder of how to boot SE container using pure Weld API:

[ source, java ]

public void bootWeldSeContainer() {
        Weld weld = new Weld();
        try (WeldContainer container = weld.initialize()) {
            container.select(FooBean.class).get();
        }
    }

One of the things Weld makes easier, is when you want to create a quick extension, but don’t really want to write a whole new class which you then need to place in META-INF/services or register on bootstrap. You can easily create a 'synthetic extension' programatically:

[ source, java ]

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...
    }

What we just did was to create an extension with two container lifecycle observer methods. It follows a familiar builder pattern and the body of the observer methods is specified as lambda expression. Before booting SE container, we register this extension as we would any other. For more information about this, don’t hesitate to check our older news post.

On-demand Request Context Activation

Especially in SE (although not only there) you might want to activate a RequestContext manually for certain period of time. There are two ways to achieve that, first of which is an interceptor - @ActivateRequestContext. You can use that on either a method or a type (enabling it for all methods). As you might expect, it will activate the context before executing your method and shut it down afterwards. The other way is through means of built-in bean named RequestContextController. This bean can be injected as any other CDI bean and offers to self-explanatory methods: activate and deactivate. The obvious advantage of this approach is that you can enable the context for an extended period of time.

Observer Method Ordering

A small but noteworthy improvement to observer methods. You can not leverage @Priority annotation in observer methods hence ordering them as you wish.

[ source, java ]

public void observeFirst (@Observes @Priority(1) EventPayload payload) {...}
    
    public void observeSecond (@Observes @Priority(2) EventPayload payload) {...}

Intercepting Produced Beans

Up until now, anything you created using producers could not be easily intercepted. CDI 2.0 allows this for @AroundInvoke interceptors in two ways. There is a new method on BeanManager named createInterceptionFactory but most of the time you will rather use a built-in bean InterceptionFactory which can be injected as a producer method parameter. Here is a snippet:

[ source, java ]

@Produces
    @Dependent
    public ProducedBean produceFoo(InterceptionFactory<ProducedBean> factory) {
        factory.configure().add(Counter.Literal.INSTANCE);
        return factory.createInterceptedInstance(new ProducedBean());
    }

To explain this a bit, we first inject the built-in bean with the type equal to the produced type we wish to intercept. Then we configure() it, which returns an AnnotatedTypeConfigurator allowing us to add interceptor binding. Finally, we invoke InterceptionFactory.createInterceptedInstance() which takes a the object we produce as a parameter.

You can read more about this in this CDI spec chapter.

Trimmed Bean Archives

Last but not least feature we will mention are so called 'trimmed' bean archives. You can mark an explicit bean archive as trimmed in beans.xml by adding the </trim> element. Such bean archive will perform an annotated type discovery as with bean-discovery-mode="all" but all types that don’t have a bean defining annotation or any scope annotation are then removed from the set of discovered types.

Even in this case, Weld allows you to go one step further and veto types based on regular expression. It works on a similar principle but affects your whole application - it processess all types from all bean archives. Your archives will be scanned as they would be with bean discovery mode all and ProcessAnnotatedType will be fired for all found annotated types. Then, based on the regular expression you provide, annotated types which do not have a bean defining annotation and match the regular expression will be vetoed.


Weld 3.0.0.Final - the first implementation of CDI 2.0!

2017-5-15   release   Martin Kouba

I am very pleased to announce the release of Weld 3.0.0.Final - the first implementation of CDI 2.0! I would like to thank not only to everyone involved in this particular release but also to the Weld community as a whole and also to all active CDI EG members who invested a lot of energy into the specification process!

[ source, java ]

/**
     * TODO: Continue to deliver bugfixes and improvements
     */
    public class WeldTeam extends OpenSourceCommunity {
    
      @Inject
      @AwesomeNews
      Event<String> event;
    
      public void release() {
        // Fire asynchronously so that we don't need to wait for observer notification before we start celebrating!
        event.fireAsync("CDI 1.2 is dead, long live CDI 2.0!");
        celebrate();
      }
    
    }
Note
Weld 3 is an IMPORTANT MILESTONE. Therefore, we’re preparing a special blogpost summarizing all the important stuff that was added. Expect the Tour around Weld 3 blogpost within a few days.

Let’s sum up the notable changes since 3.0.0.CR2:

  • Weld defines two non-portable notification options to configure the notification of asynchronous observer methods (see also Notification options for more info):

    • weld.async.notification.mode - the notification mode, possible values are: SERIAL (default) and PARALLEL

    • weld.async.notification.timeout - the notification timeout (in milliseconds) after which the returned completion stage must be completed.

      • If the time expires the stage is completed exceptionally with a CompletionException holding the java.util.concurrent.TimeoutException as its cause

      • The expiration does not abort the notification of the observers

  • Session replication - handle situation when HTTPSessionBean might not be serializable (WELD-2346)

  • Fire @Initialied(RequestScoped.class)/@Destroyed(RequestScoped.class) events for a @PostConstruct callback if the request context was activated for the specific callback

  • Weld SE

    • It’s possible to easily register a org.jboss.weld.bootstrap.api.Service during container bootstrap (WELD-2360)

    • Any javax.enterprise.inject.spi.CDI method can now be called during AfterDeploymentValidation (WELD-2371)

    • ContainerInitialized and ContainerShutdown now implement toString() (WELD-2354)

  • Weld Servlet

    • Fixed usage of Jandex on Tomcat when using unpackWars=false (WELD-2357)

  • Added option to disable Jandex in Weld SE and Weld Servlet (WELD-2374)

  • Development tools

    • If a deployment validation fails and the development mode is enabled a simple validation HTML report (which contains a lot of useful information) is generated

      • Users are encouraged to always attach this report when asking a question on the mailing list or any other communication channel

  • Updated documentation and migration notes for integrators

  • Examples cleanup (dropped GAE support, etc.)

WildFly Patch

As usual, a patch for WildFly is available. This time the target platforms are WildFly 10.1.0.Final and WildFly 11.0.0.Alpha1. If you’re not familiar with patching WildFly, check the FAQ.


Weld 2.4.3.Final

2017-4-7   release   Matej Novotny

Even as we get ever closer to CDI 2.0 final version, we shan’t forget about our stable 2.4 branch. Ladies and gentlemen, here comes the next-in-line 2.4 release - Weld 2.4.3.Final!

Notable fixes and improvements:

  • Weld now shares proxy classes for built-in beans of the same type (WELD-2344)

  • Fixed usage of Jandex on Tomcat when using unpackWars=false (WELD-2357)

  • Weld now supports wider variety of non-portable extension observer methods (WELD-2338)

  • There is now new debug level logging during bootstrap which allows to monitor name, start, end and duration of all bootstrap phases (WELD-2336)

  • Session replication

    • Built-in session and conversation scoped beans are not part of the bean identifier index anymore (WELD-2343)

    • Handle situation when HTTPSessionBean might not be serializable (WELD-2346)

  • Weld SE

    • You can now easily register new org.jboss.weld.bootstrap.api.Service during container bootstrap (WELD-2360)

    • Any javax.enterprise.inject.spi.CDI method can now be called during AfterDeploymentValidation (WELD-2371)

    • ContainerInitialized event is now correctly fired after registration of shutdown hook (WELD-2340)

    • ContainerInitialized and ContainerShutdown now implement toString() (WELD-2354)

  • Probe development tool

    • Allow monitoring of bean instance creation using AroundConstruct (WELD-2332)

    • Fixed a situation when bean was wrongly marked as unused when injected as parameter (WELD-2342)

See also the release details. Thanks to everyone involved in this release!

WildFly Patch

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