service is available. A null object implements the target service interface but doesn't
do anything meaningful.
Null objects and default implementations
Unless you explicitly tell it not to do so, iPOJO injects a null object in place of missing
optional service dependencies. These null objects are created using a trivial mock
object pattern where any method that returns void takes no action, and methods that
return values return the default false , 0 , or null , depending on which is appropriate.
If you're using service proxies (which is the default), this means the service proxies
are injected with null objects if a backing service isn't available. If you aren't using
proxies, then your component is injected with a null object directly. This approach
saves you from having to check for null in your component code. If you don't desire
this behavior, you can disable null object creation like this:
private Foo foo;
If you disable null objects and you're using proxies, your component code must be
prepared to catch runtime exceptions when accessing a proxy object if the backing
service is missing (similar to the unavailable service exceptions in Blueprint and in-
dicative of OSGi service dynamism in general). If you aren't using proxies, you'll
need to check for null service values in your component code. When using proxies,
it's recommended to keep the default behavior of null object creation, because the
whole point of proxies is to try to insulate the component from dynamism, but the
choice is yours.
In the case where you're using null objects without proxies, it's possible for your com-
ponent to determine whether it has a null object using instanceof , because all null
objects implement the Nullable interface.
As a final comment, because a null object is just a default service implementation
that doesn't do anything, iPOJO provides one more wrinkle. You can supply your own
default service implementation instead of the normal null object:
private Foo foo;
When you do this, iPOJO constructs an instance of the DefaultFoo class and injects
it into the proxy or component whenever a real Foo service is unavailable.
The @Requires annotation goes even further with respect to service dynamism. The
i POJO runtime ensures that a given field access always returns the same service instance
from the moment in time a given calling thread enters a component method and uses
a service until it ultimately exits the original entry method. This means that even if the
calling thread somehow calls out to another component and reenters the original com-
ponent, it always sees the same service instances until it exits the original component
once and for all. Essentially, i POJO associates a shadow copy of a component's field after