Evaluating Software Design Patterns
— the "Gang of Four" patterns implemented in Java 6

dk.rode.thesis.singleton
Annotation Type Singleton


@Documented
@Retention(value=RUNTIME)
@Target(value=TYPE)
public @interface Singleton

A singleton annotation identifies a given type already at compile-time as a singleton by identifying the static method returning an instance of the annotated type. The method can either accept no arguments, or a fixed number of java.lang.String arguments.

The method is known as the singleton method. By default, a method name of getInstance is assumed, corresponding to the static method Foo getInstance() in the Foo class.

Any type declared as a Singleton can be utilised in a stateless singleton registry.

Implementation notes:
An annotation is preferred over an interface, because different singleton objects offer no common functionality except for conceptual behaviour in form of only a single instance available. The singleton method must in any case be static, and interfaces cannot declare static methods. An annotation also allows for different method names for different types.

Furthermore, neither an annotation or an interface can guarantee that the implementing class does not disclose an accessible constructor. However, by using annotations, Sun's Annotation Processing Tool (APT) could be primed with a handler to enforce that all found annotated types do not expose accessible constructors, and check the existence of the specified singleton method, already at compile time.

A consequence of not using an interface is that singleton registries cannot impose direct bounds on the type parameters used, for example <T extends Singleton> for a given Singleton interface. However, the SingletonRegistry still allows for such parameterisation by specifying an appropriate type parameter.

A general parameterised singleton method - corresponding to a parameterised Factory Method - is not practically feasible using this annotation without involving a lot of String parsing; that is, using an argument to determine the actual singleton instance to fetch of any type. Hence, we only allow no arguments or a fixed number of String arguments here. However, the idea to use reflection to access the singleton method could easily be extended to allow for more complex protocols as Java's reflection mechanism can mimic all normal method (and constructor) invocation scenarios. It could also be extended so any type could be a singleton type, but that would require a registry keeping taps on created instances and would only work if all access to acquire/create instances were via the registry. A scenario were this could work could be an Abstract Factory that internally uses such a registry.

The annotation is not inherited, because there is no way a given class can tell if a sub-class will be implemented as a singleton as well. Even so, the sub-class could decide to use a different singleton method.

An alternative to letting the annotation specify the method name could be to use an annotation as a marker on the method to use. A visitor of some sorts would then be required to traverse the methods declared in a given type to find the (first) one with the marker annotation that fits the profile of a static method returning a proper singleton type. This roughly corresponds to the idea behind the Executor annotation, which is used in the Observer pattern (see the ObserverManager class). Here, however, annotation of the singleton type itself is the logical design choice.

Author:
Gunni Rode / rode.dk

Optional Element Summary
 String[] arguments
          Returns the fixed java.lang.String arguments to supply each time the singleton method identified by value() is invoked, if any.
 String value
          The name of the singleton method to access the singleton instance.
 

arguments

public abstract String[] arguments
Returns the fixed java.lang.String arguments to supply each time the singleton method identified by value() is invoked, if any.

The singleton method used must formally declare the same number of parameters of type java.lang.String.

Returns:
The fixed string arguments; default empty array (no-argument method).
Default:
{}

value

public abstract String value
The name of the singleton method to access the singleton instance.

The method name must represent a static method returning an instance of the annotated type. The name must not include parentheses. The method can either be a no-argument method, or a method accepting a fixed number of java.lang.String arguments.

Argument values are fixed and specified by arguments().

Returns:
The method name, excluding parenthesis; default getInstance (accepting no arguments).
Default:
"getInstance"

Gunni Rode / rode.dk

Feel free to use and/or modify the Java 6 source code developed for this thesis AT YOUR OWN RISK, but note that the source code comes WITHOUT ANY — and I do mean WITHOUT ANY — form of warranty WHAT SO EVER!

The original thesis and source code are available at rode.dk/thesis.