/*******************************************************************************
* Copyright 2012 Geoscience Australia
*
* 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 au.gov.ga.earthsci.common.util;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
/**
* Helper class which contains methods for instantiating objects from strings
* (when supported). Supported objects are boxed primitives, as well as objects
* that have a single-parameter constructor which takes a {@link String}.
*
* @author Michael de Hoog (michael.dehoog@ga.gov.au)
*/
public class StringInstantiable
{
/**
* Is the given class able to be instantiated from a string?
*
* @param c
* Class to test
* @return True if the given class is able to be instantiated from a string.
*/
public static boolean isInstantiable(Class<?> c)
{
if (c == null)
{
return false;
}
if (c.isPrimitive())
{
return true;
}
if (c.isAssignableFrom(Character.class))
{
//the Character class doesn't have a String constructor
return true;
}
try
{
//can the class be constructed from a String?
c.getDeclaredConstructor(String.class); //throws exception if not found
return true;
}
catch (Exception e)
{
}
try
{
//can the class be constructed from a static "fromString" method?
Method method = c.getDeclaredMethod("fromString", String.class); //$NON-NLS-1$
if (Modifier.isStatic(method.getModifiers()) && c.isAssignableFrom(method.getReturnType()))
{
return true;
}
}
catch (Exception e)
{
}
return false;
}
/**
* Convert the given object to a string. If the object is of a type that
* doesn't support instantiation by this class (ie
* {@link #isInstantiable(Class)} returns false), this method will return
* null.
*
* @param o
* @return Object converted to a string.
*/
public static String toString(Object o)
{
if (o == null)
{
return null;
}
if (!isInstantiable(o.getClass()))
{
return null;
}
return o.toString();
}
/**
* Convert the given string to an instance of the provided type. Will return
* null if the given type doesn't support instantiation by this class (ie
* {@link #isInstantiable(Class)} returns false).
*
* @param s
* @param type
* @return String converted to an instance of the given type.
*/
@SuppressWarnings("unchecked")
public static <E> E newInstance(String s, Class<E> type)
{
if (s == null)
{
return null;
}
if (type.isPrimitive())
{
type = (Class<E>) Util.primitiveClassToBoxed(type);
}
if (Util.boxedClassToPrimitive(type) != null && s.length() <= 0)
{
//don't try instantiating a boxed class with an empty string
return null;
}
if (type.isAssignableFrom(Character.class) && s.length() > 0)
{
return type.cast(s.charAt(0));
}
try
{
Constructor<E> stringConstructor = type.getDeclaredConstructor(String.class);
return stringConstructor.newInstance(s);
}
catch (InvocationTargetException e)
{
if (e.getCause() instanceof RuntimeException)
{
throw (RuntimeException) e.getCause();
}
throw new IllegalArgumentException(e.getCause());
}
catch (Exception e)
{
}
try
{
Method method = type.getDeclaredMethod("fromString", String.class); //$NON-NLS-1$
if (Modifier.isStatic(method.getModifiers()) && type.isAssignableFrom(method.getReturnType()))
{
return type.cast(method.invoke(null, s));
}
}
catch (InvocationTargetException e)
{
if (e.getCause() instanceof RuntimeException)
{
throw (RuntimeException) e.getCause();
}
throw new IllegalArgumentException(e.getCause());
}
catch (Exception e)
{
}
return null;
}
}