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    /**
025     * Base class for numeric expressions.
026     */
027    public abstract class NumericExpression
028        extends ExpressionNode
029        implements NodeType
030    {
031    
032        private static final long serialVersionUID = -174952564587478850L;
033    
034        protected Class<?> getterClass;
035    
036        public NumericExpression( int id )
037        {
038            super( id );
039        }
040    
041        public NumericExpression( OgnlParser p, int id )
042        {
043            super( p, id );
044        }
045    
046        /**
047         * {@inheritDoc}
048         */
049        public Class<?> getGetterClass()
050        {
051            if ( getterClass != null )
052            {
053                return getterClass;
054            }
055    
056            return Double.TYPE;
057        }
058    
059        /**
060         * {@inheritDoc}
061         */
062        public Class<?> getSetterClass()
063        {
064            return null;
065        }
066    
067        /**
068         * {@inheritDoc}
069         */
070        @Override
071        public String toGetSourceString( OgnlContext context, Object target )
072        {
073            Object value;
074            StringBuilder result = new StringBuilder( "" );
075    
076            try
077            {
078    
079                value = getValueBody( context, target );
080    
081                if ( value != null )
082                {
083                    getterClass = value.getClass();
084                }
085    
086                for ( int i = 0; i < children.length; i++ )
087                {
088                    if ( i > 0 )
089                    {
090                        result.append( " " ).append( getExpressionOperator( i ) ).append( " " );
091                    }
092                    String str = OgnlRuntime.getChildSource( context, target, children[i] );
093    
094                    result.append( coerceToNumeric( str, context, children[i] ) );
095                }
096    
097            }
098            catch ( Throwable t )
099            {
100                throw OgnlOps.castToRuntime( t );
101            }
102    
103            return result.toString();
104        }
105    
106        public String coerceToNumeric( String source, OgnlContext context, Node child )
107        {
108            StringBuilder ret = new StringBuilder( source );
109            Object value = context.getCurrentObject();
110    
111            if ( ASTConst.class.isInstance( child ) && value != null )
112            {
113                return value.toString();
114            }
115    
116            if ( context.getCurrentType() != null && !context.getCurrentType().isPrimitive()
117                && context.getCurrentObject() != null && Number.class.isInstance( context.getCurrentObject() ) )
118            {
119                ret = new StringBuilder( "((" ).append(
120                    ExpressionCompiler.getCastString( context.getCurrentObject().getClass() ) ).append( ")" ).append(
121                    ret ).append( ")." ).append(
122                    OgnlRuntime.getNumericValueGetter( context.getCurrentObject().getClass() ) );
123            }
124            else if ( context.getCurrentType() != null && context.getCurrentType().isPrimitive()
125                && ( ASTConst.class.isInstance( child ) || NumericExpression.class.isInstance( child ) ) )
126            {
127                @SuppressWarnings( "unchecked" ) // checked by the condition in the if clause
128                Class<? extends Number> numberClass = (Class<? extends Number>) context.getCurrentType();
129                ret.append( OgnlRuntime.getNumericLiteral( numberClass ) );
130            }
131            else if ( context.getCurrentType() != null && String.class.isAssignableFrom( context.getCurrentType() ) )
132            {
133                ret = new StringBuilder( "Double.parseDouble(" )
134                    .append( ret )
135                    .append( ")" );
136                context.setCurrentType( Double.TYPE );
137            }
138    
139            if ( NumericExpression.class.isInstance( child ) )
140            {
141                ret = new StringBuilder( "(" ).append( ret ).append( ")" );
142            }
143    
144            return ret.toString();
145        }
146    }