/* * 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.shale.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.4 */ 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"); } // Is the specified value type-compatible already? if ((object != null) && targetType.isAssignableFrom(object.getClass())) { return object; } // 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 MockValueExpression(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); } }