|
Groovy example source code file (DefaultTypeTransformation.java)
The Groovy DefaultTypeTransformation.java source code
/*
* Copyright 2003-2010 the original author or authors.
*
* Licensed 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.codehaus.groovy.runtime.typehandling;
import groovy.lang.GString;
import groovy.lang.GroovyRuntimeException;
import org.codehaus.groovy.reflection.ReflectionCache;
import org.codehaus.groovy.runtime.*;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
/**
* Class providing various type conversions, coercions and boxing/unboxing operations.
*
* @author Guillaume Laforge
*/
public class DefaultTypeTransformation {
protected static final Object[] EMPTY_ARGUMENTS = {};
protected static final BigInteger ONE_NEG = new BigInteger("-1");
// --------------------------------------------------------
// unboxing methods
// --------------------------------------------------------
public static byte byteUnbox(Object value) {
Number n = castToNumber(value, byte.class);
return n.byteValue();
}
public static char charUnbox(Object value) {
return castToChar(value);
}
public static short shortUnbox(Object value) {
Number n = castToNumber(value, short.class);
return n.shortValue();
}
public static int intUnbox(Object value) {
Number n = castToNumber(value, int.class);
return n.intValue();
}
public static boolean booleanUnbox(Object value) {
return castToBoolean(value);
}
public static long longUnbox(Object value) {
Number n = castToNumber(value, long.class);
return n.longValue();
}
public static float floatUnbox(Object value) {
Number n = castToNumber(value, float.class);
return n.floatValue();
}
public static double doubleUnbox(Object value) {
Number n = castToNumber(value, double.class);
return n.doubleValue();
}
// --------------------------------------------------------
// boxing methods
// --------------------------------------------------------
public static Object box(boolean value) {
return value ? Boolean.TRUE : Boolean.FALSE;
}
public static Object box(byte value) {
return Byte.valueOf(value);
}
public static Object box(char value) {
return Character.valueOf(value);
}
public static Object box(short value) {
return Short.valueOf(value);
}
public static Object box(int value) {
return Integer.valueOf(value);
}
public static Object box(long value) {
return Long.valueOf(value);
}
public static Object box(float value) {
return Float.valueOf(value);
}
public static Object box(double value) {
return Double.valueOf(value);
}
public static Number castToNumber(Object object) {
// default to Number class in exception details, else use the specified Number subtype.
return castToNumber(object, Number.class);
}
public static Number castToNumber(Object object, Class type) {
if (object instanceof Number)
return (Number) object;
if (object instanceof Character) {
return Integer.valueOf(((Character) object).charValue());
}
if (object instanceof GString) {
String c = ((GString) object).toString();
if (c.length() == 1) {
return Integer.valueOf(c.charAt(0));
} else {
throw new GroovyCastException(c, type);
}
}
if (object instanceof String) {
String c = (String) object;
if (c.length() == 1) {
return Integer.valueOf(c.charAt(0));
} else {
throw new GroovyCastException(c, type);
}
}
throw new GroovyCastException(object, type);
}
/**
* Method used for coercing an object to a boolean value,
* thanks to an <code>asBoolean() method added on types.
*
* @param object to coerce to a boolean value
* @return a boolean value
*/
public static boolean castToBoolean(Object object) {
// null is always false
if (object == null) {
return false;
}
// if the object is not null, try to call an asBoolean() method on the object
return (Boolean)InvokerHelper.invokeMethod(object, "asBoolean", InvokerHelper.EMPTY_ARGS);
}
public static char castToChar(Object object) {
if (object instanceof Character) {
return ((Character) object).charValue();
} else if (object instanceof Number) {
Number value = (Number) object;
return (char) value.intValue();
} else {
String text = object.toString();
if (text.length() == 1) {
return text.charAt(0);
}
else {
throw new GroovyCastException(text,char.class);
}
}
}
public static Object castToType(Object object, Class type) {
if (object == null) {
return null;
}
if (type == Object.class)
return object;
final Class aClass = object.getClass();
if (type == aClass) return object;
// TODO we should move these methods to groovy method, like g$asType() so that
// we can use operator overloading to customize on a per-type basis
if (ReflectionCache.isArray(type)) {
return asArray(object, type);
}
if (ReflectionCache.isAssignableFrom(type, aClass)) {
return object;
}
if (Collection.class.isAssignableFrom(type)) {
int modifiers = type.getModifiers();
Collection answer;
if (object instanceof Collection && type.isAssignableFrom(HashSet.class) &&
(type == HashSet.class || Modifier.isAbstract(modifiers) || Modifier.isInterface(modifiers))) {
return new HashSet((Collection)object);
}
if (aClass.isArray()) {
if (type.isAssignableFrom(ArrayList.class) && (Modifier.isAbstract(modifiers) || Modifier.isInterface(modifiers))) {
answer = new ArrayList();
} else {
// let's call the collections constructor
// passing in the list wrapper
try {
answer = (Collection) type.newInstance();
}
catch (Exception e) {
throw new GroovyCastException("Could not instantiate instance of: " + type.getName() + ". Reason: " + e);
}
}
// we cannot just wrap in a List as we support primitive type arrays
int length = Array.getLength(object);
for (int i = 0; i < length; i++) {
Object element = Array.get(object, i);
answer.add(element);
}
return answer;
}
}
if (type == String.class) {
return object.toString();
} else if (type == Character.class) {
return box(castToChar(object));
} else if (type == Boolean.class) {
return box(castToBoolean(object));
} else if (type == Class.class) {
return castToClass(object);
} else if (Number.class.isAssignableFrom(type)) {
Number n = castToNumber(object, type);
if (type == Byte.class) {
return new Byte(n.byteValue());
} else if (type == Character.class) {
return new Character((char) n.intValue());
} else if (type == Short.class) {
return new Short(n.shortValue());
} else if (type == Integer.class) {
return Integer.valueOf(n.intValue());
} else if (type == Long.class) {
return new Long(n.longValue());
} else if (type == Float.class) {
return new Float(n.floatValue());
} else if (type == Double.class) {
Double answer = new Double(n.doubleValue());
//throw a runtime exception if conversion would be out-of-range for the type.
if (!(n instanceof Double) && (answer.doubleValue() == Double.NEGATIVE_INFINITY
|| answer.doubleValue() == Double.POSITIVE_INFINITY)) {
throw new GroovyRuntimeException("Automatic coercion of " + n.getClass().getName()
+ " value " + n + " to double failed. Value is out of range.");
}
return answer;
} else if (type == BigDecimal.class) {
if (n instanceof Float || n instanceof Double) {
return new BigDecimal(n.doubleValue());
}
return new BigDecimal(n.toString());
} else if (type == BigInteger.class) {
if (object instanceof Float || object instanceof Double) {
BigDecimal bd = new BigDecimal(n.doubleValue());
return bd.toBigInteger();
} else if (object instanceof BigDecimal) {
return ((BigDecimal) object).toBigInteger();
} else {
return new BigInteger(n.toString());
}
}
} else if (type.isPrimitive()) {
if (type == boolean.class) {
return box(booleanUnbox(object));
} else if (type == byte.class) {
return box(byteUnbox(object));
} else if (type == char.class) {
return box(charUnbox(object));
} else if (type == short.class) {
return box(shortUnbox(object));
} else if (type == int.class) {
return box(intUnbox(object));
} else if (type == long.class) {
return box(longUnbox(object));
} else if (type == float.class) {
return box(floatUnbox(object));
} else if (type == double.class) {
Double answer = new Double(doubleUnbox(object));
//throw a runtime exception if conversion would be out-of-range for the type.
if (!(object instanceof Double) && (answer.doubleValue() == Double.NEGATIVE_INFINITY
|| answer.doubleValue() == Double.POSITIVE_INFINITY)) {
throw new GroovyRuntimeException("Automatic coercion of " + aClass.getName()
+ " value " + object + " to double failed. Value is out of range.");
}
return answer;
}
} else if (object instanceof String && type.isEnum()) {
return Enum.valueOf(type, (String) object);
} else if (object instanceof GString && type.isEnum()) {
return Enum.valueOf(type, object.toString());
}
Object[] args = null;
if (object instanceof Collection) {
// let's try invoke the constructor with the list as arguments
// such as for creating a Dimension, Point, Color etc.
Collection collection = (Collection) object;
args = collection.toArray();
} else if (object instanceof Object[]) {
args = (Object[]) object;
} else if (object instanceof Map) {
// emulate named params constructor
args = new Object[1];
args[0] = object;
}
Exception nested = null;
if (args != null) {
try {
return InvokerHelper.invokeConstructorOf(type, args);
} catch (InvokerInvocationException iie){
throw iie;
} catch (Exception e) {
// let's ignore exception and return the original object
// as the caller has more context to be able to throw a more
// meaningful exception (but stash to get message later)
nested = e;
}
}
GroovyCastException gce;
if (nested != null) {
gce = new GroovyCastException(object, type, nested);
} else {
gce = new GroovyCastException(object, type);
}
throw gce;
}
private static Class castToClass(Object object) {
try {
return Class.forName(object.toString());
} catch (Exception e) {
throw new GroovyCastException(object, Class.class, e);
}
}
public static Object asArray(Object object, Class type) {
if (type.isAssignableFrom(object.getClass())) {
return object;
}
Collection list = asCollection(object);
int size = list.size();
Class elementType = type.getComponentType();
Object array = Array.newInstance(elementType, size);
int idx = 0;
if (boolean.class.equals(elementType)) {
for (Iterator iter = list.iterator(); iter.hasNext(); idx++) {
Object element = iter.next();
Array.setBoolean(array, idx, booleanUnbox(element));
}
}
else if (byte.class.equals(elementType)) {
for (Iterator iter = list.iterator(); iter.hasNext(); idx++) {
Object element = iter.next();
Array.setByte(array, idx, byteUnbox(element));
}
}
else if (char.class.equals(elementType)) {
for (Iterator iter = list.iterator(); iter.hasNext(); idx++) {
Object element = iter.next();
Array.setChar(array, idx, charUnbox(element));
}
}
else if (double.class.equals(elementType)) {
for (Iterator iter = list.iterator(); iter.hasNext(); idx++) {
Object element = iter.next();
Array.setDouble(array, idx, doubleUnbox(element));
}
}
else if (float.class.equals(elementType)) {
for (Iterator iter = list.iterator(); iter.hasNext(); idx++) {
Object element = iter.next();
Array.setFloat(array, idx, floatUnbox(element));
}
}
else if (int.class.equals(elementType)) {
for (Iterator iter = list.iterator(); iter.hasNext(); idx++) {
Object element = iter.next();
Array.setInt(array, idx, intUnbox(element));
}
}
else if (long.class.equals(elementType)) {
for (Iterator iter = list.iterator(); iter.hasNext(); idx++) {
Object element = iter.next();
Array.setLong(array, idx, longUnbox(element));
}
}
else if (short.class.equals(elementType)) {
for (Iterator iter = list.iterator(); iter.hasNext(); idx++) {
Object element = iter.next();
Array.setShort(array, idx, shortUnbox(element));
}
}
else {
for (Iterator iter = list.iterator(); iter.hasNext(); idx++) {
Object element = iter.next();
Object coercedElement = castToType(element, elementType);
Array.set(array, idx, coercedElement);
}
}
return array;
}
public static <T> Collection
Other Groovy examples (source code examples)Here is a short list of links related to this Groovy DefaultTypeTransformation.java source code file: |
Other websites by Alvin Alexander:
Life/living in Alaska (OneMansAlaska.com)
How I Sold My Business (HowISoldMyBusiness.com)
Copyright 1998-2011 Alvin Alexander, devdaily.com
All Rights Reserved.