/* Copyright 2008-2010 Gephi Authors : Martin Škurla <bujacik@gmail.com>, Mathieu Bastian <mathieu.bastian@gephi.org> Website : http://www.gephi.org This file is part of Gephi. Gephi is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Gephi is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with Gephi. If not, see <http://www.gnu.org/licenses/>. */ package org.gephi.data.attributes.type; import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import org.gephi.data.attributes.api.AttributeType; /** * Class responsible for type manipulation and creation needed in Attributes API. * * @author Martin Škurla * @author Mathieu Bastian */ public final class TypeConvertor { private static final String CONVERSION_METHOD_NAME = "valueOf"; private TypeConvertor() { } /** * Creates array of given type from single String value. String value is always parsed by given * separator into smaller chunks. Every chunk will represent independent object in final array. * The exact conversion process from String value into final type is done by * {@link #createInstanceFromString createInstanceFromString} method. * * @param <T> type parameter representing final array type * @param input input * @param separator separator which will be used in the process of tokenizing input * @param finalType type of final array * * @return final array * * @throws NullPointerException if any of given parameters is null * @throws IllegalArgumentException if array of given type cannot be created * * @see #createInstanceFromString createInstanceFromString */ @SuppressWarnings("unchecked") public static <T> T[] createArrayFromString(String input, String separator, Class<T> finalType) { if (input == null || separator == null || finalType == null) { throw new NullPointerException(); } String[] stringValues = input.split(separator); T[] resultList = (T[]) Array.newInstance(finalType, stringValues.length); for (int i = 0; i < stringValues.length; i++) { String stringValue = stringValues[i].trim(); T resultValue = null; if (finalType == String.class) { resultValue = (T) stringValue; } else { resultValue = TypeConvertor.<T>createInstanceFromString(stringValue, finalType); } resultList[i] = resultValue; } return resultList; } /** * Transforms String value to any kind of object with given type. The concrete conversion * must be done by the type itself. This assumes, that given type defines at least one of the * following: * <ul> * <li>public constructor with single parameter of type String * <li>factory method "valueOf" with single parameter of type String<br /> * If given type does not definy any of these requirements, IllegalArgumentException will be * thrown. * * @param <T> type parameter representing final type * @param input input * @param finalType type of final object * * @return final object * * @throws NullPointerException if any of given parameters is null * @throws IllegalArgumentException if given type cannot be created */ @SuppressWarnings("unchecked") public static <T> T createInstanceFromString(String input, Class<T> finalType) { if (input == null || finalType == null) { throw new NullPointerException(); } T resultValue = null; try { Method conversionMethod = finalType.getMethod(CONVERSION_METHOD_NAME, String.class); resultValue = (T) conversionMethod.invoke(null, input); } catch (NoSuchMethodException e) { try { Constructor<T> constructor = finalType.getConstructor(String.class); resultValue = constructor.newInstance(input); } catch (NoSuchMethodException e1) { String errorMessage = String.format( "Type '%s' does not have neither method 'T %s(String)' nor constructor '<init>(String)'...", finalType, CONVERSION_METHOD_NAME); throw new IllegalArgumentException(errorMessage); } catch (Exception e2) { } } catch (Exception e) { } return resultValue; } /** * Converts given array of primitive type into array of wrapper type. * * @param <T> type parameter representing final wrapper type * @param primitiveArray primitive array * * @return wrapper array * * @throws NullPointerException if given parameter is null * @throws IllegalArgumentException if given parameter is not array or given parameter is not * array of primitive type */ @SuppressWarnings("unchecked") public static <T> T[] convertPrimitiveToWrapperArray(Object primitiveArray) { if (primitiveArray == null) { throw new NullPointerException(); } if (!primitiveArray.getClass().isArray()) { throw new IllegalArgumentException("Given object is not of primitive array: " + primitiveArray.getClass()); } Class<?> primitiveClass = primitiveArray.getClass().getComponentType(); Class<T> wrapperClass = (Class<T>) getWrapperFromPrimitive(primitiveClass); int arrayLength = Array.getLength(primitiveArray); T[] wrapperArray = (T[]) Array.newInstance(wrapperClass, arrayLength); for (int i = 0; i < arrayLength; i++) { T arrayItem = (T) Array.get(primitiveArray, i); wrapperArray[i] = arrayItem; } return wrapperArray; } /** * Returns wrapper type from given primitive type. * * @param primitiveType primitive type * * @return wrapper type * * @throws NullPointerException if given parameter is null * @throws IllegalArgumentException if given parameter is not a primitive type */ public static Class<?> getWrapperFromPrimitive(Class<?> primitiveType) { if (primitiveType == null) { throw new NullPointerException(); } if (primitiveType == byte.class) { return Byte.class; } else if (primitiveType == short.class) { return Short.class; } else if (primitiveType == int.class) { return Integer.class; } else if (primitiveType == long.class) { return Long.class; } else if (primitiveType == float.class) { return Float.class; } else if (primitiveType == double.class) { return Double.class; } else if (primitiveType == boolean.class) { return Boolean.class; } else if (primitiveType == char.class) { return Character.class; } throw new IllegalArgumentException("Given type '" + primitiveType + "' is not primitive..."); } /** * Returns the underlying static type from <code>dynamicType</code> For example * returns <code>FLOAT</code> if given type is <code>DYNAMIC_FLOAT</code>. * @param dynamicType a dynamic type * @return the underlying static type * @throws IllegalArgumentException if <code>dynamicType</code> is not dynamic */ public static AttributeType getStaticType(AttributeType dynamicType) { if (!dynamicType.isDynamicType()) { throw new IllegalArgumentException("Given type '" + dynamicType + "' is not dynamic."); } switch (dynamicType) { case DYNAMIC_BIGDECIMAL: return AttributeType.BIGDECIMAL; case DYNAMIC_BIGINTEGER: return AttributeType.BIGINTEGER; case DYNAMIC_BOOLEAN: return AttributeType.BOOLEAN; case DYNAMIC_BYTE: return AttributeType.BYTE; case DYNAMIC_CHAR: return AttributeType.CHAR; case DYNAMIC_DOUBLE: return AttributeType.DOUBLE; case DYNAMIC_FLOAT: return AttributeType.FLOAT; case DYNAMIC_INT: return AttributeType.INT; case DYNAMIC_LONG: return AttributeType.LONG; case DYNAMIC_SHORT: return AttributeType.SHORT; case DYNAMIC_STRING: return AttributeType.STRING; default: return null; } } /** * Returns the corresponding dynamic type from <code>staticType</code> For example * returns <code>DYNAMIC_FLOAT</code> if given type is <code>FLOAT</code>. * @param staticType a static type * @return the corresponding dynamic type * @throws IllegalArgumentException if <code>staticType</code> is not static */ public static AttributeType getDynamicType(AttributeType staticType) { if (staticType.isDynamicType()) { throw new IllegalArgumentException("Given type '" + staticType + "' is not static."); } switch (staticType) { case BIGDECIMAL: return AttributeType.DYNAMIC_BIGDECIMAL; case BIGINTEGER: return AttributeType.DYNAMIC_BIGINTEGER; case BOOLEAN: return AttributeType.DYNAMIC_BOOLEAN; case BYTE: return AttributeType.DYNAMIC_BYTE; case CHAR: return AttributeType.DYNAMIC_CHAR; case DOUBLE: return AttributeType.DYNAMIC_DOUBLE; case FLOAT: return AttributeType.DYNAMIC_FLOAT; case INT: return AttributeType.DYNAMIC_INT; case LONG: return AttributeType.DYNAMIC_LONG; case SHORT: return AttributeType.DYNAMIC_SHORT; case STRING: return AttributeType.DYNAMIC_STRING; default: return null; } } }