org.unitils.core.util
Class AnnotatedInstanceManager<T,A extends Annotation>

java.lang.Object
  extended by org.unitils.core.util.AnnotatedInstanceManager<T,A>
Type Parameters:
T - Type of the object that is configured by the annotations
A - Type of the annotation that is used for configuring the instance
Direct Known Subclasses:
ApplicationContextManager

public abstract class AnnotatedInstanceManager<T,A extends Annotation>
extends Object

Class for managing and creating instances of a given type. A given annotation controls how a new instance will be created.

Instances will be created if an annotation instance is found that specifies values or if a custom create method is found. Custom create methods are methods that are marked with the annotation and have one of following signatures:

For the second version the found annotation values are passed to the creation method.

Subclass overrides superclass configuration. That is, when a subclass and superclass contain an annotation with values, only the values of the sub-class will be used. Same is true for custom create methods. Methods in subclasses override methods in superclasses.

Lets explain all this with an example:


 ' @MyAnnotation("supervalue")
 ' public class SuperClass {
 '
 '     @MyAnnotation
 '     protected MyType createMyType(List values)
 ' }
 '
 ' @MyAnnotation({"value1", "value2"})
 ' public class MyClass extends SuperClass {
 '
 '}
 
Following steps are performed: there is annotation with 2 values on the sub class. These values override the value of the annotation in the superclass and will be used for creating a new instance. The 2 values are then passed to the createMyType custom create method to create the actual instance.

If no custom create method is found, the default createInstanceForValues(java.lang.Object, java.lang.Class, java.util.List) method is called for creating the instance.

Created instances are cached on the level in the hierarchy that caused the creation of the instance. That is, if a subclass did not contain any annotations with values or any custom create methods, the super class is tried, if an instance for that super class was already created, that instance will be returned. This way, instances are reused as much as possible.

If an instance needs to be recreated (for example because a test made modification to it), it can be removed from the cache by calling invalidateInstance(java.lang.Class...)

Author:
Tim Ducheyne, Filip Neven

Field Summary
protected  Class<A> annotationClass
          The annotation type
protected  Class<T> instanceClass
          The type of the managed instances
protected  Map<Class<?>,T> instances
          All created intances per class
 
Constructor Summary
protected AnnotatedInstanceManager(Class<T> instanceClass, Class<A> annotationClass)
          Creates a manager
 
Method Summary
protected  void afterInstanceCreate(T instance, Object testObject, Class<?> testClass)
          Hook method that can be overriden to perform extra initialization after the instance was created.
protected  T createCustomCreatedInstance(Method customCreateMethod, Object testObject, Class<?> testClass, List<String> annotationValues)
           
protected  T createCustomCreatedInstanceFromCustomCreateMethodResult(Object testObject, Class<?> testClass, Object customCreateMethodResult)
           
protected abstract  T createInstanceForValues(Object testObject, Class<?> testClass, List<String> values)
          Creates an instance for the given values.
protected abstract  List<String> getAnnotationValues(A annotation)
          Gets the values that are specified for the given annotation.
protected  List<String> getAnnotationValues(Class<?> testClass)
          Gets the values of the annotations on the given class.
protected  Method getCustomCreateMethod(Class<?> testClass, boolean searchSuperClasses)
          Gets the custom create methods on the given class.
protected  Class<?> getCustomCreateMethodReturnType()
           
protected  T getInstance(Object testObject)
          Gets an instance for the given test.
protected  T getInstanceImpl(Object testObject, Class<?> testClass)
          Recursive implementation of getInstance(Object).
protected  boolean hasInstance(Object testObject)
          Checks whether getInstance(java.lang.Object) will return an instance.
protected  boolean hasInstanceImpl(Object testObject, Class<?> testClass)
          Recursive implementation of hasInstance(Object).
protected  void invalidateInstance(Class<?>... classes)
          Forces the recreation of the instance the next time that it is requested.
protected  Object invokeCustomCreateMethod(Method customCreateMethod, Object testObject, List<String> annotationValues)
          Creates an instance by calling a custom create method (if there is one).
protected  boolean isCustomCreateMethod(Method method)
          Checks whether the given method is a custom create method.
protected  void registerInstance(Class<?> testClass, T instance)
          Registers an instance for a given class.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

instances

protected Map<Class<?>,T> instances
All created intances per class


instanceClass

protected Class<T> instanceClass
The type of the managed instances


annotationClass

protected Class<A extends Annotation> annotationClass
The annotation type

Constructor Detail

AnnotatedInstanceManager

protected AnnotatedInstanceManager(Class<T> instanceClass,
                                   Class<A> annotationClass)
Creates a manager

Parameters:
instanceClass - The type of the managed instances
annotationClass - The annotation type
Method Detail

getInstance

protected T getInstance(Object testObject)
Gets an instance for the given test. This will first look for values of annotations on the test class and its super classes. If there is a custom create method, that method is then used to create the instance (passing the values). If no create was found, createInstanceForValues(java.lang.Object, java.lang.Class, java.util.List) is called to create the instance.

Parameters:
testObject - The test object, not null
Returns:
The instance, null if not found

registerInstance

protected void registerInstance(Class<?> testClass,
                                T instance)
Registers an instance for a given class. This will cause getInstance(java.lang.Object) to return the given instance if the testObject is of the given test type.

Parameters:
testClass - The test type, not null
instance - The instance, not null

hasInstance

protected boolean hasInstance(Object testObject)
Checks whether getInstance(java.lang.Object) will return an instance. If false is returned, getInstance(java.lang.Object) will return null.

Parameters:
testObject - The test object, not null
Returns:
True if an instance is linked to the given test object

invalidateInstance

protected void invalidateInstance(Class<?>... classes)
Forces the recreation of the instance the next time that it is requested. If classes are given as argument only instances on those class levels will be reset. If no classes are given, all cached instances will be reset.

Parameters:
classes - The classes for which to reset the instances

hasInstanceImpl

protected boolean hasInstanceImpl(Object testObject,
                                  Class<?> testClass)
Recursive implementation of hasInstance(Object).

Parameters:
testObject - The test object, not null
testClass - The level in the hierarchy
Returns:
True if an instance is linked to the given test object

getInstanceImpl

protected T getInstanceImpl(Object testObject,
                            Class<?> testClass)
Recursive implementation of getInstance(Object).

Parameters:
testObject - The test object, not null
testClass - The level in the hierarchy
Returns:
The instance, null if not found

afterInstanceCreate

protected void afterInstanceCreate(T instance,
                                   Object testObject,
                                   Class<?> testClass)
Hook method that can be overriden to perform extra initialization after the instance was created.

Parameters:
instance - The instance, not null
testObject - The test object, not null
testClass - The level in the hierarchy

getAnnotationValues

protected List<String> getAnnotationValues(Class<?> testClass)
Gets the values of the annotations on the given class. This will look for class-level, method-level and field-level annotations with values. If more than 1 such annotation is found, an exception is raised. If no annotation was found, an empty list is returned.

Parameters:
testClass - The test class, not null
Returns:
The values of the annotation, empty list if none found

getCustomCreateMethod

protected Method getCustomCreateMethod(Class<?> testClass,
                                       boolean searchSuperClasses)
Gets the custom create methods on the given class. If there is more than 1 create method found, an exception is raised. If no create method was found, null is returned. If searchSuperClasses is true, it will also look in super classes for create methods.

Parameters:
testClass - The test class, not null
searchSuperClasses - True to look recursively in superclasses
Returns:
The instance, null if no create method was found

isCustomCreateMethod

protected boolean isCustomCreateMethod(Method method)
Checks whether the given method is a custom create method. A custom create method must have following signature:

Parameters:
method - The method, not null
Returns:
True if it has the correct signature

createCustomCreatedInstance

protected T createCustomCreatedInstance(Method customCreateMethod,
                                        Object testObject,
                                        Class<?> testClass,
                                        List<String> annotationValues)

invokeCustomCreateMethod

protected Object invokeCustomCreateMethod(Method customCreateMethod,
                                          Object testObject,
                                          List<String> annotationValues)
Creates an instance by calling a custom create method (if there is one). Such a create method should have one of following exact signatures: The second version receives the given locations. They both should return an instance (not null)

Parameters:
customCreateMethod - The create method, not null
testObject - The test object, not null
annotationValues - The specified locations if there are any, not null
Returns:
The instance, null if no create method was found

createCustomCreatedInstanceFromCustomCreateMethodResult

protected T createCustomCreatedInstanceFromCustomCreateMethodResult(Object testObject,
                                                                    Class<?> testClass,
                                                                    Object customCreateMethodResult)

getCustomCreateMethodReturnType

protected Class<?> getCustomCreateMethodReturnType()
Returns:
The return type of a custom create method. By default, this is the type of the managed instance. Subclasses that override this method are themselves responsible for making sure that the returned object can be used for creating an instance of the managed class.

getAnnotationValues

protected abstract List<String> getAnnotationValues(A annotation)
Gets the values that are specified for the given annotation. An array with 1 empty string should be considered to be empty and null should be returned.

Parameters:
annotation - The annotation, not null
Returns:
The values, null if no values were specified

createInstanceForValues

protected abstract T createInstanceForValues(Object testObject,
                                             Class<?> testClass,
                                             List<String> values)
Creates an instance for the given values.

Parameters:
testObject - TODO
testClass - TODO
values - The values, not null
Returns:
The instance, not null


Copyright © 2011. All Rights Reserved.