1 | |
package org.apache.commons.ognl.enhance; |
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
|
15 | |
|
16 | |
|
17 | |
|
18 | |
|
19 | |
|
20 | |
|
21 | |
|
22 | |
import javassist.CannotCompileException; |
23 | |
import javassist.ClassPool; |
24 | |
import javassist.CtClass; |
25 | |
import javassist.CtField; |
26 | |
import javassist.CtMethod; |
27 | |
import javassist.CtNewConstructor; |
28 | |
import javassist.CtNewMethod; |
29 | |
import javassist.LoaderClassPath; |
30 | |
import javassist.NotFoundException; |
31 | |
import org.apache.commons.ognl.ASTAnd; |
32 | |
import org.apache.commons.ognl.ASTChain; |
33 | |
import org.apache.commons.ognl.ASTConst; |
34 | |
import org.apache.commons.ognl.ASTCtor; |
35 | |
import org.apache.commons.ognl.ASTList; |
36 | |
import org.apache.commons.ognl.ASTMethod; |
37 | |
import org.apache.commons.ognl.ASTOr; |
38 | |
import org.apache.commons.ognl.ASTProperty; |
39 | |
import org.apache.commons.ognl.ASTRootVarRef; |
40 | |
import org.apache.commons.ognl.ASTStaticField; |
41 | |
import org.apache.commons.ognl.ASTStaticMethod; |
42 | |
import org.apache.commons.ognl.ASTThisVarRef; |
43 | |
import org.apache.commons.ognl.ASTVarRef; |
44 | |
import org.apache.commons.ognl.ClassResolver; |
45 | |
import org.apache.commons.ognl.ExpressionNode; |
46 | |
import org.apache.commons.ognl.Node; |
47 | |
import org.apache.commons.ognl.OgnlContext; |
48 | |
import org.apache.commons.ognl.OgnlRuntime; |
49 | |
|
50 | |
import java.lang.reflect.Method; |
51 | |
import java.lang.reflect.Modifier; |
52 | |
import java.util.Collection; |
53 | |
import java.util.HashMap; |
54 | |
import java.util.Iterator; |
55 | |
import java.util.List; |
56 | |
import java.util.Map; |
57 | |
import java.util.Set; |
58 | |
|
59 | |
import static java.lang.String.format; |
60 | |
|
61 | |
|
62 | |
|
63 | |
|
64 | |
|
65 | 62 | public class ExpressionCompiler |
66 | |
implements OgnlExpressionCompiler |
67 | |
{ |
68 | |
|
69 | |
|
70 | |
|
71 | |
|
72 | |
public static final String PRE_CAST = "_preCast"; |
73 | |
|
74 | |
|
75 | |
|
76 | |
|
77 | 62 | protected Map<ClassResolver, EnhancedClassLoader> loaders = new HashMap<ClassResolver, EnhancedClassLoader>(); |
78 | |
|
79 | |
|
80 | |
|
81 | |
|
82 | |
protected ClassPool pool; |
83 | |
|
84 | 62 | protected int classCounter = 0; |
85 | |
|
86 | |
|
87 | |
|
88 | |
|
89 | |
|
90 | |
|
91 | |
|
92 | |
|
93 | |
|
94 | |
|
95 | |
public static void addCastString( OgnlContext context, String cast ) |
96 | |
{ |
97 | 196 | String value = (String) context.get( PRE_CAST ); |
98 | |
|
99 | 196 | if ( value != null ) |
100 | |
{ |
101 | 18 | value = cast + value; |
102 | |
} |
103 | |
else |
104 | |
{ |
105 | 178 | value = cast; |
106 | |
} |
107 | |
|
108 | 196 | context.put( PRE_CAST, value ); |
109 | 196 | } |
110 | |
|
111 | |
|
112 | |
|
113 | |
|
114 | |
|
115 | |
|
116 | |
|
117 | |
|
118 | |
|
119 | |
|
120 | |
|
121 | |
public static String getCastString( Class<?> type ) |
122 | |
{ |
123 | 972 | if ( type == null ) |
124 | |
{ |
125 | 0 | return null; |
126 | |
} |
127 | |
|
128 | 972 | return type.isArray() ? type.getComponentType().getName() + "[]" : type.getName(); |
129 | |
} |
130 | |
|
131 | |
|
132 | |
|
133 | |
|
134 | |
|
135 | |
|
136 | |
|
137 | |
|
138 | |
|
139 | |
|
140 | |
|
141 | |
|
142 | |
public static String getRootExpression( Node expression, Object root, OgnlContext context ) |
143 | |
{ |
144 | 1184 | String rootExpr = ""; |
145 | |
|
146 | 1184 | if ( !shouldCast( expression ) ) |
147 | |
{ |
148 | 380 | return rootExpr; |
149 | |
} |
150 | |
|
151 | 804 | if ( ( !ASTList.class.isInstance( expression ) && !ASTVarRef.class.isInstance( expression ) |
152 | |
&& !ASTStaticMethod.class.isInstance( expression ) && !ASTStaticField.class.isInstance( expression ) |
153 | |
&& !ASTConst.class.isInstance( expression ) && !ExpressionNode.class.isInstance( expression ) |
154 | |
&& !ASTCtor.class.isInstance( expression ) && !ASTStaticMethod.class.isInstance( expression ) |
155 | |
&& root != null ) || ( root != null && ASTRootVarRef.class.isInstance( expression ) ) ) |
156 | |
{ |
157 | |
|
158 | 526 | Class<?> castClass = OgnlRuntime.getCompiler( context ).getRootExpressionClass( expression, context ); |
159 | |
|
160 | 526 | if ( castClass.isArray() || ASTRootVarRef.class.isInstance( expression ) || ASTThisVarRef.class.isInstance( |
161 | |
expression ) ) |
162 | |
{ |
163 | 17 | rootExpr = "((" + getCastString( castClass ) + ")$2)"; |
164 | |
|
165 | 17 | if ( ASTProperty.class.isInstance( expression ) && !( (ASTProperty) expression ).isIndexedAccess() ) |
166 | |
{ |
167 | 2 | rootExpr += "."; |
168 | |
} |
169 | |
} |
170 | 509 | else if ( ( ASTProperty.class.isInstance( expression ) && ( (ASTProperty) expression ).isIndexedAccess() ) |
171 | |
|| ASTChain.class.isInstance( expression ) ) |
172 | |
{ |
173 | 217 | rootExpr = "((" + getCastString( castClass ) + ")$2)"; |
174 | |
} |
175 | |
else |
176 | |
{ |
177 | 292 | rootExpr = "((" + getCastString( castClass ) + ")$2)."; |
178 | |
} |
179 | |
} |
180 | |
|
181 | 804 | return rootExpr; |
182 | |
} |
183 | |
|
184 | |
|
185 | |
|
186 | |
|
187 | |
|
188 | |
|
189 | |
|
190 | |
|
191 | |
public static boolean shouldCast( Node expression ) |
192 | |
{ |
193 | 1393 | if ( ASTChain.class.isInstance( expression ) ) |
194 | |
{ |
195 | 249 | Node child = expression.jjtGetChild( 0 ); |
196 | 249 | if ( ASTConst.class.isInstance( child ) || ASTStaticMethod.class.isInstance( child ) |
197 | |
|| ASTStaticField.class.isInstance( child ) || ( ASTVarRef.class.isInstance( child ) |
198 | |
&& !ASTRootVarRef.class.isInstance( child ) ) ) |
199 | |
{ |
200 | 17 | return false; |
201 | |
} |
202 | |
} |
203 | |
|
204 | 1376 | return !ASTConst.class.isInstance( expression ); |
205 | |
} |
206 | |
|
207 | |
|
208 | |
|
209 | |
|
210 | |
public String castExpression( OgnlContext context, Node expression, String body ) |
211 | |
{ |
212 | |
|
213 | |
|
214 | 702 | if ( context.getCurrentAccessor() == null || context.getPreviousType() == null |
215 | |
|| context.getCurrentAccessor().isAssignableFrom( context.getPreviousType() ) || ( |
216 | |
context.getCurrentType() != null && context.getCurrentObject() != null |
217 | |
&& context.getCurrentType().isAssignableFrom( context.getCurrentObject().getClass() ) |
218 | |
&& context.getCurrentAccessor().isAssignableFrom( context.getPreviousType() ) ) || body == null |
219 | |
|| body.trim().length() < 1 || ( context.getCurrentType() != null && context.getCurrentType().isArray() && ( |
220 | |
context.getPreviousType() == null || context.getPreviousType() != Object.class ) ) |
221 | |
|| ASTOr.class.isInstance( expression ) || ASTAnd.class.isInstance( expression ) |
222 | |
|| ASTRootVarRef.class.isInstance( expression ) || context.getCurrentAccessor() == Class.class || ( |
223 | |
context.get( ExpressionCompiler.PRE_CAST ) != null && ( (String) context.get( |
224 | |
ExpressionCompiler.PRE_CAST ) ).startsWith( "new" ) ) || ASTStaticField.class.isInstance( expression ) |
225 | |
|| ASTStaticMethod.class.isInstance( expression ) || ( OrderedReturn.class.isInstance( expression ) |
226 | |
&& ( (OrderedReturn) expression ).getLastExpression() != null ) ) |
227 | |
{ |
228 | 520 | return body; |
229 | |
} |
230 | |
|
231 | |
|
232 | |
|
233 | |
|
234 | |
|
235 | |
|
236 | |
|
237 | |
|
238 | 182 | ExpressionCompiler.addCastString( context, |
239 | |
"((" + ExpressionCompiler.getCastString( context.getCurrentAccessor() ) |
240 | |
+ ")" ); |
241 | |
|
242 | 182 | return ")" + body; |
243 | |
} |
244 | |
|
245 | |
|
246 | |
|
247 | |
|
248 | |
public String getClassName( Class<?> clazz ) |
249 | |
{ |
250 | 0 | if ( "java.util.AbstractList$Itr".equals( clazz.getName() ) ) |
251 | |
{ |
252 | 0 | return Iterator.class.getName(); |
253 | |
} |
254 | |
|
255 | 0 | if ( Modifier.isPublic( clazz.getModifiers() ) && clazz.isInterface() ) |
256 | |
{ |
257 | 0 | return clazz.getName(); |
258 | |
} |
259 | |
|
260 | 0 | Class<?>[] interfaces = clazz.getInterfaces(); |
261 | |
|
262 | 0 | for ( Class<?> intface : interfaces ) |
263 | |
{ |
264 | 0 | if ( intface.getName().indexOf( "util.List" ) > 0 ) |
265 | |
{ |
266 | 0 | return intface.getName(); |
267 | |
} |
268 | 0 | else if ( intface.getName().indexOf( "Iterator" ) > 0 ) |
269 | |
{ |
270 | 0 | return intface.getName(); |
271 | |
} |
272 | |
} |
273 | |
|
274 | 0 | if ( clazz.getSuperclass() != null && clazz.getSuperclass().getInterfaces().length > 0 ) |
275 | |
{ |
276 | 0 | return getClassName( clazz.getSuperclass() ); |
277 | |
} |
278 | |
|
279 | 0 | return clazz.getName(); |
280 | |
} |
281 | |
|
282 | |
|
283 | |
|
284 | |
|
285 | |
public Class<?> getSuperOrInterfaceClass( Method m, Class<?> clazz ) |
286 | |
{ |
287 | 1767 | if ( clazz.getInterfaces() != null && clazz.getInterfaces().length > 0 ) |
288 | |
{ |
289 | 94 | Class<?>[] intfs = clazz.getInterfaces(); |
290 | |
Class<?> intClass; |
291 | |
|
292 | 218 | for ( Class<?> intf : intfs ) |
293 | |
{ |
294 | 165 | intClass = getSuperOrInterfaceClass( m, intf ); |
295 | |
|
296 | 165 | if ( intClass != null ) |
297 | |
{ |
298 | 41 | return intClass; |
299 | |
} |
300 | |
|
301 | 124 | if ( Modifier.isPublic( intf.getModifiers() ) && containsMethod( m, intf ) ) |
302 | |
{ |
303 | 0 | return intf; |
304 | |
} |
305 | |
} |
306 | |
} |
307 | |
|
308 | 1726 | if ( clazz.getSuperclass() != null ) |
309 | |
{ |
310 | 798 | Class<?> superClass = getSuperOrInterfaceClass( m, clazz.getSuperclass() ); |
311 | |
|
312 | 798 | if ( superClass != null ) |
313 | |
{ |
314 | 9 | return superClass; |
315 | |
} |
316 | |
} |
317 | |
|
318 | 1717 | if ( Modifier.isPublic( clazz.getModifiers() ) && containsMethod( m, clazz ) ) |
319 | |
{ |
320 | 804 | return clazz; |
321 | |
} |
322 | |
|
323 | 913 | return null; |
324 | |
} |
325 | |
|
326 | |
|
327 | |
|
328 | |
|
329 | |
|
330 | |
|
331 | |
|
332 | |
|
333 | |
|
334 | |
public boolean containsMethod( Method m, Class<?> clazz ) |
335 | |
{ |
336 | 1840 | Method[] methods = clazz.getMethods(); |
337 | |
|
338 | 1840 | if ( methods == null ) |
339 | |
{ |
340 | 0 | return false; |
341 | |
} |
342 | |
|
343 | 19554 | for ( Method method : methods ) |
344 | |
{ |
345 | 18518 | if ( method.getName().equals( m.getName() ) && method.getReturnType() == m.getReturnType() ) |
346 | |
{ |
347 | 817 | Class<?>[] parms = m.getParameterTypes(); |
348 | 817 | if ( parms == null ) |
349 | |
{ |
350 | 0 | continue; |
351 | |
} |
352 | |
|
353 | 817 | Class<?>[] mparms = method.getParameterTypes(); |
354 | 817 | if ( mparms == null || mparms.length != parms.length ) |
355 | |
{ |
356 | 6 | continue; |
357 | |
} |
358 | |
|
359 | 811 | boolean parmsMatch = true; |
360 | 1017 | for ( int p = 0; p < parms.length; p++ ) |
361 | |
{ |
362 | 213 | if ( parms[p] != mparms[p] ) |
363 | |
{ |
364 | 7 | parmsMatch = false; |
365 | 7 | break; |
366 | |
} |
367 | |
} |
368 | |
|
369 | 811 | if ( !parmsMatch ) |
370 | |
{ |
371 | 7 | continue; |
372 | |
} |
373 | |
|
374 | 804 | Class<?>[] exceptions = m.getExceptionTypes(); |
375 | 804 | if ( exceptions == null ) |
376 | |
{ |
377 | 0 | continue; |
378 | |
} |
379 | |
|
380 | 804 | Class<?>[] mexceptions = method.getExceptionTypes(); |
381 | 804 | if ( mexceptions == null || mexceptions.length != exceptions.length ) |
382 | |
{ |
383 | 0 | continue; |
384 | |
} |
385 | |
|
386 | 804 | boolean exceptionsMatch = true; |
387 | 810 | for ( int e = 0; e < exceptions.length; e++ ) |
388 | |
{ |
389 | 6 | if ( exceptions[e] != mexceptions[e] ) |
390 | |
{ |
391 | 0 | exceptionsMatch = false; |
392 | 0 | break; |
393 | |
} |
394 | |
} |
395 | |
|
396 | 804 | if ( !exceptionsMatch ) |
397 | |
{ |
398 | 0 | continue; |
399 | |
} |
400 | |
|
401 | 804 | return true; |
402 | |
} |
403 | |
} |
404 | |
|
405 | 1036 | return false; |
406 | |
} |
407 | |
|
408 | |
|
409 | |
|
410 | |
|
411 | |
public Class<?> getInterfaceClass( Class<?> clazz ) |
412 | |
{ |
413 | 1241 | if ( "java.util.AbstractList$Itr".equals( clazz.getName() ) ) |
414 | |
{ |
415 | 4 | return Iterator.class; |
416 | |
} |
417 | |
|
418 | 1237 | if ( Modifier.isPublic( clazz.getModifiers() ) && clazz.isInterface() || clazz.isPrimitive() ) |
419 | |
{ |
420 | 0 | return clazz; |
421 | |
} |
422 | |
|
423 | 1237 | Class<?>[] intf = clazz.getInterfaces(); |
424 | |
|
425 | 1399 | for ( Class<?> anIntf : intf ) |
426 | |
{ |
427 | 290 | if ( List.class.isAssignableFrom( anIntf ) ) |
428 | |
{ |
429 | 21 | return List.class; |
430 | |
} |
431 | 269 | else if ( Iterator.class.isAssignableFrom( anIntf ) ) |
432 | |
{ |
433 | 0 | return Iterator.class; |
434 | |
} |
435 | 269 | else if ( Map.class.isAssignableFrom( anIntf ) ) |
436 | |
{ |
437 | 105 | return Map.class; |
438 | |
} |
439 | 164 | else if ( Set.class.isAssignableFrom( anIntf ) ) |
440 | |
{ |
441 | 2 | return Set.class; |
442 | |
} |
443 | 162 | else if ( Collection.class.isAssignableFrom( anIntf ) ) |
444 | |
{ |
445 | 0 | return Collection.class; |
446 | |
} |
447 | |
} |
448 | |
|
449 | 1109 | if ( clazz.getSuperclass() != null && clazz.getSuperclass().getInterfaces().length > 0 ) |
450 | |
{ |
451 | 40 | return getInterfaceClass( clazz.getSuperclass() ); |
452 | |
} |
453 | |
|
454 | 1069 | return clazz; |
455 | |
} |
456 | |
|
457 | |
|
458 | |
|
459 | |
|
460 | |
public Class<?> getRootExpressionClass( Node rootNode, OgnlContext context ) |
461 | |
{ |
462 | 526 | if ( context.getRoot() == null ) |
463 | |
{ |
464 | 0 | return null; |
465 | |
} |
466 | |
|
467 | 526 | Class<?> ret = context.getRoot().getClass(); |
468 | |
|
469 | 526 | if ( context.getFirstAccessor() != null && context.getFirstAccessor().isInstance( context.getRoot() ) ) |
470 | |
{ |
471 | 448 | ret = context.getFirstAccessor(); |
472 | |
} |
473 | |
|
474 | 526 | return ret; |
475 | |
} |
476 | |
|
477 | |
|
478 | |
|
479 | |
|
480 | |
public void compileExpression( OgnlContext context, Node expression, Object root ) |
481 | |
throws Exception |
482 | |
{ |
483 | |
|
484 | |
|
485 | 568 | if ( expression.getAccessor() != null ) |
486 | |
{ |
487 | 0 | return; |
488 | |
} |
489 | |
|
490 | |
String getBody, setBody; |
491 | |
|
492 | 568 | EnhancedClassLoader loader = getClassLoader( context ); |
493 | 568 | ClassPool classPool = getClassPool( context, loader ); |
494 | |
|
495 | 568 | CtClass newClass = classPool.makeClass( |
496 | |
expression.getClass().getName() + expression.hashCode() + classCounter++ + "Accessor" ); |
497 | 568 | newClass.addInterface( getCtClass( ExpressionAccessor.class ) ); |
498 | |
|
499 | 568 | CtClass ognlClass = getCtClass( OgnlContext.class ); |
500 | 568 | CtClass objClass = getCtClass( Object.class ); |
501 | |
|
502 | 568 | CtMethod valueGetter = new CtMethod( objClass, "get", new CtClass[] { ognlClass, objClass }, newClass ); |
503 | 568 | CtMethod valueSetter = |
504 | |
new CtMethod( CtClass.voidType, "set", new CtClass[] { ognlClass, objClass, objClass }, newClass ); |
505 | |
|
506 | 568 | CtField nodeMember = null; |
507 | |
|
508 | 568 | CtClass nodeClass = getCtClass( Node.class ); |
509 | 568 | CtMethod setExpression = null; |
510 | |
|
511 | |
try |
512 | |
{ |
513 | |
|
514 | 568 | getBody = generateGetter( context, newClass, objClass, classPool, valueGetter, expression, root ); |
515 | |
|
516 | |
} |
517 | 155 | catch ( UnsupportedCompilationException uc ) |
518 | |
{ |
519 | |
|
520 | |
|
521 | 155 | nodeMember = new CtField( nodeClass, "_node", newClass ); |
522 | 155 | newClass.addField( nodeMember ); |
523 | |
|
524 | 155 | getBody = generateOgnlGetter( newClass, valueGetter, nodeMember ); |
525 | |
|
526 | 155 | setExpression = CtNewMethod.setter( "setExpression", nodeMember ); |
527 | 155 | newClass.addMethod( setExpression ); |
528 | 412 | } |
529 | |
|
530 | |
try |
531 | |
{ |
532 | |
|
533 | 567 | setBody = generateSetter( context, newClass, objClass, classPool, valueSetter, expression, root ); |
534 | |
|
535 | |
} |
536 | 438 | catch ( UnsupportedCompilationException uc ) |
537 | |
{ |
538 | |
|
539 | |
|
540 | |
|
541 | 438 | if ( nodeMember == null ) |
542 | |
{ |
543 | 285 | nodeMember = new CtField( nodeClass, "_node", newClass ); |
544 | 285 | newClass.addField( nodeMember ); |
545 | |
} |
546 | |
|
547 | 438 | setBody = generateOgnlSetter( newClass, valueSetter, nodeMember ); |
548 | |
|
549 | 438 | if ( setExpression == null ) |
550 | |
{ |
551 | 285 | setExpression = CtNewMethod.setter( "setExpression", nodeMember ); |
552 | 285 | newClass.addMethod( setExpression ); |
553 | |
} |
554 | 129 | } |
555 | |
|
556 | |
try |
557 | |
{ |
558 | 567 | newClass.addConstructor( CtNewConstructor.defaultConstructor( newClass ) ); |
559 | |
|
560 | 567 | Class<?> clazz = classPool.toClass( newClass ); |
561 | 567 | newClass.detach(); |
562 | |
|
563 | 567 | expression.setAccessor( (ExpressionAccessor) clazz.newInstance() ); |
564 | |
|
565 | |
|
566 | |
|
567 | 567 | if ( nodeMember != null ) |
568 | |
{ |
569 | 440 | expression.getAccessor().setExpression( expression ); |
570 | |
} |
571 | |
|
572 | |
} |
573 | 0 | catch ( Throwable t ) |
574 | |
{ |
575 | |
|
576 | |
|
577 | 0 | throw new RuntimeException( "Error compiling expression on object " + root + " with expression node " |
578 | |
+ expression + " getter body: " + getBody + " setter body: " + setBody, t ); |
579 | 567 | } |
580 | |
|
581 | 567 | } |
582 | |
|
583 | |
protected String generateGetter( OgnlContext context, CtClass newClass, CtClass objClass, ClassPool classPool, |
584 | |
CtMethod valueGetter, Node expression, Object root ) |
585 | |
throws Exception |
586 | |
{ |
587 | 568 | String pre = ""; |
588 | 568 | String post = ""; |
589 | |
String body; |
590 | |
|
591 | 568 | context.setRoot( root ); |
592 | |
|
593 | |
|
594 | |
|
595 | |
|
596 | |
|
597 | 568 | context.remove( PRE_CAST ); |
598 | |
|
599 | |
|
600 | |
|
601 | 568 | String getterCode = expression.toGetSourceString( context, root ); |
602 | |
|
603 | 412 | if ( getterCode == null || getterCode.trim().length() <= 0 |
604 | |
&& !ASTVarRef.class.isAssignableFrom( expression.getClass() ) ) |
605 | |
{ |
606 | 2 | getterCode = "null"; |
607 | |
} |
608 | |
|
609 | 412 | String castExpression = (String) context.get( PRE_CAST ); |
610 | |
|
611 | 412 | if ( context.getCurrentType() == null || context.getCurrentType().isPrimitive() |
612 | |
|| Character.class.isAssignableFrom( context.getCurrentType() ) |
613 | |
|| Object.class == context.getCurrentType() ) |
614 | |
{ |
615 | 278 | pre = pre + " ($w) ("; |
616 | 278 | post = post + ")"; |
617 | |
} |
618 | |
|
619 | 412 | String rootExpr = !"null".equals( getterCode ) ? getRootExpression( expression, root, context ) : ""; |
620 | |
|
621 | 412 | String noRoot = (String) context.remove( "_noRoot" ); |
622 | 412 | if ( noRoot != null ) |
623 | |
{ |
624 | 11 | rootExpr = ""; |
625 | |
} |
626 | |
|
627 | 412 | createLocalReferences( context, classPool, newClass, objClass, valueGetter.getParameterTypes() ); |
628 | |
|
629 | 412 | if ( OrderedReturn.class.isInstance( expression ) |
630 | |
&& ( (OrderedReturn) expression ).getLastExpression() != null ) |
631 | |
{ |
632 | 3 | body = "{ " + ( ASTMethod.class.isInstance( expression ) || ASTChain.class.isInstance( expression ) |
633 | |
? rootExpr |
634 | |
: "" ) + ( castExpression != null ? castExpression : "" ) |
635 | |
+ ( (OrderedReturn) expression ).getCoreExpression() + " return " + pre |
636 | |
+ ( (OrderedReturn) expression ).getLastExpression() + post + ";}"; |
637 | |
|
638 | |
} |
639 | |
else |
640 | |
{ |
641 | |
|
642 | 409 | body = |
643 | |
"{ return " + pre + ( castExpression != null ? castExpression : "" ) + rootExpr + getterCode + post |
644 | |
+ ";}"; |
645 | |
} |
646 | |
|
647 | 412 | body = body.replaceAll( "\\.\\.", "." ); |
648 | |
|
649 | |
|
650 | 412 | valueGetter.setBody( body ); |
651 | 412 | newClass.addMethod( valueGetter ); |
652 | |
|
653 | 412 | return body; |
654 | |
} |
655 | |
|
656 | |
|
657 | |
|
658 | |
|
659 | |
public String createLocalReference( OgnlContext context, String expression, Class<?> type ) |
660 | |
{ |
661 | 149 | String referenceName = "ref" + context.incrementLocalReferenceCounter(); |
662 | 149 | context.addLocalReference( referenceName, new LocalReferenceImpl( referenceName, expression, type ) ); |
663 | |
|
664 | 149 | String castString = ""; |
665 | 149 | if ( !type.isPrimitive() ) |
666 | |
{ |
667 | 107 | castString = "(" + ExpressionCompiler.getCastString( type ) + ") "; |
668 | |
} |
669 | |
|
670 | 149 | return castString + referenceName + "($$)"; |
671 | |
} |
672 | |
|
673 | |
void createLocalReferences( OgnlContext context, ClassPool classPool, CtClass clazz, CtClass unused, |
674 | |
CtClass[] params ) |
675 | |
throws NotFoundException, CannotCompileException |
676 | |
{ |
677 | 541 | Map<String, LocalReference> referenceMap = context.getLocalReferences(); |
678 | 541 | if ( referenceMap == null || referenceMap.isEmpty() ) |
679 | |
{ |
680 | 450 | return; |
681 | |
} |
682 | |
|
683 | 91 | Iterator<LocalReference> it = referenceMap.values().iterator(); |
684 | 237 | while( it.hasNext() ) |
685 | |
{ |
686 | 146 | LocalReference ref = it.next(); |
687 | 146 | String widener = ref.getType().isPrimitive() ? " " : " ($w) "; |
688 | |
|
689 | 146 | String body = format( "{ return %s %s; }", widener, ref.getExpression() ).replaceAll( "\\.\\.", "." ); |
690 | |
|
691 | |
|
692 | |
|
693 | |
|
694 | 146 | CtMethod method = |
695 | |
new CtMethod( classPool.get( getCastString( ref.getType() ) ), ref.getName(), params, clazz ); |
696 | 146 | method.setBody( body ); |
697 | |
|
698 | 146 | clazz.addMethod( method ); |
699 | 146 | it.remove(); |
700 | 146 | } |
701 | 91 | } |
702 | |
|
703 | |
protected String generateSetter( OgnlContext context, CtClass newClass, CtClass objClass, ClassPool classPool, |
704 | |
CtMethod valueSetter, Node expression, Object root ) |
705 | |
throws Exception |
706 | |
{ |
707 | 567 | if ( ExpressionNode.class.isInstance( expression ) || ASTConst.class.isInstance( expression ) ) |
708 | |
{ |
709 | 230 | throw new UnsupportedCompilationException( "Can't compile expression/constant setters." ); |
710 | |
} |
711 | |
|
712 | 337 | context.setRoot( root ); |
713 | 337 | context.remove( PRE_CAST ); |
714 | |
|
715 | |
String body; |
716 | |
|
717 | 337 | String setterCode = expression.toSetSourceString( context, root ); |
718 | 177 | String castExpression = (String) context.get( PRE_CAST ); |
719 | |
|
720 | 177 | if ( setterCode == null || setterCode.trim().length() < 1 ) |
721 | |
{ |
722 | 42 | throw new UnsupportedCompilationException( "Can't compile null setter body." ); |
723 | |
} |
724 | |
|
725 | 135 | if ( root == null ) |
726 | |
{ |
727 | 6 | throw new UnsupportedCompilationException( "Can't compile setters with a null root object." ); |
728 | |
} |
729 | |
|
730 | 129 | String pre = getRootExpression( expression, root, context ); |
731 | |
|
732 | 129 | String noRoot = (String) context.remove( "_noRoot" ); |
733 | 129 | if ( noRoot != null ) |
734 | |
{ |
735 | 2 | pre = ""; |
736 | |
} |
737 | |
|
738 | 129 | createLocalReferences( context, classPool, newClass, objClass, valueSetter.getParameterTypes() ); |
739 | |
|
740 | 129 | body = "{" + ( castExpression != null ? castExpression : "" ) + pre + setterCode + ";}"; |
741 | |
|
742 | 129 | body = body.replaceAll( "\\.\\.", "." ); |
743 | |
|
744 | |
|
745 | |
|
746 | 129 | valueSetter.setBody( body ); |
747 | 129 | newClass.addMethod( valueSetter ); |
748 | |
|
749 | 129 | return body; |
750 | |
} |
751 | |
|
752 | |
|
753 | |
|
754 | |
|
755 | |
|
756 | |
|
757 | |
|
758 | |
|
759 | |
|
760 | |
|
761 | |
|
762 | |
protected String generateOgnlGetter( CtClass clazz, CtMethod valueGetter, CtField node ) |
763 | |
throws Exception |
764 | |
{ |
765 | 155 | String body = "return " + node.getName() + ".getValue($1, $2);"; |
766 | |
|
767 | 155 | valueGetter.setBody( body ); |
768 | 155 | clazz.addMethod( valueGetter ); |
769 | |
|
770 | 155 | return body; |
771 | |
} |
772 | |
|
773 | |
|
774 | |
|
775 | |
|
776 | |
|
777 | |
|
778 | |
|
779 | |
|
780 | |
|
781 | |
|
782 | |
|
783 | |
protected String generateOgnlSetter( CtClass clazz, CtMethod valueSetter, CtField node ) |
784 | |
throws Exception |
785 | |
{ |
786 | 438 | String body = node.getName() + ".setValue($1, $2, $3);"; |
787 | |
|
788 | 438 | valueSetter.setBody( body ); |
789 | 438 | clazz.addMethod( valueSetter ); |
790 | |
|
791 | 438 | return body; |
792 | |
} |
793 | |
|
794 | |
|
795 | |
|
796 | |
|
797 | |
|
798 | |
|
799 | |
|
800 | |
|
801 | |
protected EnhancedClassLoader getClassLoader( OgnlContext context ) |
802 | |
{ |
803 | 568 | EnhancedClassLoader ret = loaders.get( context.getClassResolver() ); |
804 | |
|
805 | 568 | if ( ret != null ) |
806 | |
{ |
807 | 561 | return ret; |
808 | |
} |
809 | |
|
810 | 7 | ClassLoader classLoader = new ContextClassLoader( OgnlContext.class.getClassLoader(), context ); |
811 | |
|
812 | 7 | ret = new EnhancedClassLoader( classLoader ); |
813 | 7 | loaders.put( context.getClassResolver(), ret ); |
814 | |
|
815 | 7 | return ret; |
816 | |
} |
817 | |
|
818 | |
|
819 | |
|
820 | |
|
821 | |
|
822 | |
|
823 | |
|
824 | |
|
825 | |
protected CtClass getCtClass( Class<?> searchClass ) |
826 | |
throws NotFoundException |
827 | |
{ |
828 | 2272 | return pool.get( searchClass.getName() ); |
829 | |
} |
830 | |
|
831 | |
|
832 | |
|
833 | |
|
834 | |
|
835 | |
|
836 | |
|
837 | |
|
838 | |
|
839 | |
|
840 | |
|
841 | |
protected ClassPool getClassPool( OgnlContext context, EnhancedClassLoader loader ) |
842 | |
{ |
843 | 568 | if ( pool != null ) |
844 | |
{ |
845 | 561 | return pool; |
846 | |
} |
847 | |
|
848 | 7 | pool = ClassPool.getDefault(); |
849 | 7 | pool.insertClassPath( new LoaderClassPath( loader.getParent() ) ); |
850 | |
|
851 | 7 | return pool; |
852 | |
} |
853 | |
} |