View Javadoc

1   package net.sf.beanrunner;
2   
3   import java.beans.BeanInfo;
4   import java.beans.Introspector;
5   import java.beans.PropertyDescriptor;
6   import java.io.ByteArrayInputStream;
7   import java.io.ByteArrayOutputStream;
8   import java.io.IOException;
9   import java.io.ObjectInputStream;
10  import java.io.ObjectOutputStream;
11  import java.io.Serializable;
12  import java.lang.reflect.Method;
13  import java.math.BigDecimal;
14  import java.math.BigInteger;
15  import java.util.ArrayList;
16  import java.util.Arrays;
17  import java.util.Collection;
18  import java.util.Collections;
19  import java.util.Date;
20  import java.util.HashMap;
21  import java.util.Iterator;
22  import java.util.List;
23  import java.util.Map;
24  import java.util.Set;
25  
26  import junit.framework.Assert;
27  import net.sf.beanrunner.factory.InstanceFactory;
28  import net.sf.beanrunner.factory.impl.BooleanInstanceFactory;
29  import net.sf.beanrunner.factory.impl.ChainedInstanceFactory;
30  import net.sf.beanrunner.factory.impl.CharInstanceFactory;
31  import net.sf.beanrunner.factory.impl.CollectionInstanceFactory;
32  import net.sf.beanrunner.factory.impl.DateInstanceFactory;
33  import net.sf.beanrunner.factory.impl.MapInstanceFactory;
34  import net.sf.beanrunner.factory.impl.NestedBeanInstanceFactory;
35  import net.sf.beanrunner.factory.impl.NumberInstanceFactory;
36  import net.sf.beanrunner.factory.impl.SingleValueInstanceFactory;
37  import net.sf.beanrunner.factory.impl.StringInstanceFactory;
38  
39  public class BeanRunner {
40  	private Map factoryMap = new HashMap();
41  	private Collection excludedProperties = new ArrayList();
42  
43  	public BeanRunner() {
44  		byte b[] = new byte[20];
45  		Arrays.fill(b, Byte.MAX_VALUE);
46  		BigInteger min = new BigInteger(-1, b);
47  		BigInteger max = new BigInteger(1, b);
48  		NumberInstanceFactory longInstanceFactory = new NumberInstanceFactory(Long.class, new Long(Long.MIN_VALUE), new Long(
49  				Long.MAX_VALUE));
50  		NumberInstanceFactory intInstanceFactory = new NumberInstanceFactory(Integer.class, new Integer(Integer.MIN_VALUE),
51  				new Integer(Integer.MAX_VALUE));
52  
53  		factoryMap.put(Double.TYPE, new NumberInstanceFactory(Double.class, new Double(Double.MIN_VALUE), new Double(
54  				Double.MAX_VALUE)));
55  		factoryMap.put(Double.class, new NumberInstanceFactory(Double.class, new Double(Double.MIN_VALUE), new Double(
56  				Double.MAX_VALUE)));
57  		factoryMap.put(Float.TYPE, new NumberInstanceFactory(Float.class, new Float(Float.MIN_VALUE), new Float(Float.MAX_VALUE)));
58  		factoryMap.put(Float.class, new NumberInstanceFactory(Float.class, new Float(Float.MIN_VALUE), new Float(Float.MAX_VALUE)));
59  		factoryMap.put(Short.TYPE, new NumberInstanceFactory(Short.class, new Short(Short.MIN_VALUE), new Short(Short.MAX_VALUE)));
60  		factoryMap.put(Short.class, new NumberInstanceFactory(Short.class, new Short(Short.MIN_VALUE), new Short(Short.MAX_VALUE)));
61  		factoryMap.put(Byte.TYPE, new NumberInstanceFactory(Byte.class, new Byte(Byte.MIN_VALUE), new Byte(Byte.MAX_VALUE)));
62  		factoryMap.put(Byte.class, new NumberInstanceFactory(Byte.class, new Byte(Byte.MIN_VALUE), new Byte(Byte.MAX_VALUE)));
63  		factoryMap.put(Integer.TYPE, intInstanceFactory);
64  		factoryMap.put(Integer.class, intInstanceFactory);
65  		factoryMap.put(Long.TYPE, longInstanceFactory);
66  		factoryMap.put(Long.class, longInstanceFactory);
67  		factoryMap.put(Boolean.TYPE, new BooleanInstanceFactory());
68  		factoryMap.put(Boolean.class, new BooleanInstanceFactory());
69  		factoryMap.put(Character.TYPE, new CharInstanceFactory());
70  		factoryMap.put(Character.class, new CharInstanceFactory());
71  		factoryMap.put(String.class, new StringInstanceFactory(16000));
72  
73  		factoryMap.put(BigInteger.class, new NumberInstanceFactory(java.math.BigInteger.class, min, max));
74  		factoryMap.put(BigDecimal.class, new NumberInstanceFactory(java.math.BigDecimal.class, new BigDecimal(min), new BigDecimal(
75  				max)));
76  
77  		factoryMap.put(Date.class, new DateInstanceFactory());
78  		factoryMap.put(Collection.class, new CollectionInstanceFactory(Collections.EMPTY_LIST));
79  		factoryMap.put(List.class, new CollectionInstanceFactory(Collections.EMPTY_LIST));
80  		factoryMap.put(Set.class, new CollectionInstanceFactory(Collections.EMPTY_SET));
81  		factoryMap.put(Map.class, new MapInstanceFactory(Collections.EMPTY_MAP));
82  	}
83  
84  	/**
85  	 * Add a new test value for any property of the given type. The types must
86  	 * match exactly. You cannot set a Map.class and expect it to be passed to a
87  	 * property of type HashMap.class.
88  	 * 
89  	 * @param type
90  	 *            the property type
91  	 * @param value
92  	 *            the value to pass
93  	 */
94  	public void addTestValue(Class type, Object value) {
95  		InstanceFactory factory = (InstanceFactory) factoryMap.get(type);
96  		if (factory == null) {
97  			factoryMap.put(type, new SingleValueInstanceFactory(value));
98  
99  		} else {
100 			factoryMap.put(type, new ChainedInstanceFactory(factory, new SingleValueInstanceFactory(value)));
101 		}
102 	}
103 
104 	/**
105 	 * Test the properties that have both getters and setters. Exclude those who
106 	 * have been excluded by {@link #excludeProperty(String)}.
107 	 * 
108 	 * If the object implements Serializable, do a check to ensure it really is.
109 	 * 
110 	 * @param bean
111 	 *            the object to test
112 	 * @throws Exception
113 	 *             on failure
114 	 */
115 	public void testBean(Object bean) throws Exception {
116 		BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
117 		simplePropertiesTest(bean, beanInfo);
118 		if (bean instanceof Serializable) {
119 			testSerializable((Serializable) bean);
120 		}
121 	}
122 
123 	/**
124 	 * Test that the bean can be serialized and deserialized.
125 	 * 
126 	 * @param bean
127 	 *            the object to test
128 	 * @throws IOException
129 	 *             if the object cannot be serialized or deserialized
130 	 * @throws ClassNotFoundException
131 	 *             if the object cannot be deserialized
132 	 */
133 	public void testSerializable(Serializable bean) throws IOException, ClassNotFoundException {
134 		ByteArrayOutputStream baos = new ByteArrayOutputStream();
135 		ObjectOutputStream oos = new ObjectOutputStream(baos);
136 		oos.writeObject(bean);
137 		byte bs[] = baos.toByteArray();
138 		ByteArrayInputStream bais = new ByteArrayInputStream(bs);
139 		ObjectInputStream ois = new ObjectInputStream(bais);
140 		ois.readObject();
141 	}
142 
143 	/**
144 	 * This method will add the name to a list of properties that need to be
145 	 * excluded for the automated testing.
146 	 * 
147 	 * @param propertyName
148 	 *            the name of the property to exclude
149 	 */
150 	public void excludeProperty(String propertyName) {
151 		excludedProperties.add(propertyName);
152 	}
153 
154 	private void simplePropertiesTest(Object bean, BeanInfo beanInfo) throws Exception {
155 		PropertyDescriptor propertyDescriptors[] = beanInfo.getPropertyDescriptors();
156 		for (int i = 0; i < propertyDescriptors.length; i++) {
157 			PropertyDescriptor descriptor = propertyDescriptors[i];
158 			String name = descriptor.getName();
159 			if (excludedProperties.contains(name)) {
160 				continue;
161 			}
162 			Method readMethod = descriptor.getReadMethod();
163 			Method writeMethod = descriptor.getWriteMethod();
164 			if (readMethod != null && writeMethod != null)
165 				simplePropertyTest(bean, descriptor, readMethod, writeMethod);
166 		}
167 
168 	}
169 
170 	private void simplePropertyTest(Object bean, PropertyDescriptor descriptor, Method readMethod, Method writeMethod)
171 			throws Exception {
172 		Class propertyType = descriptor.getPropertyType();
173 		InstanceFactory instances = (InstanceFactory) factoryMap.get(propertyType);
174 		if (instances == null) {
175 			instances = new NestedBeanInstanceFactory(propertyType);
176 		}
177 		Object obj;
178 		Object invoke;
179 		for (Iterator it = instances.iterator(); it.hasNext(); Assert.assertEquals("Property:" + descriptor.getDisplayName(), obj,
180 				invoke)) {
181 			obj = it.next();
182 			writeMethod.invoke(bean, new Object[] { obj });
183 			invoke = readMethod.invoke(bean, new Object[0]);
184 		}
185 
186 	}
187 
188 }