001 package org.apache.commons.ognl; 002 003 /* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022 import org.apache.commons.ognl.enhance.ExpressionCompiler; 023 024 import java.lang.reflect.Array; 025 import java.lang.reflect.Constructor; 026 import java.util.List; 027 028 /** 029 * $Id: ASTCtor.java 1194869 2011-10-29 11:10:16Z mcucchiara $ 030 * @author Luke Blanshard (blanshlu@netscape.net) 031 * @author Drew Davidson (drew@ognl.org) 032 */ 033 public class ASTCtor 034 extends SimpleNode 035 { 036 037 private String className; 038 039 private boolean isArray; 040 041 public ASTCtor( int id ) 042 { 043 super( id ); 044 } 045 046 public ASTCtor( OgnlParser p, int id ) 047 { 048 super( p, id ); 049 } 050 051 /** Called from parser action. */ 052 void setClassName( String className ) 053 { 054 this.className = className; 055 } 056 057 /** 058 * Get the class name for this constructor. 059 * 060 * @return the class name. 061 * @since 4.0 062 */ 063 String getClassName() 064 { 065 return className; 066 } 067 068 069 void setArray( boolean value ) 070 { 071 isArray = value; 072 } 073 074 public boolean isArray() 075 { 076 return isArray; 077 } 078 079 protected Object getValueBody( OgnlContext context, Object source ) 080 throws OgnlException 081 { 082 Object result, root = context.getRoot(); 083 int count = jjtGetNumChildren(); 084 Object[] args = OgnlRuntime.getObjectArrayPool().create( count ); 085 086 try 087 { 088 for ( int i = 0; i < count; ++i ) 089 { 090 args[i] = children[i].getValue( context, root ); 091 } 092 if ( isArray ) 093 { 094 if ( args.length == 1 ) 095 { 096 try 097 { 098 Class componentClass = OgnlRuntime.classForName( context, className ); 099 List sourceList = null; 100 int size; 101 102 if ( args[0] instanceof List ) 103 { 104 sourceList = (List) args[0]; 105 size = sourceList.size(); 106 } 107 else 108 { 109 size = (int) OgnlOps.longValue( args[0] ); 110 } 111 result = Array.newInstance( componentClass, size ); 112 if ( sourceList != null ) 113 { 114 TypeConverter converter = context.getTypeConverter(); 115 116 for ( int i = 0, icount = sourceList.size(); i < icount; i++ ) 117 { 118 Object o = sourceList.get( i ); 119 120 if ( ( o == null ) || componentClass.isInstance( o ) ) 121 { 122 Array.set( result, i, o ); 123 } 124 else 125 { 126 Array.set( result, i, 127 converter.convertValue( context, null, null, null, o, componentClass ) ); 128 } 129 } 130 } 131 } 132 catch ( ClassNotFoundException ex ) 133 { 134 throw new OgnlException( "array component class '" + className + "' not found", ex ); 135 } 136 } 137 else 138 { 139 throw new OgnlException( "only expect array size or fixed initializer list" ); 140 } 141 } 142 else 143 { 144 result = OgnlRuntime.callConstructor( context, className, args ); 145 } 146 147 return result; 148 } 149 finally 150 { 151 OgnlRuntime.getObjectArrayPool().recycle( args ); 152 } 153 } 154 155 156 public String toGetSourceString( OgnlContext context, Object target ) 157 { 158 String result = "new " + className; 159 160 Class clazz = null; 161 Object ctorValue = null; 162 try 163 { 164 165 clazz = OgnlRuntime.classForName( context, className ); 166 167 ctorValue = this.getValueBody( context, target ); 168 context.setCurrentObject( ctorValue ); 169 170 if ( clazz != null && ctorValue != null ) 171 { 172 173 context.setCurrentType( ctorValue.getClass() ); 174 context.setCurrentAccessor( ctorValue.getClass() ); 175 } 176 177 if ( isArray ) 178 { 179 context.put( "_ctorClass", clazz ); 180 } 181 } 182 catch ( Throwable t ) 183 { 184 throw OgnlOps.castToRuntime( t ); 185 } 186 187 try 188 { 189 190 if ( isArray ) 191 { 192 if ( children[0] instanceof ASTConst ) 193 { 194 195 result = result + "[" + children[0].toGetSourceString( context, target ) + "]"; 196 } 197 else if ( ASTProperty.class.isInstance( children[0] ) ) 198 { 199 200 result = 201 result + "[" + ExpressionCompiler.getRootExpression( children[0], target, context ) 202 + children[0].toGetSourceString( context, target ) + "]"; 203 } 204 else if ( ASTChain.class.isInstance( children[0] ) ) 205 { 206 207 result = result + "[" + children[0].toGetSourceString( context, target ) + "]"; 208 } 209 else 210 { 211 212 result = result + "[] " + children[0].toGetSourceString( context, target ); 213 } 214 215 } 216 else 217 { 218 result = result + "("; 219 220 if ( ( children != null ) && ( children.length > 0 ) ) 221 { 222 223 Object[] values = new Object[children.length]; 224 String[] expressions = new String[children.length]; 225 Class[] types = new Class[children.length]; 226 227 // first populate arrays with child values 228 229 for ( int i = 0; i < children.length; i++ ) 230 { 231 232 Object objValue = children[i].getValue( context, context.getRoot() ); 233 String value = children[i].toGetSourceString( context, target ); 234 235 if ( !ASTRootVarRef.class.isInstance( children[i] ) ) 236 { 237 value = ExpressionCompiler.getRootExpression( children[i], target, context ) + value; 238 } 239 240 String cast = ""; 241 if ( ExpressionCompiler.shouldCast( children[i] ) ) 242 { 243 244 cast = (String) context.remove( ExpressionCompiler.PRE_CAST ); 245 } 246 if ( cast == null ) 247 { 248 cast = ""; 249 } 250 251 if ( !ASTConst.class.isInstance( children[i] ) ) 252 { 253 value = cast + value; 254 } 255 256 values[i] = objValue; 257 expressions[i] = value; 258 types[i] = context.getCurrentType(); 259 } 260 261 // now try and find a matching constructor 262 263 Constructor[] cons = clazz.getConstructors(); 264 Constructor ctor = null; 265 Class[] ctorParamTypes = null; 266 267 for ( int i = 0; i < cons.length; i++ ) 268 { 269 Class[] ctorTypes = cons[i].getParameterTypes(); 270 271 if ( OgnlRuntime.areArgsCompatible( values, ctorTypes ) 272 && ( ctor == null || OgnlRuntime.isMoreSpecific( ctorTypes, ctorParamTypes ) ) ) 273 { 274 ctor = cons[i]; 275 ctorParamTypes = ctorTypes; 276 } 277 } 278 279 if ( ctor == null ) 280 { 281 ctor = 282 OgnlRuntime.getConvertedConstructorAndArgs( context, clazz, 283 OgnlRuntime.getConstructors( clazz ), values, 284 new Object[values.length] ); 285 } 286 287 if ( ctor == null ) 288 { 289 throw new NoSuchMethodException( 290 "Unable to find constructor appropriate for arguments in class: " + clazz ); 291 } 292 ctorParamTypes = ctor.getParameterTypes(); 293 294 // now loop over child values again and build up the actual source string 295 296 for ( int i = 0; i < children.length; i++ ) 297 { 298 if ( i > 0 ) 299 { 300 result = result + ", "; 301 } 302 303 String value = expressions[i]; 304 305 if ( types[i].isPrimitive() ) 306 { 307 308 String literal = OgnlRuntime.getNumericLiteral( types[i] ); 309 if ( literal != null ) 310 { 311 value += literal; 312 } 313 } 314 315 if ( ctorParamTypes[i] != types[i] ) 316 { 317 318 if ( values[i] != null && !types[i].isPrimitive() && !values[i].getClass().isArray() 319 && !ASTConst.class.isInstance( children[i] ) ) 320 { 321 322 value = 323 "(" + OgnlRuntime.getCompiler( context ).getInterfaceClass( values[i].getClass() ).getName() 324 + ")" + value; 325 } 326 else if ( !ASTConst.class.isInstance( children[i] ) 327 || ( ASTConst.class.isInstance( children[i] ) && !types[i].isPrimitive() ) ) 328 { 329 330 if ( !types[i].isArray() && types[i].isPrimitive() && !ctorParamTypes[i].isPrimitive() ) 331 { 332 value = 333 "new " 334 + ExpressionCompiler.getCastString( 335 OgnlRuntime.getPrimitiveWrapperClass( types[i] ) ) 336 + "(" + value + ")"; 337 } 338 else 339 { 340 value = " ($w) " + value; 341 } 342 } 343 } 344 345 result += value; 346 } 347 348 } 349 result = result + ")"; 350 } 351 352 context.setCurrentType( ctorValue != null ? ctorValue.getClass() : clazz ); 353 context.setCurrentAccessor( clazz ); 354 context.setCurrentObject( ctorValue ); 355 356 } 357 catch ( Throwable t ) 358 { 359 throw OgnlOps.castToRuntime( t ); 360 } 361 362 context.remove( "_ctorClass" ); 363 364 return result; 365 } 366 367 public String toSetSourceString( OgnlContext context, Object target ) 368 { 369 return ""; 370 } 371 372 public <R, P> R accept( NodeVisitor<? extends R, ? super P> visitor, P data ) 373 throws OgnlException 374 { 375 return visitor.visit( this, data ); 376 } 377 }