001: // Modified or written by Object Mentor, Inc. for inclusion with FitNesse.
002: // Copyright (c) 2002 Cunningham & Cunningham, Inc.
003: // Released under the terms of the GNU General Public License version 2 or later.
004: package fit;
005:
006: // Copyright (c) 2002 Cunningham & Cunningham, Inc.
007: // Released under the terms of the GNU General Public License version 2 or later.
008:
009: import java.lang.reflect.Array;
010: import java.lang.reflect.Field;
011: import java.lang.reflect.InvocationTargetException;
012: import java.lang.reflect.Method;
013: import java.lang.reflect.Modifier;
014: import java.util.HashMap;
015: import java.util.Map;
016: import java.util.StringTokenizer;
017:
018: public class TypeAdapter {
019: public Object target;
020: public Fixture fixture;
021: public Field field;
022: public Method method;
023: public Class type;
024: private static Map<Class, TypeAdapter> PARSE_DELEGATES = new HashMap<Class, TypeAdapter>();
025:
026: // Factory //////////////////////////////////
027:
028: public static TypeAdapter on(Fixture target, Class type) {
029: TypeAdapter a = adapterFor(type);
030: a.init(target, type);
031: return a;
032: }
033:
034: public static TypeAdapter on(Fixture fixture, Field field) {
035: TypeAdapter a = on(fixture, field.getType());
036: a.target = fixture;
037: a.field = field;
038: return a;
039: }
040:
041: public static TypeAdapter on(Fixture fixture, Method method) {
042: TypeAdapter a = on(fixture, method.getReturnType());
043: a.target = fixture;
044: a.method = method;
045: return a;
046: }
047:
048: public static TypeAdapter adapterFor(Class type)
049: throws UnsupportedOperationException {
050: if (type.isPrimitive()) {
051: if (type.equals(byte.class))
052: return new ByteAdapter();
053: if (type.equals(short.class))
054: return new ShortAdapter();
055: if (type.equals(int.class))
056: return new IntAdapter();
057: if (type.equals(long.class))
058: return new LongAdapter();
059: if (type.equals(float.class))
060: return new FloatAdapter();
061: if (type.equals(double.class))
062: return new DoubleAdapter();
063: if (type.equals(char.class))
064: return new CharAdapter();
065: if (type.equals(boolean.class))
066: return new BooleanAdapter();
067: throw new UnsupportedOperationException("can't yet adapt "
068: + type);
069: } else {
070: Object delegate = PARSE_DELEGATES.get(type);
071: if (delegate instanceof DelegateClassAdapter)
072: return (TypeAdapter) ((DelegateClassAdapter) delegate)
073: .clone();
074: if (delegate instanceof DelegateObjectAdapter)
075: return (TypeAdapter) ((DelegateObjectAdapter) delegate)
076: .clone();
077: if (type.equals(Byte.class))
078: return new ClassByteAdapter();
079: if (type.equals(Short.class))
080: return new ClassShortAdapter();
081: if (type.equals(Integer.class))
082: return new ClassIntegerAdapter();
083: if (type.equals(Long.class))
084: return new ClassLongAdapter();
085: if (type.equals(Float.class))
086: return new ClassFloatAdapter();
087: if (type.equals(Double.class))
088: return new ClassDoubleAdapter();
089: if (type.equals(Character.class))
090: return new ClassCharacterAdapter();
091: if (type.equals(Boolean.class))
092: return new ClassBooleanAdapter();
093: if (type.isArray())
094: return new ArrayAdapter();
095: return new TypeAdapter();
096: }
097: }
098:
099: // Accessors ////////////////////////////////
100:
101: public void init(Fixture fixture, Class type) {
102: this .fixture = fixture;
103: this .type = type;
104: }
105:
106: public Object get() throws IllegalAccessException,
107: InvocationTargetException {
108: if (field != null) {
109: return field.get(target);
110: }
111: if (method != null) {
112: return invoke();
113: }
114: return null;
115: }
116:
117: public void set(Object value) throws Exception {
118: field.set(target, value);
119: }
120:
121: public Object invoke() throws IllegalAccessException,
122: InvocationTargetException {
123: Object params[] = {};
124: return method.invoke(target, params);
125: }
126:
127: public Object parse(String s) throws Exception {
128: return fixture.parse(s, type);
129: }
130:
131: public boolean equals(Object a, Object b) {
132: if (a == null) {
133: return b == null;
134: }
135: return a.equals(b);
136: }
137:
138: public String toString(Object o) {
139: if (o == null) {
140: return "null";
141: } else if (o instanceof String && ((String) o).equals(""))
142: return "blank";
143: else
144: return o.toString();
145: }
146:
147: /**
148: * Registers a delegate, a class that will handle parsing of other types of values.
149: */
150: public static void registerParseDelegate(Class type,
151: Class parseDelegate) {
152: try {
153: PARSE_DELEGATES.put(type, new DelegateClassAdapter(
154: parseDelegate));
155: } catch (Exception ex) {
156: throw new RuntimeException(
157: "Parse delegate class "
158: + parseDelegate.getName()
159: + " does not have a suitable static parse() method.");
160: }
161: }
162:
163: /**
164: * Registers a delegate object that will handle parsing of other types of values.
165: */
166: public static void registerParseDelegate(Class type,
167: Object parseDelegate) {
168: try {
169: PARSE_DELEGATES.put(type, new DelegateObjectAdapter(
170: parseDelegate));
171: } catch (Exception ex) {
172: throw new RuntimeException(
173: "Parse delegate object of class "
174: + parseDelegate.getClass().getName()
175: + " does not have a suitable parse() method.");
176: }
177: }
178:
179: public static void clearDelegatesForNextTest() {
180: PARSE_DELEGATES.clear();
181: }
182:
183: // Subclasses ///////////////////////////////
184:
185: static class ByteAdapter extends ClassByteAdapter {
186: public void set(Object i) throws IllegalAccessException {
187: field.setByte(target, ((Byte) i).byteValue());
188: }
189: }
190:
191: static class ClassByteAdapter extends TypeAdapter {
192: public Object parse(String s) {
193: return new Byte(Byte.parseByte(s));
194: }
195: }
196:
197: static class ShortAdapter extends ClassShortAdapter {
198: public void set(Object i) throws IllegalAccessException {
199: field.setShort(target, ((Short) i).shortValue());
200: }
201: }
202:
203: static class ClassShortAdapter extends TypeAdapter {
204: public Object parse(String s) {
205: return new Short(Short.parseShort(s));
206: }
207: }
208:
209: static class IntAdapter extends ClassIntegerAdapter {
210: public void set(Object i) throws IllegalAccessException {
211: field.setInt(target, ((Integer) i).intValue());
212: }
213: }
214:
215: static class ClassIntegerAdapter extends TypeAdapter {
216: public Object parse(String s) {
217: return new Integer(Integer.parseInt(s));
218: }
219: }
220:
221: static class LongAdapter extends ClassLongAdapter {
222: public void set(Long i) throws IllegalAccessException {
223: field.setLong(target, i.longValue());
224: }
225: }
226:
227: static class ClassLongAdapter extends TypeAdapter {
228: public Object parse(String s) {
229: return new Long(Long.parseLong(s));
230: }
231: }
232:
233: static class FloatAdapter extends ClassFloatAdapter {
234: public void set(Object i) throws IllegalAccessException {
235: field.setFloat(target, ((Number) i).floatValue());
236: }
237:
238: public Object parse(String s) {
239: return new Float(Float.parseFloat(s));
240: }
241: }
242:
243: static class ClassFloatAdapter extends TypeAdapter {
244: public Object parse(String s) {
245: return new Float(Float.parseFloat(s));
246: }
247: }
248:
249: static class DoubleAdapter extends ClassDoubleAdapter {
250: public void set(Object i) throws IllegalAccessException {
251: field.setDouble(target, ((Number) i).doubleValue());
252: }
253:
254: public Object parse(String s) {
255: return new Double(Double.parseDouble(s));
256: }
257: }
258:
259: static class ClassDoubleAdapter extends TypeAdapter {
260: public Object parse(String s) {
261: return new Double(Double.parseDouble(s));
262: }
263: }
264:
265: static class CharAdapter extends ClassCharacterAdapter {
266: public void set(Object i) throws IllegalAccessException {
267: field.setChar(target, ((Character) i).charValue());
268: }
269: }
270:
271: static class ClassCharacterAdapter extends TypeAdapter {
272: public Object parse(String s) {
273: return new Character(s.charAt(0));
274: }
275: }
276:
277: static class BooleanAdapter extends ClassBooleanAdapter {
278: public void set(Object i) throws IllegalAccessException {
279: field.setBoolean(target, ((Boolean) i).booleanValue());
280: }
281: }
282:
283: static class ClassBooleanAdapter extends TypeAdapter {
284: public Object parse(String s) {
285: String ls = s.toLowerCase();
286: if (ls.equals("true"))
287: return new Boolean(true);
288: if (ls.equals("yes"))
289: return new Boolean(true);
290: if (ls.equals("1"))
291: return new Boolean(true);
292: if (ls.equals("y"))
293: return new Boolean(true);
294: if (ls.equals("+"))
295: return new Boolean(true);
296: return new Boolean(false);
297: }
298: }
299:
300: static class ArrayAdapter extends TypeAdapter {
301: Class componentType;
302: TypeAdapter componentAdapter;
303:
304: public void init(Fixture target, Class type) {
305: super .init(target, type);
306: componentType = type.getComponentType();
307: componentAdapter = on(target, componentType);
308: }
309:
310: public Object parse(String s) throws Exception {
311: StringTokenizer t = new StringTokenizer(s, ",");
312: Object array = Array.newInstance(componentType, t
313: .countTokens());
314: for (int i = 0; t.hasMoreTokens(); i++) {
315: Array.set(array, i, componentAdapter.parse(t
316: .nextToken().trim()));
317: }
318: return array;
319: }
320:
321: public String toString(Object o) {
322: if (o == null)
323: return "";
324: int length = Array.getLength(o);
325: StringBuffer b = new StringBuffer(5 * length);
326: for (int i = 0; i < length; i++) {
327: b.append(componentAdapter.toString(Array.get(o, i)));
328: if (i < (length - 1)) {
329: b.append(", ");
330: }
331: }
332: return b.toString();
333: }
334:
335: public boolean equals(Object a, Object b) {
336: int length = Array.getLength(a);
337: if (length != Array.getLength(b))
338: return false;
339: for (int i = 0; i < length; i++) {
340: if (!componentAdapter.equals(Array.get(a, i), Array
341: .get(b, i)))
342: return false;
343: }
344: return true;
345: }
346: }
347:
348: static class DelegateClassAdapter extends TypeAdapter implements
349: Cloneable {
350: private Method parseMethod;
351:
352: public DelegateClassAdapter(Class parseDelegate)
353: throws SecurityException, NoSuchMethodException {
354: this .parseMethod = parseDelegate.getMethod("parse",
355: new Class[] { String.class });
356: int modifiers = parseMethod.getModifiers();
357: if (!Modifier.isStatic(modifiers)
358: || !Modifier.isPublic(modifiers)
359: || parseMethod.getReturnType() == Void.class)
360: throw new NoSuchMethodException();
361: }
362:
363: public Object parse(String s) throws Exception {
364: return parseMethod.invoke(null, new Object[] { s });
365: }
366:
367: protected Object clone() {
368: try {
369: return super .clone();
370: } catch (CloneNotSupportedException e) {
371: return null;
372: }
373: }
374: }
375:
376: static class DelegateObjectAdapter extends TypeAdapter implements
377: Cloneable {
378: private Object delegate;
379: private Method parseMethod;
380:
381: public DelegateObjectAdapter(Object delegate)
382: throws SecurityException, NoSuchMethodException {
383: this .delegate = delegate;
384: this .parseMethod = delegate.getClass().getMethod("parse",
385: new Class[] { String.class });
386: }
387:
388: public Object parse(String s) throws Exception {
389: return parseMethod.invoke(delegate, new Object[] { s });
390: }
391:
392: protected Object clone() {
393: try {
394: return super .clone();
395: } catch (CloneNotSupportedException e) {
396: return null;
397: }
398: }
399: }
400: }
|