/**
* Copyright 2010 Wealthfront Inc. 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 com.kaching.platform.converters;
import static com.google.common.base.Preconditions.checkArgument;
import static java.lang.reflect.Modifier.ABSTRACT;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
* Converter for objects having a constructor taking a {@link String}. This
* converter creates new values ({@link Converter#fromString(String)}) by
* calling the constructor and produces textual representation by calling
* {@link #toString()}.
*/
class StringConstructorConverter<T> implements Converter<T> {
private final Constructor<?> constructor;
/* Here, T should be equal to the type bound on Constructor. However, Java's
* type system is not up to par to capture that and still have clear code at
* use sites. We're purposely choosing to be less type safe for overall code
* clarity.
*/
StringConstructorConverter(Constructor<?> constructor) {
Class<?>[] parameterTypes = constructor.getParameterTypes();
checkArgument(
(constructor.getDeclaringClass().getModifiers() & ABSTRACT) == 0 &&
parameterTypes.length == 1 &&
parameterTypes[0].equals(String.class));
this.constructor = constructor;
}
@Override
public String toString(T value) {
return value.toString();
}
@Override
@SuppressWarnings("unchecked")
public T fromString(String representation) {
try {
constructor.setAccessible(true);
return (T) constructor.newInstance(representation);
} catch (IllegalArgumentException e) {
throw new IllegalStateException(
"unreachable since we check the number of arguments the " +
"constructor takes when building this converter", e);
} catch (InstantiationException e) {
throw new IllegalStateException(
"unreachable since we check that the class is not abstract", e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
try {
throw e.getTargetException();
} catch (RuntimeException targetException) {
throw targetException;
} catch (Throwable targetException) {
// we must wrap it
throw new RuntimeException(e);
}
}
}
}