View Javadoc

1   package org.apache.commons.ognl;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   * http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
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   * $Id: ASTCtor.java 1194869 2011-10-29 11:10:16Z mcucchiara $
30   * @author Luke Blanshard (blanshlu@netscape.net)
31   * @author Drew Davidson (drew@ognl.org)
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          super( id );
44      }
45  
46      public ASTCtor( OgnlParser p, int id )
47      {
48          super( p, id );
49      }
50  
51      /** Called from parser action. */
52      void setClassName( String className )
53      {
54          this.className = className;
55      }
56  
57      /**
58       * Get the class name for this constructor.
59       *
60       * @return the class name.
61       * @since 4.0
62       */
63      String getClassName()
64      {
65          return className;
66      }
67  
68  
69      void setArray( boolean value )
70      {
71          isArray = value;
72      }
73  
74      public boolean isArray()
75      {
76          return isArray;
77      }
78  
79      protected Object getValueBody( OgnlContext context, Object source )
80          throws OgnlException
81      {
82          Object result, root = context.getRoot();
83          int count = jjtGetNumChildren();
84          Object[] args = OgnlRuntime.getObjectArrayPool().create( count );
85  
86          try
87          {
88              for ( int i = 0; i < count; ++i )
89              {
90                  args[i] = children[i].getValue( context, root );
91              }
92              if ( isArray )
93              {
94                  if ( args.length == 1 )
95                  {
96                      try
97                      {
98                          Class componentClass = OgnlRuntime.classForName( context, className );
99                          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 }