blob: 34e5c74da2d34363bb81687c6526892e1cd02a85 [file] [log] [blame]
/*
* 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.
*/
package org.apache.myfaces.test.el;
import java.math.BigDecimal;
import java.math.BigInteger;
import javax.el.ELContext;
import javax.el.ExpressionFactory;
import javax.el.MethodExpression;
import javax.el.ValueExpression;
/**
* <p>Mock implementation of <code>ExpressionFactory</code>.</p>
*
* @since 1.0.0
*/
public class MockExpressionFactory extends ExpressionFactory
{
// ------------------------------------------------------------ Constructors
/** Creates a new instance of MockExpressionFactory */
public MockExpressionFactory()
{
}
// ------------------------------------------------------ Instance Variables
/**
* <p>Literal numeric value for zero.</p>
*/
private static final Integer ZERO = new Integer(0);
// ----------------------------------------------------- Mock Object Methods
// ----------------------------------------------- ExpressionFactory Methods
/** {@inheritDoc} */
public Object coerceToType(Object object, Class targetType)
{
// Check for no conversion necessary
if ((targetType == null) || Object.class.equals(targetType))
{
return object;
}
// Coerce to String if appropriate
if (String.class.equals(targetType))
{
if (object == null)
{
return "";
}
else if (object instanceof String)
{
return (String) object;
}
else
{
return object.toString();
}
}
// Coerce to Number (or a subclass of Number) if appropriate
if (isNumeric(targetType))
{
if (object == null)
{
return coerce(ZERO, targetType);
}
else if ("".equals(object))
{
return coerce(ZERO, targetType);
}
else if (object instanceof String)
{
return coerce((String) object, targetType);
}
else if (isNumeric(object.getClass()))
{
return coerce((Number) object, targetType);
}
throw new IllegalArgumentException("Cannot convert " + object
+ " to Number");
}
// Coerce to Boolean if appropriate
if (Boolean.class.equals(targetType) || (Boolean.TYPE == targetType))
{
if (object == null)
{
return Boolean.FALSE;
}
else if ("".equals(object))
{
return Boolean.FALSE;
}
else if ((object instanceof Boolean)
|| (object.getClass() == Boolean.TYPE))
{
return (Boolean) object;
}
else if (object instanceof String)
{
return Boolean.valueOf((String) object);
}
throw new IllegalArgumentException("Cannot convert " + object
+ " to Boolean");
}
// Coerce to Character if appropriate
if (Character.class.equals(targetType)
|| (Character.TYPE == targetType))
{
if (object == null)
{
return new Character((char) 0);
}
else if ("".equals(object))
{
return new Character((char) 0);
}
else if (object instanceof String)
{
return new Character(((String) object).charAt(0));
}
else if (isNumeric(object.getClass()))
{
return new Character((char) ((Number) object).shortValue());
}
else if ((object instanceof Character)
|| (object.getClass() == Character.TYPE))
{
return (Character) object;
}
throw new IllegalArgumentException("Cannot convert " + object
+ " to Character");
}
if (targetType.isEnum())
{
if (object == null || "".equals(object))
{
return null;
}
if (targetType.isAssignableFrom(object.getClass()))
{
return (Enum) object;
}
if (!(object instanceof String))
{
throw new IllegalArgumentException("Cannot convert " + object + " to Enum");
}
Enum<?> result;
try
{
result = Enum.valueOf(targetType, (String) object);
return result;
}
catch (IllegalArgumentException iae)
{
throw new IllegalArgumentException("Cannot convert " + object + " to Enum");
}
}
// Is the specified value type-compatible already?
if ((object != null) && targetType.isAssignableFrom(object.getClass()))
{
return object;
}
// new to spec
if (object == null)
{
return null;
}
// We do not know how to perform this conversion
throw new IllegalArgumentException("Cannot convert " + object + " to "
+ targetType.getName());
}
/** {@inheritDoc} */
public MethodExpression createMethodExpression(ELContext context,
String expression, Class expectedType, Class[] signature)
{
return new MockMethodExpression(expression, signature, expectedType);
}
/** {@inheritDoc} */
public ValueExpression createValueExpression(ELContext context,
String expression, Class expectedType)
{
return new MockCompositeValueExpression(expression, expectedType);
}
/** {@inheritDoc} */
public ValueExpression createValueExpression(Object instance,
Class expectedType)
{
return new MockVariableValueExpression(instance, expectedType);
}
// --------------------------------------------------------- Private Methods
/**
* <p>Coerce the specified value to the specified Number subclass.</p>
*
* @param value Value to be coerced
* @param type Destination type
*/
private Number coerce(Number value, Class type)
{
if ((type == Byte.TYPE) || (type == Byte.class))
{
return new Byte(value.byteValue());
}
else if ((type == Double.TYPE) || (type == Double.class))
{
return new Double(value.doubleValue());
}
else if ((type == Float.TYPE) || (type == Float.class))
{
return new Float(value.floatValue());
}
else if ((type == Integer.TYPE) || (type == Integer.class))
{
return new Integer(value.intValue());
}
else if ((type == Long.TYPE) || (type == Long.class))
{
return new Long(value.longValue());
}
else if ((type == Short.TYPE) || (type == Short.class))
{
return new Short(value.shortValue());
}
else if (type == BigDecimal.class)
{
if (value instanceof BigDecimal)
{
return (BigDecimal) value;
}
else if (value instanceof BigInteger)
{
return new BigDecimal((BigInteger) value);
}
else
{
return new BigDecimal(((Number) value).doubleValue());
}
}
else if (type == BigInteger.class)
{
if (value instanceof BigInteger)
{
return (BigInteger) value;
}
else if (value instanceof BigDecimal)
{
return ((BigDecimal) value).toBigInteger();
}
else
{
return BigInteger.valueOf(((Number) value).longValue());
}
}
throw new IllegalArgumentException("Cannot convert " + value + " to "
+ type.getName());
}
/**
* <p>Coerce the specified value to the specified Number subclass.</p>
*
* @param value Value to be coerced
* @param type Destination type
*/
private Number coerce(String value, Class type)
{
if ((type == Byte.TYPE) || (type == Byte.class))
{
return Byte.valueOf(value);
}
else if ((type == Double.TYPE) || (type == Double.class))
{
return Double.valueOf(value);
}
else if ((type == Float.TYPE) || (type == Float.class))
{
return Float.valueOf(value);
}
else if ((type == Integer.TYPE) || (type == Integer.class))
{
return Integer.valueOf(value);
}
else if ((type == Long.TYPE) || (type == Long.class))
{
return Long.valueOf(value);
}
else if ((type == Short.TYPE) || (type == Short.class))
{
return Short.valueOf(value);
}
else if (type == BigDecimal.class)
{
return new BigDecimal(value);
}
else if (type == BigInteger.class)
{
return new BigInteger(value);
}
throw new IllegalArgumentException("Cannot convert " + value + " to "
+ type.getName());
}
/**
* <p>Return <code>true</code> if the specified type is numeric.</p>
*
* @param type Type to check
*/
private boolean isNumeric(Class type)
{
return (type == Byte.TYPE) || (type == Byte.class)
|| (type == Double.TYPE) || (type == Double.class)
|| (type == Float.TYPE) || (type == Float.class)
|| (type == Integer.TYPE) || (type == Integer.class)
|| (type == Long.TYPE) || (type == Long.class)
|| (type == Short.TYPE) || (type == Short.class)
|| (type == BigDecimal.class) || (type == BigInteger.class);
}
}