View Javadoc

1   package net.sourceforge.jparam.conversion.creators;
2   
3   import java.util.Arrays;
4   import java.util.HashMap;
5   import java.util.Iterator;
6   import java.util.LinkedList;
7   import java.util.List;
8   import java.util.Map;
9   import java.util.Set;
10  import java.util.TreeMap;
11  
12  import net.sourceforge.jparam.JParamException;
13  import net.sourceforge.jparam.conversion.weights.ScalarConversionWeight;
14  import net.sourceforge.jparam.parser.SimpleLeaf;
15  import net.sourceforge.jparam.parser.TreeNode;
16  import net.sourceforge.jparam.util.MultiMap;
17  
18  public class ObjectCreator {
19  	private static ObjectCreator objectCreator = null;
20  
21  	private Map primitiveTypeMap = new HashMap();
22  
23  	private ObjectCreator() {
24  		primitiveTypeMap.put(Boolean.TYPE, Boolean.class);
25  		primitiveTypeMap.put(Character.TYPE, Character.class);
26  		primitiveTypeMap.put(Byte.TYPE, Byte.class);
27  		primitiveTypeMap.put(Short.TYPE, Short.class);
28  		primitiveTypeMap.put(Integer.TYPE, Integer.class);
29  		primitiveTypeMap.put(Long.TYPE, Long.class);
30  		primitiveTypeMap.put(Float.TYPE, Float.class);
31  		primitiveTypeMap.put(Double.TYPE, Double.class);
32  	}
33  
34  	public boolean isPrimitive(Class c) {
35  		return (c.isPrimitive() || primitiveTypeMap.containsKey(c));
36  	}
37  
38  	public Class getNonPrimitiveClass(Class c) {
39  		if (c.isPrimitive()) {
40  			return (Class) primitiveTypeMap.get(c);
41  		}
42  		return c;
43  	}
44  
45  	public static ObjectCreator getInstance() {
46  		if (objectCreator == null) {
47  			objectCreator = new ObjectCreator();
48  		}
49  		return objectCreator;
50  	}
51  
52  	public Object create(Class bt, TreeNode[] paramNodes)
53  			throws JParamException {
54  		Set availableCreators = CreatorRegistry.getInstance().getCreators(bt);
55  		boolean isArgNull[] = new boolean[paramNodes.length];
56  		for (int i = 0; i < paramNodes.length; i++) {
57  			TreeNode node = paramNodes[i];
58  
59  			if (node instanceof SimpleLeaf) {
60  				Object val = node.getConstructedValue(Object.class);
61  				if (val == null) {
62  					isArgNull[i] = true;
63  				}
64  			}
65  		}
66  
67  		// have a map from the weight to all creators with this weight
68  		// convertion
69  		List possibleCreators = new LinkedList();
70  		for (Iterator iter = availableCreators.iterator(); iter.hasNext();) {
71  			ICreator creator = (ICreator) iter.next();
72  			Class[] expectedParameters = creator.getParameterTypes();
73  
74  			if (expectedParameters.length == paramNodes.length) {
75  				boolean impossible = false;
76  				ScalarConversionWeight[] parametersConversionWeights = new ScalarConversionWeight[paramNodes.length];
77  				for (int i = 0; i < expectedParameters.length; i++) {
78  					ScalarConversionWeight cw = paramNodes[i]
79  							.getConversionWeight(expectedParameters[i]);
80  					if ((!creator.canBeNull(i) && isArgNull[i])
81  							|| (cw
82  									.compareTo(ScalarConversionWeight.CONV_IMPOSSIBLE) == 0)) {
83  						impossible = true;
84  						continue;
85  					}
86  					parametersConversionWeights[i] = cw;
87  				}
88  
89  				if (!impossible) {
90  					possibleCreators.add(new WeightedCreator(creator,
91  							parametersConversionWeights));
92  				}
93  			}
94  		}
95  
96  		if (possibleCreators.size() == 0) {
97  			throw new JParamException("No creator available for type: "
98  					+ bt.getName() + " with parameters: "
99  					+ Arrays.asList(paramNodes));
100 		}
101 
102 		ICreator[] bestCreators = findBest((WeightedCreator[]) possibleCreators
103 				.toArray(new WeightedCreator[possibleCreators.size()]));
104 
105 		if (bestCreators.length > 1) {
106 			throw new JParamException("Ambiguity creating: " + bt.getName()
107 					+ " with parameters: " + Arrays.asList(paramNodes)
108 					+ ", available creators: " + Arrays.asList(bestCreators));
109 		}
110 		ICreator creator = bestCreators[0];
111 		Object[] args = new Object[paramNodes.length];
112 		Class[] creatorParameters = creator.getParameterTypes();
113 		for (int i = 0; i < args.length; i++) {
114 			args[i] = paramNodes[i].getConstructedValue(creatorParameters[i]);
115 		}
116 		return creator.create(args);
117 	}
118 
119 	private ICreator[] findBest(WeightedCreator[] creators) {
120 		MultiMap weightedCreators = new MultiMap(new TreeMap());
121 
122 		Set bestMatches = null;
123 		for (int i = 0; i < creators.length; i++) {
124 			WeightedCreator curCreator = creators[i];
125 
126 			int creatorIsAsGoodAs = 0;
127 			for (int j = 0; j < creators.length; j++) {
128 				if (j == i) {
129 					continue;
130 				}
131 
132 				if (curCreator.isAsGood(creators[j])) {
133 					creatorIsAsGoodAs++;
134 				}
135 			}
136 
137 			weightedCreators.put(new Integer(creatorIsAsGoodAs), curCreator);
138 		}
139 
140 		bestMatches = weightedCreators.get(new Integer(creators.length - 1));
141 		ICreator[] c;
142 
143 		if (bestMatches == null) {
144 			c = new ICreator[creators.length];
145 			for (int i = 0; i < c.length; i++) {
146 				c[i] = creators[i].creator;
147 			}
148 		} else {
149 			boolean areAllAsGood = true;
150 
151 			if (bestMatches.size() > 1) {
152 				for (Iterator i = bestMatches.iterator(); i.hasNext()
153 						&& areAllAsGood;) {
154 					WeightedCreator ic = (WeightedCreator) i.next();
155 					for (Iterator j = bestMatches.iterator(); j.hasNext()
156 							&& areAllAsGood;) {
157 						WeightedCreator jc = (WeightedCreator) j.next();
158 						if (!jc.isAsGood(ic)) {
159 							areAllAsGood = false;
160 						}
161 					}
162 				}
163 			}
164 
165 			if (!areAllAsGood) {
166 				c = new ICreator[bestMatches.size()];
167 				int i = 0;
168 				for (Iterator iter = bestMatches.iterator(); iter.hasNext(); i++) {
169 					WeightedCreator wc = (WeightedCreator) iter.next();
170 					c[i] = wc.creator;
171 				}
172 			} else {
173 				c = new ICreator[1];
174 				c[0] = ((WeightedCreator) bestMatches.iterator().next()).creator;
175 			}
176 		}
177 		return c;
178 	}
179 
180 	public static void clearSingleton() {
181 		objectCreator = null;
182 	}
183 
184 	private class WeightedCreator {
185 		ICreator creator;
186 
187 		ScalarConversionWeight parameterWeights[];
188 
189 		/***
190 		 * @param creator
191 		 * @param parameterWeights
192 		 */
193 		public WeightedCreator(ICreator creator,
194 				ScalarConversionWeight[] parameterWeights) {
195 			super();
196 			this.creator = creator;
197 			this.parameterWeights = parameterWeights;
198 		}
199 
200 		public boolean isAsGood(WeightedCreator other) {
201 			ScalarConversionWeight[] otherParameterWeights = other.parameterWeights;
202 
203 			int better = 0;
204 			int worse = 0;
205 
206 			for (int i = 0; i < parameterWeights.length; i++) {
207 				int comparedWeight = parameterWeights[i]
208 						.compareTo(otherParameterWeights[i]);
209 				if (comparedWeight > 0) {
210 					worse++;
211 				} else if (comparedWeight < 0) {
212 					better++;
213 				}
214 
215 				return better - worse >= 0;
216 			}
217 
218 			return true;
219 		}
220 
221 		public String toString() {
222 			return "Weights: " + Arrays.asList(parameterWeights) + " Creator: "
223 					+ creator;
224 		}
225 	}
226 }