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 import org.apache.commons.ognl.enhance.OgnlExpressionCompiler;
24 import org.apache.commons.ognl.enhance.OrderedReturn;
25 import org.apache.commons.ognl.enhance.UnsupportedCompilationException;
26
27 import java.lang.reflect.Method;
28
29
30
31
32
33
34
35 public class ASTMethod
36 extends SimpleNode
37 implements OrderedReturn, NodeType
38 {
39
40 private String methodName;
41
42 private String lastExpression;
43
44 private String coreExpression;
45
46 private Class getterClass;
47
48 public ASTMethod( int id )
49 {
50 super( id );
51 }
52
53 public ASTMethod( OgnlParser p, int id )
54 {
55 super( p, id );
56 }
57
58
59
60
61
62
63 public void setMethodName( String methodName )
64 {
65 this.methodName = methodName;
66 }
67
68
69
70
71
72
73 public String getMethodName()
74 {
75 return methodName;
76 }
77
78 protected Object getValueBody( OgnlContext context, Object source )
79 throws OgnlException
80 {
81 Object[] args = OgnlRuntime.getObjectArrayPool().create( jjtGetNumChildren() );
82
83 try
84 {
85 Object result, root = context.getRoot();
86
87 for ( int i = 0; i < args.length; ++i )
88 {
89 args[i] = children[i].getValue( context, root );
90 }
91
92 result = OgnlRuntime.callMethod( context, source, methodName, args );
93
94 if ( result == null )
95 {
96 NullHandler nullHandler = OgnlRuntime.getNullHandler( OgnlRuntime.getTargetClass( source ) );
97 result = nullHandler.nullMethodResult( context, source, methodName, args );
98 }
99
100 return result;
101
102 }
103 finally
104 {
105 OgnlRuntime.getObjectArrayPool().recycle( args );
106 }
107 }
108
109 public String getLastExpression()
110 {
111 return lastExpression;
112 }
113
114 public String getCoreExpression()
115 {
116 return coreExpression;
117 }
118
119 public Class getGetterClass()
120 {
121 return getterClass;
122 }
123
124 public Class getSetterClass()
125 {
126 return getterClass;
127 }
128
129 public String toGetSourceString( OgnlContext context, Object target )
130 {
131
132
133
134
135 if ( target == null )
136 {
137 throw new UnsupportedCompilationException( "Target object is null." );
138 }
139
140 String post = "";
141 StringBuilder sourceStringBuilder;
142 Method method;
143
144 OgnlExpressionCompiler compiler = OgnlRuntime.getCompiler( context );
145 try
146 {
147
148 method = OgnlRuntime.getMethod( context, context.getCurrentType() != null
149 ? context.getCurrentType()
150 : target.getClass(), methodName, children, false );
151 if ( method == null )
152 {
153 method = OgnlRuntime.getReadMethod( target.getClass(), methodName,
154 children != null ? children.length : -1 );
155 }
156
157 if ( method == null )
158 {
159 method = OgnlRuntime.getWriteMethod( target.getClass(), methodName,
160 children != null ? children.length : -1 );
161
162 if ( method != null )
163 {
164
165 context.setCurrentType( method.getReturnType() );
166 context.setCurrentAccessor(
167 compiler.getSuperOrInterfaceClass( method, method.getDeclaringClass() ) );
168
169 coreExpression = toSetSourceString( context, target );
170 if ( coreExpression == null || coreExpression.length() < 1 )
171 {
172 throw new UnsupportedCompilationException( "can't find suitable getter method" );
173 }
174
175 coreExpression += ";";
176 lastExpression = "null";
177
178 return coreExpression;
179 }
180
181 return "";
182 }
183 else
184 {
185 getterClass = method.getReturnType();
186 }
187
188
189 boolean varArgs = method.isVarArgs();
190
191 if ( varArgs )
192 {
193 throw new UnsupportedCompilationException(
194 "Javassist does not currently support varargs method calls" );
195 }
196
197 sourceStringBuilder = new StringBuilder().append( "." ).append( method.getName() ).append( "(" );
198
199 if ( ( children != null ) && ( children.length > 0 ) )
200 {
201 Class[] parms = method.getParameterTypes();
202 String prevCast = (String) context.remove( ExpressionCompiler.PRE_CAST );
203
204
205
206
207
208
209 for ( int i = 0; i < children.length; i++ )
210 {
211 if ( i > 0 )
212 {
213 sourceStringBuilder.append( ", " );
214 }
215
216 Class prevType = context.getCurrentType();
217
218 Object root = context.getRoot();
219 context.setCurrentObject( root );
220 context.setCurrentType( root != null ? root.getClass() : null );
221 context.setCurrentAccessor( null );
222 context.setPreviousType( null );
223
224 Node child = children[i];
225
226 String parmString = ASTMethodUtil.getParmString( context, root, child, prevType );
227
228 Class valueClass = ASTMethodUtil.getValueClass( context, root, child );
229
230 if ( ( !varArgs || varArgs && ( i + 1 ) < parms.length ) && valueClass != parms[i] )
231 {
232 parmString = ASTMethodUtil.getParmString( context, parms[i], parmString, child, valueClass,
233 ".class, true)" );
234 }
235
236 sourceStringBuilder.append( parmString );
237 }
238
239 if ( prevCast != null )
240 {
241 context.put( ExpressionCompiler.PRE_CAST, prevCast );
242 }
243 }
244
245 }
246 catch ( Throwable t )
247 {
248 throw OgnlOps.castToRuntime( t );
249 }
250
251 try
252 {
253 Object contextObj = getValueBody( context, target );
254 context.setCurrentObject( contextObj );
255 }
256 catch ( Throwable t )
257 {
258 throw OgnlOps.castToRuntime( t );
259 }
260
261 sourceStringBuilder.append( ")" ).append( post );
262
263 if ( method.getReturnType() == void.class )
264 {
265 coreExpression = sourceStringBuilder.toString() + ";";
266 lastExpression = "null";
267 }
268
269 context.setCurrentType( method.getReturnType() );
270 context.setCurrentAccessor( compiler.getSuperOrInterfaceClass( method, method.getDeclaringClass() ) );
271
272 return sourceStringBuilder.toString();
273 }
274
275 public String toSetSourceString( OgnlContext context, Object target )
276 {
277
278
279
280
281 Method method =
282 OgnlRuntime.getWriteMethod( context.getCurrentType() != null ? context.getCurrentType() : target.getClass(),
283 methodName, children != null ? children.length : -1 );
284 if ( method == null )
285 {
286 throw new UnsupportedCompilationException(
287 "Unable to determine setter method generation for " + methodName );
288 }
289
290 String post = "";
291 String result = "." + method.getName() + "(";
292
293 if ( method.getReturnType() != void.class && method.getReturnType().isPrimitive() && ( parent == null
294 || !ASTTest.class.isInstance( parent ) ) )
295 {
296 Class wrapper = OgnlRuntime.getPrimitiveWrapperClass( method.getReturnType() );
297
298 ExpressionCompiler.addCastString( context, "new " + wrapper.getName() + "(" );
299 post = ")";
300 getterClass = wrapper;
301 }
302
303 boolean varArgs = method.isVarArgs();
304
305 if ( varArgs )
306 {
307 throw new UnsupportedCompilationException( "Javassist does not currently support varargs method calls" );
308 }
309
310 OgnlExpressionCompiler compiler = OgnlRuntime.getCompiler( context );
311 try
312 {
313
314
315
316
317
318 if ( ( children != null ) && ( children.length > 0 ) )
319 {
320 Class[] parms = method.getParameterTypes();
321 String prevCast = (String) context.remove( ExpressionCompiler.PRE_CAST );
322
323 for ( int i = 0; i < children.length; i++ )
324 {
325 if ( i > 0 )
326 {
327 result += ", ";
328 }
329
330 Class prevType = context.getCurrentType();
331
332 context.setCurrentObject( context.getRoot() );
333 context.setCurrentType( context.getRoot() != null ? context.getRoot().getClass() : null );
334 context.setCurrentAccessor( null );
335 context.setPreviousType( null );
336
337 Node child = children[i];
338 Object value = child.getValue( context, context.getRoot() );
339 String parmString = child.toSetSourceString( context, context.getRoot() );
340
341 if ( context.getCurrentType() == Void.TYPE || context.getCurrentType() == void.class )
342 {
343 throw new UnsupportedCompilationException( "Method argument can't be a void type." );
344 }
345
346 if ( parmString == null || parmString.trim().length() < 1 )
347 {
348 if ( ASTProperty.class.isInstance( child ) || ASTMethod.class.isInstance( child )
349 || ASTStaticMethod.class.isInstance( child ) || ASTChain.class.isInstance( child ) )
350 {
351 throw new UnsupportedCompilationException(
352 "ASTMethod setter child returned null from a sub property expression." );
353 }
354 parmString = "null";
355 }
356
357
358 if ( ASTConst.class.isInstance( child ) )
359 {
360 context.setCurrentType( prevType );
361 }
362
363 parmString = ExpressionCompiler.getRootExpression( child, context.getRoot(), context ) + parmString;
364
365 String cast = "";
366 if ( ExpressionCompiler.shouldCast( child ) )
367 {
368 cast = (String) context.remove( ExpressionCompiler.PRE_CAST );
369 }
370
371 if ( cast == null )
372 {
373 cast = "";
374 }
375
376 parmString = cast + parmString;
377
378 Class valueClass = value != null ? value.getClass() : null;
379 if ( NodeType.class.isAssignableFrom( child.getClass() ) )
380 {
381 valueClass = ( (NodeType) child ).getGetterClass();
382 }
383
384 if ( valueClass != parms[i] )
385 {
386 parmString =
387 ASTMethodUtil.getParmString( context, parms[i], parmString, child, valueClass, ".class)" );
388 }
389
390 result += parmString;
391 }
392
393 if ( prevCast != null )
394 {
395 context.put( ExpressionCompiler.PRE_CAST, prevCast );
396 }
397 }
398
399 }
400 catch ( Throwable t )
401 {
402 throw OgnlOps.castToRuntime( t );
403 }
404
405 try
406 {
407 Object contextObj = getValueBody( context, target );
408 context.setCurrentObject( contextObj );
409 }
410 catch ( Throwable t )
411 {
412
413 }
414
415 context.setCurrentType( method.getReturnType() );
416 context.setCurrentAccessor( compiler.getSuperOrInterfaceClass( method, method.getDeclaringClass() ) );
417
418 return result + ")" + post;
419 }
420
421 public <R, P> R accept( NodeVisitor<? extends R, ? super P> visitor, P data )
422 throws OgnlException
423 {
424 return visitor.visit( this, data );
425 }
426 }