| 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 | |
} |