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.math.BigDecimal;
25  import java.math.BigInteger;
26  
27  /**
28   * $Id: ASTAdd.java 1194869 2011-10-29 11:10:16Z mcucchiara $
29   * @author Luke Blanshard (blanshlu@netscape.net)
30   * @author Drew Davidson (drew@ognl.org)
31   */
32  class ASTAdd
33      extends NumericExpression
34  {
35      public ASTAdd( int id )
36      {
37          super( id );
38      }
39  
40      public ASTAdd( OgnlParser p, int id )
41      {
42          super( p, id );
43      }
44  
45      public void jjtClose()
46      {
47          flattenTree();
48      }
49  
50      protected Object getValueBody( OgnlContext context, Object source )
51          throws OgnlException
52      {
53          Object result = children[0].getValue( context, source );
54  
55          for ( int i = 1; i < children.length; ++i )
56          {
57              result = OgnlOps.add( result, children[i].getValue( context, source ) );
58          }
59  
60          return result;
61      }
62  
63      public String getExpressionOperator( int index )
64      {
65          return "+";
66      }
67  
68      boolean isWider( NodeType type, NodeType lastType )
69      {
70          if ( lastType == null )
71          {
72              return true;
73          }
74  
75          // System.out.println("checking isWider(" + type.getGetterClass() + " , " + lastType.getGetterClass() + ")");
76  
77          if ( String.class.isAssignableFrom( lastType.getGetterClass() ) )
78          {
79              return false;
80          }
81  
82          if ( String.class.isAssignableFrom( type.getGetterClass() ) )
83          {
84              return true;
85          }
86  
87          if ( parent != null && String.class.isAssignableFrom( type.getGetterClass() ) )
88          {
89              return true;
90          }
91  
92          if ( String.class.isAssignableFrom( lastType.getGetterClass() ) && Object.class == type.getGetterClass() )
93          {
94              return false;
95          }
96  
97          if ( parent != null && String.class.isAssignableFrom( lastType.getGetterClass() ) )
98          {
99              return false;
100         }
101         else if ( parent == null && String.class.isAssignableFrom( lastType.getGetterClass() ) )
102         {
103             return true;
104         }
105         else if ( parent == null && String.class.isAssignableFrom( type.getGetterClass() ) )
106         {
107             return false;
108         }
109 
110         if ( BigDecimal.class.isAssignableFrom( type.getGetterClass() )
111             || BigInteger.class.isAssignableFrom( type.getGetterClass() ) )
112         {
113             return true;
114         }
115 
116         if ( BigDecimal.class.isAssignableFrom( lastType.getGetterClass() )
117             || BigInteger.class.isAssignableFrom( lastType.getGetterClass() ) )
118         {
119             return false;
120         }
121 
122         if ( Double.class.isAssignableFrom( type.getGetterClass() ) )
123         {
124             return true;
125         }
126 
127         if ( Integer.class.isAssignableFrom( type.getGetterClass() )
128             && Double.class.isAssignableFrom( lastType.getGetterClass() ) )
129         {
130             return false;
131         }
132 
133         if ( Float.class.isAssignableFrom( type.getGetterClass() )
134             && Integer.class.isAssignableFrom( lastType.getGetterClass() ) )
135         {
136             return true;
137         }
138 
139         return true;
140     }
141 
142     public String toGetSourceString( OgnlContext context, Object target )
143     {
144         try
145         {
146             String result = "";
147             NodeType lastType = null;
148 
149             // go through once to determine the ultimate type
150 
151             if ( ( children != null ) && ( children.length > 0 ) )
152             {
153                 Class currType = context.getCurrentType();
154                 Class currAccessor = context.getCurrentAccessor();
155 
156                 Object cast = context.get( ExpressionCompiler.PRE_CAST );
157 
158                 for ( int i = 0; i < children.length; ++i )
159                 {
160                     children[i].toGetSourceString( context, target );
161 
162                     if ( NodeType.class.isInstance( children[i] )
163                         && ( (NodeType) children[i] ).getGetterClass() != null
164                         && isWider( (NodeType) children[i], lastType ) )
165                     {
166                         lastType = (NodeType) children[i];
167                     }
168                 }
169 
170                 context.put( ExpressionCompiler.PRE_CAST, cast );
171 
172                 context.setCurrentType( currType );
173                 context.setCurrentAccessor( currAccessor );
174             }
175 
176             // reset context since previous children loop would have changed it
177 
178             context.setCurrentObject( target );
179 
180             if ( ( children != null ) && ( children.length > 0 ) )
181             {
182 
183                 for ( int i = 0; i < children.length; ++i )
184                 {
185                     if ( i > 0 )
186                     {
187                         result += " " + getExpressionOperator( i ) + " ";
188                     }
189 
190                     String expr = children[i].toGetSourceString( context, target );
191 
192                     if ( ( expr != null && "null".equals( expr ) )
193                         || ( !ASTConst.class.isInstance( children[i] )
194                         && ( expr == null || expr.trim().length() <= 0 ) ) )
195                     {
196                         expr = "null";
197                     }
198 
199                     // System.out.println("astadd child class: " + _children[i].getClass().getName() +
200                     // " and return expr: " + expr);
201 
202                     if ( ASTProperty.class.isInstance( children[i] ) )
203                     {
204                         expr = ExpressionCompiler.getRootExpression( children[i], context.getRoot(), context ) + expr;
205                         context.setCurrentAccessor( context.getRoot().getClass() );
206                     }
207                     else if ( ASTMethod.class.isInstance( children[i] ) )
208                     {
209                         String chain = (String) context.get( "_currentChain" );
210                         String rootExpr =
211                             ExpressionCompiler.getRootExpression( children[i], context.getRoot(), context );
212 
213                         // System.out.println("astadd chains is >>" + chain + "<< and rootExpr is >>" + rootExpr +
214                         // "<<");
215 
216                         // dirty fix for overly aggressive casting dot operations
217                         if ( rootExpr.endsWith( "." ) && chain != null && chain.startsWith( ")." ) )
218                         {
219                             chain = chain.substring( 1, chain.length() );
220                         }
221 
222                         expr = rootExpr + ( chain != null ? chain + "." : "" ) + expr;
223                         context.setCurrentAccessor( context.getRoot().getClass() );
224 
225                     }
226                     else if ( ExpressionNode.class.isInstance( children[i] ) )
227                     {
228                         expr = "(" + expr + ")";
229                     }
230                     else if ( ( parent == null || !ASTChain.class.isInstance( parent ) )
231                         && ASTChain.class.isInstance( children[i] ) )
232                     {
233                         String rootExpr =
234                             ExpressionCompiler.getRootExpression( children[i], context.getRoot(), context );
235 
236                         if ( !ASTProperty.class.isInstance( children[i].jjtGetChild( 0 ) ) && rootExpr.endsWith( ")" )
237                             && expr.startsWith( ")" ) )
238                         {
239                             expr = expr.substring( 1, expr.length() );
240                         }
241 
242                         expr = rootExpr + expr;
243                         context.setCurrentAccessor( context.getRoot().getClass() );
244 
245                         String cast = (String) context.remove( ExpressionCompiler.PRE_CAST );
246                         if ( cast == null )
247                         {
248                             cast = "";
249                         }
250 
251                         expr = cast + expr;
252                     }
253 
254                     // turn quoted characters into quoted strings
255 
256                     if ( context.getCurrentType() != null && context.getCurrentType() == Character.class
257                         && ASTConst.class.isInstance( children[i] ) )
258                     {
259                         expr = expr.replaceAll( "'", "\"" );
260                         context.setCurrentType( String.class );
261                     }
262                     else
263                     {
264 
265                         if ( !ASTVarRef.class.isAssignableFrom( children[i].getClass() )
266                             && !ASTProperty.class.isInstance( children[i] )
267                             && !ASTMethod.class.isInstance( children[i] )
268                             && !ASTSequence.class.isInstance( children[i] )
269                             && !ASTChain.class.isInstance( children[i] )
270                             && !NumericExpression.class.isAssignableFrom( children[i].getClass() )
271                             && !ASTStaticField.class.isInstance( children[i] )
272                             && !ASTStaticMethod.class.isInstance( children[i] )
273                             && !ASTTest.class.isInstance( children[i] ) )
274                         {
275                             if ( lastType != null && String.class.isAssignableFrom( lastType.getGetterClass() ) )
276                             {
277                                 // System.out.println("Input expr >>" + expr + "<<");
278                                 expr = expr.replaceAll( "&quot;", "\"" );
279                                 expr = expr.replaceAll( "\"", "'" );
280                                 expr = "\"" + expr + "\"";
281                                 // System.out.println("Expr now >>" + expr + "<<");
282                             }
283                         }
284                     }
285 
286                     result += expr;
287 
288                     // hanlde addition for numeric types when applicable or just string concatenation
289 
290                     if ( ( lastType == null || !String.class.isAssignableFrom( lastType.getGetterClass() ) )
291                         && !ASTConst.class.isAssignableFrom( children[i].getClass() )
292                         && !NumericExpression.class.isAssignableFrom( children[i].getClass() ) )
293                     {
294                         if ( context.getCurrentType() != null
295                             && Number.class.isAssignableFrom( context.getCurrentType() )
296                             && !ASTMethod.class.isInstance( children[i] ) )
297                         {
298                             if ( ASTVarRef.class.isInstance( children[i] )
299                                 || ASTProperty.class.isInstance( children[i] )
300                                 || ASTChain.class.isInstance( children[i] ) )
301                             {
302                                 result += ".";
303                             }
304 
305                             result += OgnlRuntime.getNumericValueGetter( context.getCurrentType() );
306                             context.setCurrentType( OgnlRuntime.getPrimitiveWrapperClass( context.getCurrentType() ) );
307                         }
308                     }
309 
310                     if ( lastType != null )
311                     {
312                         context.setCurrentAccessor( lastType.getGetterClass() );
313                     }
314                 }
315             }
316 
317             if ( parent == null || ASTSequence.class.isAssignableFrom( parent.getClass() ) )
318             {
319                 if ( getterClass != null && String.class.isAssignableFrom( getterClass ) )
320                 {
321                     getterClass = Object.class;
322                 }
323             }
324             else
325             {
326                 context.setCurrentType( getterClass );
327             }
328 
329             try
330             {
331                 Object contextObj = getValueBody( context, target );
332                 context.setCurrentObject( contextObj );
333             }
334             catch ( Throwable t )
335             {
336                 throw OgnlOps.castToRuntime( t );
337             }
338 
339             return result;
340 
341         }
342         catch ( Throwable t )
343         {
344             throw OgnlOps.castToRuntime( t );
345         }
346     }
347     
348     public <R, P> R accept( NodeVisitor<? extends R, ? super P> visitor, P data )
349         throws OgnlException
350     {
351         return visitor.visit( this, data );
352     }
353 }