Inject null in Java EE

Yassin Hajaj
Aug 19 · 3 min read
Injecting air is as dangerous for your app that it is for your body. Make it safer!

Introduction

It’s been years since Contexts and Dependency Injection (CDI) exist on the Java EE platform.

It simplifies dependency injection and gives it a wider definition than the only injection of EJBs.

One of the problems: it fails at runtime when a dependency can’t be resolved.

Let’s discover one way to inject optional values in Java EE.

Instance

The Instance class is part of the original JSR 299: Contexts and Dependency Injection for the JavaTM EE platform.

The class contains interesting methods to work with injected instances. Let’s first focus on how to inject an optional value on the Java EE platform.

Interface

Let’s call it OptionalInjectable and give a simple mission: return the name of the implementation :

public interface OptionalInjectable {
String implementationName();
}

Injecting Class

Now let’s write the class injecting an instance of OptionalInjectable :

@Path("/service")
public class SimpleAPI {
@Inject
OptionalInjectable optionalInjectable;
@GET
public String action() {
return optionalInjectable.implementationName();
}
}

Run It!

Now let’s run it and see what it does.

Well, as expected, the CDI container can’t match the injected interface to one of its instances and complaints about it during start time :

javax.enterprise.inject.UnsatisfiedResolutionException: Api type [be.yh.tomeeoptionaldi.OptionalInjectable] is not found with the qualifiers
Qualifiers: [@javax.enterprise.inject.Default()]

Using Instance.java

@Path("/service")
public class SimpleAPI {
@Inject
Instance<OptionalInjectable> optionalInjectableInstance;
@GET
public String action() {
boolean unsatisfied = optionalInjectableInstance.isUnsatisfied();
if (!unsatisfied) {
return optionalInjectableInstance.get().implementationName();
}
return "No implementation found !";
}
}
  1. We used Instance in the declaration of the injection point
  2. We check its presence using Instance#isUnsatisfied
  3. We retrieve the instance using Instance#get

This solution works! That’s a good start, but is it the most optimal way?

Wrap it in an Optional

Let’s create a class handling the Instance<T> to make them Optional<T> instances :

public class InstanceOptional {    private InstanceOptional() {
}
public static <T> Optional<T> of(Instance<T> instance) {
return Optional.ofNullable(instance)
.filter(InstanceOptional::isSatisfied)
.map(Instance::get);
}
private static boolean isSatisfied(Instance instance) {
return !instance.isUnsatisfied();
}
}

Put this class somewhere between your util classes and let’s use it in the JAX-RS service written earlier :

@Path("/service")
public class SimpleAPI {
@Inject
Instance<OptionalInjectable> optionalInjectableInstance;
@GET
public String action() {
return InstanceOptional.of(optionalInjectableInstance)
.map(OptionalInjectable::implementationName)
.orElse("No implementation found !");
}
}

We now have a method which is far more readable, using fluent method chaining and increasing expressiveness.

Multiple Injected Instances

Now let’s say, we have multiple instances for the same interface, with the same qualifiers. From there, we want a simple concatenation of their implementation names.

We could, of course, define multiple injection points :

@Inject
@FirstImpl
Instance<OptionalInjectable> firstInstance;
@Inject
@SecondImpl
Instance<OptionalInjectable> secondInstance;

And then stream over it :

Stream.of(firstInstance, secondInstance)
.map(InstanceOptional::of)
// ...

But it feels wrong, right? It’s not future proof and will force us to add the new implementation each time a new one is added.

The API comes with a solution out-of-the-box for these cases. As it extends Iterable<T> , it is possible to iterate over all resolved possible injectable instances :

@GET
@Path("/two")
public String action2() {
return StreamSupport.stream(optionalInjectableInstance.spliterator(), false)
.map(OptionalInjectable::implementationName)
.collect(joining("\n"));
}

This will give us a concatenation of all the implementation names present in the application.

NOTE: If you have multiple implementations and you try the first method, it will fail and print that the injection is ambiguous. For this use Instance#isAmbiguous and you’re good to go. Or use this last one with the Stream API.

Searching for a Specific Instance

When having multiple implementations of an interface, you also usually use CDI identifiers to be able to make the difference.

Let’s see how to search for a specific implementation, without having to inject them all one by one.

Annotation Instance

You’ll have to get an instance of the annotation first. One way of doing it is :

Second second = new Second() {
@Override
public Class<? extends Annotation> annotationType() {
return Second.class;
}
};

Instance#select(Annotation annotation)

Let’s now use this method to get the instance we want :

optionalInjectableInstance.select(second)

If we wrap it into the InstanceOptional<T> created earlier we get the following result :

@GET
@Path("/three")
public String action3() {
// ... get the annnotation instance
return InstanceOptional.of(instance.select(second))
.map(OptionalInjectable::implementationName)
.orElse("No Implementation Found !");
}

Conclusion

We’ve seen in this article multiple ways to inject instances in a more flexible way than the standard one.

We’ve seen how powerful Instance can be but also its limitations, but how to extend its capabilities.

Yassin Hajaj

Written by

I’m a developer who has a thing for artificial intelligence !

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade