WeldContainer and SeContainer

2.3k views Asked by At

What is the difference between using:

WeldContainer se = new Weld().initialize();

or

SeContainer se = SeContainerInitializer.newInstance().initialize();

I just want to use @Injection and @Produce annotations, but I have not found the difference between these two ways of initializing an object instance.

2

There are 2 answers

0
Slaw On BEST ANSWER

Context and Dependency Injection (CDI) is a specification. That means it defines an API only and does not provide an implementation. That's why you have to include an implementation such as Weld in order to actually use the API. The WeldContainer class is vendor-specific whereas the SeContainer interface is part of the specification. The former implements the latter.

The SeContainerInitializer class, which is part of the API, will delegate to the implementation included with the application. So if you use Weld as the implementation then ultimately using SeContainerInitializer and SeContainer is the same as using Weld and WeldContainer "under the hood".

From a purist's perspective it's best to rely only on the specification's interface and never directly depend on the implementation. That way you can swap vendors if and when you need to since you're using functionality common to all implementations. However, often times an implementation provides more functionality than what's required by the specification. In order to use that functionality you have to directly depend on the implementation.

In other words, whether you use Weld / WeldContainer or SeContainerInitialializer / SeContainer depends on the (current and future) requirements of your application. When in doubt, program to the interface.

Note this separation between the API and implementation is not unique to CDI. Pretty much the entire Java EE—or as it's now known, Jakarta EE—API works this way. An example would be the Java Persistence API (JPA) and Hibernate or EclipseLink (two implementations). For an example within Java SE there's the Java Database Connectivity (JDBC) API and the various implementations (i.e. drivers).

0
zforgo On

Using SeContainerInitializer it will load an instance by ServiceLoader.load(...) and initialize it.

public static SeContainerInitializer newInstance() {
    return findSeContainerInitializer();
}

private static SeContainerInitializer findSeContainerInitializer() {

    SeContainerInitializer result;
    Iterator<SeContainerInitializer> iterator = ServiceLoader.load(SeContainerInitializer.class, SeContainerInitializer.class.getClassLoader()).iterator();

    if (!iterator.hasNext()) {
        throw new IllegalStateException("No valid CDI implementation found");
    }
    try {
        result = iterator.next();
    } catch (ServiceConfigurationError e) {
        throw new IllegalStateException("Error while instantiating SeContainerInitializer", e);
    }
    if (iterator.hasNext())
        throw new IllegalStateException("Two or more CDI implementations found, only one is supported");
    return result;
}

Weld is one implementation of SeContainerInitializer so if it exists on the classpath SeContainerInitializer.newInstance() method will create a new Weld instance and call initialize() method on this object.

Some hints which is a good choice

SeContainerInitializer.newInstance() is a factory method. If you want to create a vendor-independent application it would be good. But Weld is the reference implementation of CDI specification. Honestly I don't think choosing another implementation is necessary.

new Weld().initialize() will create a WeldContainer (which is an implementation of SeContainer). Using this method you will get a vendor-lock but you can use a lot of useful extra features (e.g. add alternatives or interceptors programmatically). My opinion is: In this case vendor-lock doesn't matter anithing.

Conclusion

If you're planning to change CDI implementation anything else than Weld use independent SeContainerInitializer.newInstance() otherwise just create a Weld instance. If I were you I would use new Weld() way.