1 | |
package org.apache.commons.ognl; |
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
|
15 | |
|
16 | |
|
17 | |
|
18 | |
|
19 | |
|
20 | |
|
21 | |
|
22 | |
import org.apache.commons.ognl.enhance.ExpressionCompiler; |
23 | |
|
24 | |
import java.lang.reflect.Array; |
25 | |
import java.lang.reflect.Constructor; |
26 | |
import java.util.List; |
27 | |
|
28 | |
|
29 | |
|
30 | |
|
31 | |
|
32 | |
|
33 | |
public class ASTCtor |
34 | |
extends SimpleNode |
35 | |
{ |
36 | |
|
37 | |
private String className; |
38 | |
|
39 | |
private boolean isArray; |
40 | |
|
41 | |
public ASTCtor( int id ) |
42 | |
{ |
43 | 96 | super( id ); |
44 | 96 | } |
45 | |
|
46 | |
public ASTCtor( OgnlParser p, int id ) |
47 | |
{ |
48 | 0 | super( p, id ); |
49 | 0 | } |
50 | |
|
51 | |
|
52 | |
void setClassName( String className ) |
53 | |
{ |
54 | 96 | this.className = className; |
55 | 96 | } |
56 | |
|
57 | |
|
58 | |
|
59 | |
|
60 | |
|
61 | |
|
62 | |
|
63 | |
String getClassName() |
64 | |
{ |
65 | 0 | return className; |
66 | |
} |
67 | |
|
68 | |
|
69 | |
void setArray( boolean value ) |
70 | |
{ |
71 | 53 | isArray = value; |
72 | 53 | } |
73 | |
|
74 | |
public boolean isArray() |
75 | |
{ |
76 | 20 | return isArray; |
77 | |
} |
78 | |
|
79 | |
protected Object getValueBody( OgnlContext context, Object source ) |
80 | |
throws OgnlException |
81 | |
{ |
82 | 111 | Object result, root = context.getRoot(); |
83 | 111 | int count = jjtGetNumChildren(); |
84 | 111 | Object[] args = OgnlRuntime.getObjectArrayPool().create( count ); |
85 | |
|
86 | |
try |
87 | |
{ |
88 | 254 | for ( int i = 0; i < count; ++i ) |
89 | |
{ |
90 | 143 | args[i] = children[i].getValue( context, root ); |
91 | |
} |
92 | 111 | if ( isArray ) |
93 | |
{ |
94 | 33 | if ( args.length == 1 ) |
95 | |
{ |
96 | |
try |
97 | |
{ |
98 | 33 | Class componentClass = OgnlRuntime.classForName( context, className ); |
99 | 33 | List sourceList = null; |
100 | |
int size; |
101 | |
|
102 | 33 | if ( args[0] instanceof List ) |
103 | |
{ |
104 | 20 | sourceList = (List) args[0]; |
105 | 20 | size = sourceList.size(); |
106 | |
} |
107 | |
else |
108 | |
{ |
109 | 13 | size = (int) OgnlOps.longValue( args[0] ); |
110 | |
} |
111 | 33 | result = Array.newInstance( componentClass, size ); |
112 | 33 | if ( sourceList != null ) |
113 | |
{ |
114 | 20 | TypeConverter converter = context.getTypeConverter(); |
115 | |
|
116 | 62 | for ( int i = 0, icount = sourceList.size(); i < icount; i++ ) |
117 | |
{ |
118 | 42 | Object o = sourceList.get( i ); |
119 | |
|
120 | 42 | if ( ( o == null ) || componentClass.isInstance( o ) ) |
121 | |
{ |
122 | 17 | Array.set( result, i, o ); |
123 | |
} |
124 | |
else |
125 | |
{ |
126 | 25 | Array.set( result, i, |
127 | |
converter.convertValue( context, null, null, null, o, componentClass ) ); |
128 | |
} |
129 | |
} |
130 | |
} |
131 | |
} |
132 | 0 | catch ( ClassNotFoundException ex ) |
133 | |
{ |
134 | 0 | throw new OgnlException( "array component class '" + className + "' not found", ex ); |
135 | 33 | } |
136 | |
} |
137 | |
else |
138 | |
{ |
139 | 0 | throw new OgnlException( "only expect array size or fixed initializer list" ); |
140 | |
} |
141 | |
} |
142 | |
else |
143 | |
{ |
144 | 78 | result = OgnlRuntime.callConstructor( context, className, args ); |
145 | |
} |
146 | |
|
147 | 111 | return result; |
148 | |
} |
149 | |
finally |
150 | |
{ |
151 | 111 | OgnlRuntime.getObjectArrayPool().recycle( args ); |
152 | |
} |
153 | |
} |
154 | |
|
155 | |
|
156 | |
public String toGetSourceString( OgnlContext context, Object target ) |
157 | |
{ |
158 | 53 | String result = "new " + className; |
159 | |
|
160 | 53 | Class clazz = null; |
161 | 53 | Object ctorValue = null; |
162 | |
try |
163 | |
{ |
164 | |
|
165 | 53 | clazz = OgnlRuntime.classForName( context, className ); |
166 | |
|
167 | 53 | ctorValue = this.getValueBody( context, target ); |
168 | 53 | context.setCurrentObject( ctorValue ); |
169 | |
|
170 | 53 | if ( clazz != null && ctorValue != null ) |
171 | |
{ |
172 | |
|
173 | 53 | context.setCurrentType( ctorValue.getClass() ); |
174 | 53 | context.setCurrentAccessor( ctorValue.getClass() ); |
175 | |
} |
176 | |
|
177 | 53 | if ( isArray ) |
178 | |
{ |
179 | 26 | context.put( "_ctorClass", clazz ); |
180 | |
} |
181 | |
} |
182 | 0 | catch ( Throwable t ) |
183 | |
{ |
184 | 0 | throw OgnlOps.castToRuntime( t ); |
185 | 53 | } |
186 | |
|
187 | |
try |
188 | |
{ |
189 | |
|
190 | 53 | if ( isArray ) |
191 | |
{ |
192 | 26 | if ( children[0] instanceof ASTConst ) |
193 | |
{ |
194 | |
|
195 | 7 | result = result + "[" + children[0].toGetSourceString( context, target ) + "]"; |
196 | |
} |
197 | 19 | else if ( ASTProperty.class.isInstance( children[0] ) ) |
198 | |
{ |
199 | |
|
200 | 1 | result = |
201 | |
result + "[" + ExpressionCompiler.getRootExpression( children[0], target, context ) |
202 | |
+ children[0].toGetSourceString( context, target ) + "]"; |
203 | |
} |
204 | 18 | else if ( ASTChain.class.isInstance( children[0] ) ) |
205 | |
{ |
206 | |
|
207 | 1 | result = result + "[" + children[0].toGetSourceString( context, target ) + "]"; |
208 | |
} |
209 | |
else |
210 | |
{ |
211 | |
|
212 | 17 | result = result + "[] " + children[0].toGetSourceString( context, target ); |
213 | |
} |
214 | |
|
215 | |
} |
216 | |
else |
217 | |
{ |
218 | 27 | result = result + "("; |
219 | |
|
220 | 27 | if ( ( children != null ) && ( children.length > 0 ) ) |
221 | |
{ |
222 | |
|
223 | 21 | Object[] values = new Object[children.length]; |
224 | 21 | String[] expressions = new String[children.length]; |
225 | 21 | Class[] types = new Class[children.length]; |
226 | |
|
227 | |
|
228 | |
|
229 | 58 | for ( int i = 0; i < children.length; i++ ) |
230 | |
{ |
231 | |
|
232 | 37 | Object objValue = children[i].getValue( context, context.getRoot() ); |
233 | 37 | String value = children[i].toGetSourceString( context, target ); |
234 | |
|
235 | 37 | if ( !ASTRootVarRef.class.isInstance( children[i] ) ) |
236 | |
{ |
237 | 36 | value = ExpressionCompiler.getRootExpression( children[i], target, context ) + value; |
238 | |
} |
239 | |
|
240 | 37 | String cast = ""; |
241 | 37 | if ( ExpressionCompiler.shouldCast( children[i] ) ) |
242 | |
{ |
243 | |
|
244 | 13 | cast = (String) context.remove( ExpressionCompiler.PRE_CAST ); |
245 | |
} |
246 | 37 | if ( cast == null ) |
247 | |
{ |
248 | 12 | cast = ""; |
249 | |
} |
250 | |
|
251 | 37 | if ( !ASTConst.class.isInstance( children[i] ) ) |
252 | |
{ |
253 | 13 | value = cast + value; |
254 | |
} |
255 | |
|
256 | 37 | values[i] = objValue; |
257 | 37 | expressions[i] = value; |
258 | 37 | types[i] = context.getCurrentType(); |
259 | |
} |
260 | |
|
261 | |
|
262 | |
|
263 | 21 | Constructor[] cons = clazz.getConstructors(); |
264 | 21 | Constructor ctor = null; |
265 | 21 | Class[] ctorParamTypes = null; |
266 | |
|
267 | 75 | for ( int i = 0; i < cons.length; i++ ) |
268 | |
{ |
269 | 54 | Class[] ctorTypes = cons[i].getParameterTypes(); |
270 | |
|
271 | 54 | if ( OgnlRuntime.areArgsCompatible( values, ctorTypes ) |
272 | |
&& ( ctor == null || OgnlRuntime.isMoreSpecific( ctorTypes, ctorParamTypes ) ) ) |
273 | |
{ |
274 | 21 | ctor = cons[i]; |
275 | 21 | ctorParamTypes = ctorTypes; |
276 | |
} |
277 | |
} |
278 | |
|
279 | 21 | if ( ctor == null ) |
280 | |
{ |
281 | 0 | ctor = |
282 | |
OgnlRuntime.getConvertedConstructorAndArgs( context, clazz, |
283 | |
OgnlRuntime.getConstructors( clazz ), values, |
284 | |
new Object[values.length] ); |
285 | |
} |
286 | |
|
287 | 21 | if ( ctor == null ) |
288 | |
{ |
289 | 0 | throw new NoSuchMethodException( |
290 | |
"Unable to find constructor appropriate for arguments in class: " + clazz ); |
291 | |
} |
292 | 21 | ctorParamTypes = ctor.getParameterTypes(); |
293 | |
|
294 | |
|
295 | |
|
296 | 58 | for ( int i = 0; i < children.length; i++ ) |
297 | |
{ |
298 | 37 | if ( i > 0 ) |
299 | |
{ |
300 | 16 | result = result + ", "; |
301 | |
} |
302 | |
|
303 | 37 | String value = expressions[i]; |
304 | |
|
305 | 37 | if ( types[i].isPrimitive() ) |
306 | |
{ |
307 | |
|
308 | 6 | String literal = OgnlRuntime.getNumericLiteral( types[i] ); |
309 | 6 | if ( literal != null ) |
310 | |
{ |
311 | 6 | value += literal; |
312 | |
} |
313 | |
} |
314 | |
|
315 | 37 | if ( ctorParamTypes[i] != types[i] ) |
316 | |
{ |
317 | |
|
318 | 4 | if ( values[i] != null && !types[i].isPrimitive() && !values[i].getClass().isArray() |
319 | |
&& !ASTConst.class.isInstance( children[i] ) ) |
320 | |
{ |
321 | |
|
322 | 2 | value = |
323 | |
"(" + OgnlRuntime.getCompiler( context ).getInterfaceClass( values[i].getClass() ).getName() |
324 | |
+ ")" + value; |
325 | |
} |
326 | 2 | else if ( !ASTConst.class.isInstance( children[i] ) |
327 | |
|| ( ASTConst.class.isInstance( children[i] ) && !types[i].isPrimitive() ) ) |
328 | |
{ |
329 | |
|
330 | 2 | if ( !types[i].isArray() && types[i].isPrimitive() && !ctorParamTypes[i].isPrimitive() ) |
331 | |
{ |
332 | 1 | value = |
333 | |
"new " |
334 | |
+ ExpressionCompiler.getCastString( |
335 | |
OgnlRuntime.getPrimitiveWrapperClass( types[i] ) ) |
336 | |
+ "(" + value + ")"; |
337 | |
} |
338 | |
else |
339 | |
{ |
340 | 1 | value = " ($w) " + value; |
341 | |
} |
342 | |
} |
343 | |
} |
344 | |
|
345 | 37 | result += value; |
346 | |
} |
347 | |
|
348 | |
} |
349 | 27 | result = result + ")"; |
350 | |
} |
351 | |
|
352 | 52 | context.setCurrentType( ctorValue != null ? ctorValue.getClass() : clazz ); |
353 | 52 | context.setCurrentAccessor( clazz ); |
354 | 52 | context.setCurrentObject( ctorValue ); |
355 | |
|
356 | |
} |
357 | 1 | catch ( Throwable t ) |
358 | |
{ |
359 | 1 | throw OgnlOps.castToRuntime( t ); |
360 | 52 | } |
361 | |
|
362 | 52 | context.remove( "_ctorClass" ); |
363 | |
|
364 | 52 | return result; |
365 | |
} |
366 | |
|
367 | |
public String toSetSourceString( OgnlContext context, Object target ) |
368 | |
{ |
369 | 32 | return ""; |
370 | |
} |
371 | |
|
372 | |
public <R, P> R accept( NodeVisitor<? extends R, ? super P> visitor, P data ) |
373 | |
throws OgnlException |
374 | |
{ |
375 | 0 | return visitor.visit( this, data ); |
376 | |
} |
377 | |
} |