View Javadoc

1   package net.sf.twip.parameterhandler;
2   
3   import java.lang.reflect.*;
4   import java.util.*;
5   
6   import net.sf.twip.*;
7   import net.sf.twip.internal.*;
8   import net.sf.twip.util.Parameter;
9   
10  /**
11   * Produces all the values to call for one {@link Parameter}, including only those that match the
12   * {@link Assume} or {@link NotNull} annotations.
13   * 
14   * @see AbstractNumberParameterHandler for the expessions allowed for numbers
15   */
16  public abstract class ParameterHandler {
17  
18  	public static ParameterHandler of(Parameter parameter) {
19  		final Class<?> type = parameter.getType();
20  		if (type.isEnum()) {
21  			return new EnumParameterHandler(parameter);
22  		} else if (Boolean.class.isAssignableFrom(type) || Boolean.TYPE.equals(type)) {
23  			return new BooleanParameterHandler(parameter);
24  		} else if (Byte.class.isAssignableFrom(type) || Byte.TYPE.equals(type)) {
25  			return new ByteParameterHandler(parameter);
26  		} else if (Character.class.isAssignableFrom(type) || Character.TYPE.equals(type)) {
27  			return new CharacterParameterHandler(parameter);
28  		} else if (Double.class.isAssignableFrom(type) || Double.TYPE.equals(type)) {
29  			return new DoubleParameterHandler(parameter);
30  		} else if (Float.class.isAssignableFrom(type) || Float.TYPE.equals(type)) {
31  			return new FloatParameterHandler(parameter);
32  		} else if (Integer.class.isAssignableFrom(type) || Integer.TYPE.equals(type)) {
33  			return new IntegerParameterHandler(parameter);
34  		} else if (Long.class.isAssignableFrom(type) || Long.TYPE.equals(type)) {
35  			return new LongParameterHandler(parameter);
36  		} else if (Short.class.isAssignableFrom(type) || Short.TYPE.equals(type)) {
37  			return new ShortParameterHandler(parameter);
38  		} else if (String.class.isAssignableFrom(type)) {
39  			return new StringParameterHandler(parameter);
40  		} else {
41  			return new AutoTwipParameterHandler(parameter);
42  		}
43  	}
44  
45  	protected final Parameter parameter;
46  
47  	public ParameterHandler(Parameter parameter) {
48  		this.parameter = parameter;
49  	}
50  
51  	/**
52  	 * Get the values from the method or field specified in the {@link Values} annotation... with a
53  	 * lot of collecting useful error information.
54  	 */
55  	private Object[] getAnnotatedValues() {
56  		final String name = parameter.getAnnotation(Values.class).value();
57  		try {
58  			final Field field = parameter.getMethod().getDeclaringClass().getField(name);
59  			if (!Modifier.isStatic(field.getModifiers()))
60  				throw new TwipConfigurationErrorNonStatic("the field '" + name
61  						+ "' named in the @Values annotation of " + parameter + " must be static.");
62  			if (field.getType().isArray()) {
63  				if (field.getType().getComponentType().isPrimitive())
64  					throw new TwipConfigurationErrorNonPrimitive("the values of the field '" + name
65  							+ "' named in the @Values annotation of " + parameter
66  							+ " must not be primitives.");
67  				final Object[] result = (Object[]) field.get(null);
68  				if (result == null)
69  					throw new TwipConfigurationErrorNullPointer("the field '" + name
70  							+ "' named in the @Values annotation of " + parameter + " is null");
71  				return result;
72  			} else if (Collection.class.isAssignableFrom(field.getType())) {
73  				final Collection<?> result = (Collection<?>) field.get(null);
74  				if (result == null)
75  					throw new TwipConfigurationErrorNullPointer("the field '" + name
76  							+ "' named in the @Values annotation of " + parameter + " is null");
77  				return result.toArray();
78  			} else {
79  				throw new TwipConfigurationErrorNotArrayOrCollection("the field '" + name
80  						+ "' named in the @Values annotation of " + parameter
81  						+ " must be an array or collection.");
82  			}
83  		} catch (final IllegalAccessException e) {
84  			throw new TwipConfigurationErrorGettingField("can't access field '" + name
85  					+ "' named in the @Values annotation of " + parameter, e);
86  		} catch (final NoSuchFieldException ex) {
87  			try {
88  				final Method method = parameter.getMethod().getDeclaringClass().getMethod(name);
89  				if (!Modifier.isStatic(method.getModifiers()))
90  					throw new TwipConfigurationErrorNonStatic("the method '" + name
91  							+ "' named in the @Values annotation of " + parameter
92  							+ " must be static.");
93  				if (method.getReturnType().isArray()) {
94  					if (method.getReturnType().getComponentType().isPrimitive())
95  						throw new TwipConfigurationErrorNonPrimitive(
96  								"the values returned by the method '" + name
97  										+ "' named in the @Values annotation of " + parameter
98  										+ " must not be primitives.");
99  					final Object[] result = (Object[]) method.invoke(null);
100 					if (result == null)
101 						throw new TwipConfigurationErrorNullPointer("the method '" + name
102 								+ "' named in the @Values annotation of " + parameter
103 								+ " returns null");
104 					return result;
105 				} else if (Collection.class.isAssignableFrom(method.getReturnType())) {
106 					final Collection<?> collection = (Collection<?>) method.invoke(null);
107 					if (collection == null)
108 						throw new TwipConfigurationErrorNullPointer("the method '" + name
109 								+ "' named in the @Values annotation of " + parameter
110 								+ " returns null.");
111 					return collection.toArray();
112 				} else {
113 					throw new TwipConfigurationErrorNotArrayOrCollection("the method '" + name
114 							+ "' named in the @Values annotation of " + parameter
115 							+ " must return an array or collection.");
116 				}
117 			} catch (final IllegalAccessException e) {
118 				throw new TwipConfigurationErrorCallingMethod("can't access the method '" + name
119 						+ "' named in the @Values annotation of " + parameter, e);
120 			} catch (final NoSuchMethodException e) {
121 				throw new TwipConfigurationErrorNoSuchMethod("there is no method or field '" + name
122 						+ "' named in the @Values annotation of " + parameter, e);
123 			} catch (final InvocationTargetException e) {
124 				throw new TwipConfigurationErrorCallingMethod("can't invoke method '" + name
125 						+ "' named in the @Values annotation of " + parameter, e);
126 			}
127 		}
128 	}
129 
130 	protected abstract Object[] getDefaultParameterValues();
131 
132 	public Object[] getParameterValues() {
133 		final Object[] values = (parameter.isAnnotationPresent(Values.class)) ? getAnnotatedValues()
134 				: getDefaultParameterValues();
135 		if (!parameter.isAnnotationPresent(Assume.class))
136 			return values;
137 		final List<Object> result = new ArrayList<Object>();
138 		for (final Object value : values) {
139 			if (test(value)) {
140 				result.add(value);
141 			}
142 		}
143 		if (!parameter.isAnnotationPresent(NotNull.class) && !parameter.getType().isPrimitive()) {
144 			result.add(null);
145 		}
146 		return result.toArray();
147 	}
148 
149 	/**
150 	 * Should this value go into the parameter values?
151 	 * 
152 	 * @param value
153 	 *            the value to check
154 	 */
155 	protected boolean test(Object value) {
156 		return true;
157 	}
158 }