Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * Copyright 2010-2011 the original author or authors.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 package org.callbackparams.combine.reflect;
 
 import java.util.Map;
 import java.util.Set;
Factory-class whose main purpose is to create callback-records from reflectively looked-up callback-values factory classes. The default recipe for a callback-values factory is a nested class that has a static array-returning method with the signature 'values()', e.g. a nested enum.

Author(s):
Henrik Kaipe
 
 public abstract class CallbackRecordsFactory {
 
     private static CallbackRecordsFactory instance;

    
Factory method that returns the implementation suitable for the java-version in use. I.e. a pretty simple implementation for JDK-1.4, which basicly only supports a default behaviour, and a more feature-rich implementation for JDK-1.5+, which makes it possible tweak the default behaviour through annotations.
 
     public static CallbackRecordsFactory getInstance() {
         if (null == ) {
             String annotationAwareFactoryClassName =
                     "org.callbackparams.combine.annotation.AnnotationAwareCallbackRecordsFactory";
             try {
                  = (CallbackRecordsFactory)
                         Class.forName(annotationAwareFactoryClassName)
                         .newInstance();
 //                System.out.println("CallbackRecordsFactory with TIGER support");
 
             } catch (UnsupportedClassVersionError detectionOf_JDK1_4) {
                  = new CallbackRecordsFactory() {};
 //                System.out.println("CallbackRecordsFactory for JDK-1.4");
 
             } catch (Exception shouldNeverHappen) {
                 throw new Error(shouldNeverHappen);
             }
         }
         return ;
     }
    
    
Searches the specified class, its super-classes and all implemented interfaces for nested classes that provide callback-values, as defined by isCallbackValuesFactoryClass(java.lang.Class).
 
     protected Set/*Class*/ findCallbackValuesFactoryClasses(Class testClass) {
         if (null == testClass) {
             return new LinkedHashSet();
         }
         final Set factoryClasses =
                 findCallbackValuesFactoryClasses(testClass.getSuperclass());
         
         final Class[] interfaces = testClass.getInterfaces();
         for (int i = 0 ; i < interfaces.length ; ++i) {
             factoryClasses.addAll(
                     findCallbackValuesFactoryClasses(interfaces[i]));
         }
         
         final Class[] nestedClasses = testClass.getDeclaredClasses();
         for (int i = 0 ; i < nestedClasses.length ; ++i) {
             if (isCallbackValuesFactoryClass(nestedClasses[i])) {
                 factoryClasses.add(nestedClasses[i]);
             }
         }
        return factoryClasses;
    }
    
    
The default implementation returns true if the specified class has a static method "values()" that returns an array.
    protected boolean isCallbackValuesFactoryClass(Class factoryProspect) {
        try {
            Method factoryMethod = factoryProspect
                    .getDeclaredMethod("values", (Class[]) null);
            return 0 < (factoryMethod.getModifiers() & .)
                    && factoryMethod.getReturnType().isArray();
            
        } catch (NoSuchMethodException x) {
            return false;
        }
    }

    
    private static Boolean[] booleanValues() {
        return new Boolean[] {..};
    }
    public static Method valuesMethodFor(Class valuesClass)
    throws NoSuchMethodException {
        boolean useBooleanValues =
                boolean.class == valuesClass
                || Boolean.class == valuesClass;
        return (useBooleanValues ? CallbackRecordsFactory.class : valuesClass)
                .getDeclaredMethod(
                        useBooleanValues ? "booleanValues" : "values",
                        (Class[])null);
    }

    
The returned array (supposedly containing callback-values) is determined from the specified class. The default procedure to determine this array is simply to invoke the static method values() and assume it returns an array of callback-values. The reason is that the static values()-method is the method that returns an array of all enum-constants for a java.lang.Enum implementation.
However, it is not necessary that the argument class is an Enum, as long as it has its static values()-method returning an array of callback-values.
    public Combined[] retrieveCombinedArray(Class valuesClass) {
        try {
            Method m = valuesMethodFor(valuesClass);
            if (false == m.isAccessible()) {
                m.setAccessible(true);
            }
            int nbrOfValues = Array.getLength(m.invoke(null, (Object[])null));
            Combined[] combinedValues = new Combined[nbrOfValues];
            for (int i = 0; i < combinedValues.length; ++i) {
                combinedValues[i] = new Combined(mi);
            }
            return combinedValues;
            
        } catch (Exception x) {
            throw new Error(x);
        }
    }

    
The default combine strategy is org.callbackparams.combine.CombineAllPossible2Combinations but any other strategy could be used by overriding this class or by using the @CombineConfig annotation (if using JDK-1.5+).
    public CombineStrategy retrieveCombineStrategy(Class testClass) {
        return new CombineAllPossible2Combinations();
    }

    
This is the method that integration harnesses (such as the CallbackParamsRunner) should use for retrieving their callback-records in a test-developer friendly way.

Parameters:
testClass the test class
Returns:
the collection of combined and ready-to-use callback-records retrieved from testClass
        ValuesCollection vc = new ValuesCollection();
        Map/*Field,Class*/ fieldValues = collectValueInjections(testClass);
        addAsCombinedValues(vcfieldValues);
        Set/*Class*/ consumedValuesFactoryClasses =
                new HashSet(fieldValues.values());
        for (Iterator i = findCallbackValuesFactoryClasses(testClass)
                .iterator() ; i.hasNext() ;) {
            final Class factoryClass = (Classi.next();
            if (false == consumedValuesFactoryClasses.contains(factoryClass)) {
                vc.add(retrieveCombinedArray(factoryClass));
            }
        }
        return retrieveCombineStrategy(testClass).combine(vc);
    }

    
Collects values for the parameterized fields that are to be value-injected. This default implementation returns an empty map but the JDK-1.5+ implementation overrides this and makes sure that @ParameterizedValue annotated fields are value-injected.

Returns:
a map that maps instances of java.lang.reflect.Field to the class, in which to find the values() method that will provide the values for this field
    protected Map/*Field,Class*/ collectValueInjections(Class testClass) {
        return new IdentityHashMap();
    }

    
Decides on whether the specified value is also available as callback when it is injected to the specified field. This defualt implementation always returns true. The default behaviour can be overridden by overriding this class or by using the annotation-attribute org.callbackparams.annotation.ValueField#alsoAvailableAsCallback() (when using JDK -1.5+).

Returns:
true if the specified value is supposed to be available as callback when value-injected to the specified field; otherwise false
    protected boolean isValueAlsoAvailableAsCallback(Field f) {
        return boolean.class != f.getType() && Boolean.class != f.getType();
    }
    private void addAsCombinedValues(
            ValuesCollection vcMap/*Field,Class*/ fieldValues) {
        for (Iterator/*Map.Entry*/ iter = fieldValues.entrySet().iterator();
                iter.hasNext();) {
            Map.Entry/*Field,Class*/ entry = (Map.Entryiter.next();
            final Field f = (Fieldentry.getKey();
            final Combined[] combinedArray =
                    retrieveCombinedArray((Class)entry.getValue());
            for (int i = 0; i < combinedArray.length; ++i) {
                combinedArray[i].toBeInjected(
                        fisValueAlsoAvailableAsCallback(f));
            }
            vc.add(combinedArray);
        }
    }

    
Utility method that is used by subclasses and the JUnit-3.x utilities.
    public static Combined[] asCombinedArray(Object record) {
        Combined[] combinedArray = new Combined[sizeOfRecord(record)];
        Iterator iRecord = iterateRecordElements(record);
        for (int i = 0; i < combinedArray.length; ++i) {
            final Object nextRecordElement = iRecord.next();
            combinedArray[i] = nextRecordElement instanceof Combined
                    ? (Combined)nextRecordElement
                    : new Combined(nextRecordElement);
        }
        return combinedArray;
    }
    private static Iterator iterateRecordElements(Object record) {
        if (record instanceof Object[]) {
            record = Arrays.asList((Object[])record);
        }
        return ((Collection)record).iterator();
    }
    private static int sizeOfRecord(Object record) {
        if (record instanceof Object[]) {
            return ((Object[])record).length;
        } else {
            return ((Collection)record).size();
        }
    }
New to GrepCode? Check out our FAQ X