Java Reference
In-Depth Information
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:
@Requires(nullable=false)
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:
@Requires(default-implementation=org.foo.DefaultFoo)
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