blob: 950c9de902ac27698af3df74823199a6cb719e2b [file] [log] [blame]
package org.apache.commons.ognl;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import org.apache.commons.ognl.enhance.ExpressionCompiler;
import java.math.BigDecimal;
import java.math.BigInteger;
import static java.lang.String.format;
/**
* $Id$
*/
class ASTAdd
extends NumericExpression
{
public ASTAdd( int id )
{
super( id );
}
public ASTAdd( OgnlParser p, int id )
{
super( p, id );
}
public void jjtClose()
{
flattenTree();
}
protected Object getValueBody( OgnlContext context, Object source )
throws OgnlException
{
Object result = children[0].getValue( context, source );
for ( int i = 1; i < children.length; ++i )
{
result = OgnlOps.add( result, children[i].getValue( context, source ) );
}
return result;
}
public String getExpressionOperator( int index )
{
return "+";
}
boolean isWider( NodeType type, NodeType lastType )
{
if ( lastType == null )
{
return true;
}
// System.out.println("checking isWider(" + type.getGetterClass() + " , " + lastType.getGetterClass() + ")");
if ( String.class.isAssignableFrom( lastType.getGetterClass() ) )
{
return false;
}
if ( String.class.isAssignableFrom( type.getGetterClass() ) )
{
return true;
}
if ( parent != null && String.class.isAssignableFrom( type.getGetterClass() ) )
{
return true;
}
if ( String.class.isAssignableFrom( lastType.getGetterClass() ) && Object.class == type.getGetterClass() )
{
return false;
}
if ( parent != null && String.class.isAssignableFrom( lastType.getGetterClass() ) )
{
return false;
}
if ( parent == null && String.class.isAssignableFrom( lastType.getGetterClass() ) )
{
return true;
}
if ( parent == null && String.class.isAssignableFrom( type.getGetterClass() ) )
{
return false;
}
if ( BigDecimal.class.isAssignableFrom( type.getGetterClass() )
|| BigInteger.class.isAssignableFrom( type.getGetterClass() ) )
{
return true;
}
if ( BigDecimal.class.isAssignableFrom( lastType.getGetterClass() )
|| BigInteger.class.isAssignableFrom( lastType.getGetterClass() ) )
{
return false;
}
if ( Double.class.isAssignableFrom( type.getGetterClass() ) )
{
return true;
}
if ( Integer.class.isAssignableFrom( type.getGetterClass() )
&& Double.class.isAssignableFrom( lastType.getGetterClass() ) )
{
return false;
}
if ( Float.class.isAssignableFrom( type.getGetterClass() )
&& Integer.class.isAssignableFrom( lastType.getGetterClass() ) )
{
return true;
}
return true;
}
public String toGetSourceString( OgnlContext context, Object target )
{
try
{
StringBuilder result = new StringBuilder();
NodeType lastType = null;
// go through once to determine the ultimate type
if ( ( children != null ) && ( children.length > 0 ) )
{
Class currType = context.getCurrentType();
Class currAccessor = context.getCurrentAccessor();
Object cast = context.get( ExpressionCompiler.PRE_CAST );
for ( Node aChildren : children )
{
aChildren.toGetSourceString( context, target );
if ( NodeType.class.isInstance( aChildren ) && ( (NodeType) aChildren ).getGetterClass() != null
&& isWider( (NodeType) aChildren, lastType ) )
{
lastType = (NodeType) aChildren;
}
}
context.put( ExpressionCompiler.PRE_CAST, cast );
context.setCurrentType( currType );
context.setCurrentAccessor( currAccessor );
}
// reset context since previous children loop would have changed it
context.setCurrentObject( target );
if ( ( children != null ) && ( children.length > 0 ) )
{
for ( int i = 0; i < children.length; ++i )
{
if ( i > 0 )
{
result.append(" ").append(getExpressionOperator(i)).append(" ");
}
String expr = children[i].toGetSourceString( context, target );
if ( ( "null".equals( expr ) )
|| ( !ASTConst.class.isInstance( children[i] )
&& ( expr == null || expr.trim().isEmpty() ) ) )
{
expr = "null";
}
// System.out.println("astadd child class: " + _children[i].getClass().getName() +
// " and return expr: " + expr);
if ( ASTProperty.class.isInstance( children[i] ) )
{
expr = ExpressionCompiler.getRootExpression( children[i], context.getRoot(), context ) + expr;
context.setCurrentAccessor( context.getRoot().getClass() );
}
else if ( ASTMethod.class.isInstance( children[i] ) )
{
String chain = (String) context.get( "_currentChain" );
String rootExpr =
ExpressionCompiler.getRootExpression( children[i], context.getRoot(), context );
// System.out.println("astadd chains is >>" + chain + "<< and rootExpr is >>" + rootExpr +
// "<<");
// dirty fix for overly aggressive casting dot operations
if ( rootExpr.endsWith( "." ) && chain != null && chain.startsWith( ")." ) )
{
chain = chain.substring( 1 );
}
expr = rootExpr + ( chain != null ? chain + "." : "" ) + expr;
context.setCurrentAccessor( context.getRoot().getClass() );
}
else if ( ExpressionNode.class.isInstance( children[i] ) )
{
expr = "(" + expr + ")";
}
else if ( ( parent == null || !ASTChain.class.isInstance( parent ) )
&& ASTChain.class.isInstance( children[i] ) )
{
String rootExpr =
ExpressionCompiler.getRootExpression( children[i], context.getRoot(), context );
if ( !ASTProperty.class.isInstance( children[i].jjtGetChild( 0 ) ) && rootExpr.endsWith( ")" )
&& expr.startsWith( ")" ) )
{
expr = expr.substring( 1 );
}
expr = rootExpr + expr;
context.setCurrentAccessor( context.getRoot().getClass() );
String cast = (String) context.remove( ExpressionCompiler.PRE_CAST );
if ( cast == null )
{
cast = "";
}
expr = cast + expr;
}
// turn quoted characters into quoted strings
if ( context.getCurrentType() != null && context.getCurrentType() == Character.class
&& ASTConst.class.isInstance( children[i] ) )
{
expr = expr.replace( "'", "\"" );
context.setCurrentType( String.class );
}
else
{
if ( !ASTVarRef.class.isAssignableFrom( children[i].getClass() )
&& !ASTProperty.class.isInstance( children[i] )
&& !ASTMethod.class.isInstance( children[i] )
&& !ASTSequence.class.isInstance( children[i] )
&& !ASTChain.class.isInstance( children[i] )
&& !NumericExpression.class.isAssignableFrom( children[i].getClass() )
&& !ASTStaticField.class.isInstance( children[i] )
&& !ASTStaticMethod.class.isInstance( children[i] )
&& !ASTTest.class.isInstance( children[i] ) )
{
if ( lastType != null && String.class.isAssignableFrom( lastType.getGetterClass() ) )
{
// System.out.println("Input expr >>" + expr + "<<");
expr = expr.replace( "&quot;", "\"" );
expr = expr.replace( "\"", "'" );
expr = format( "\"%s\"", expr );
// System.out.println("Expr now >>" + expr + "<<");
}
}
}
result.append(expr);
// hanlde addition for numeric types when applicable or just string concatenation
if ( ( lastType == null || !String.class.isAssignableFrom( lastType.getGetterClass() ) )
&& !ASTConst.class.isAssignableFrom( children[i].getClass() )
&& !NumericExpression.class.isAssignableFrom( children[i].getClass() ) )
{
if ( context.getCurrentType() != null
&& Number.class.isAssignableFrom( context.getCurrentType() )
&& !ASTMethod.class.isInstance( children[i] ) )
{
if ( ASTVarRef.class.isInstance( children[i] )
|| ASTProperty.class.isInstance( children[i] )
|| ASTChain.class.isInstance( children[i] ) )
{
result.append(".");
}
result.append(OgnlRuntime.getNumericValueGetter(context.getCurrentType()));
context.setCurrentType( OgnlRuntime.getPrimitiveWrapperClass( context.getCurrentType() ) );
}
}
if ( lastType != null )
{
context.setCurrentAccessor( lastType.getGetterClass() );
}
}
}
if ( parent == null || ASTSequence.class.isAssignableFrom( parent.getClass() ) )
{
if ( getterClass != null && String.class.isAssignableFrom( getterClass ) )
{
getterClass = Object.class;
}
}
else
{
context.setCurrentType( getterClass );
}
try
{
Object contextObj = getValueBody( context, target );
context.setCurrentObject( contextObj );
}
catch ( Throwable t )
{
throw OgnlOps.castToRuntime( t );
}
return result.toString();
}
catch ( Throwable t )
{
throw OgnlOps.castToRuntime( t );
}
}
public <R, P> R accept( NodeVisitor<? extends R, ? super P> visitor, P data )
throws OgnlException
{
return visitor.visit( this, data );
}
}