You have to have a concrete class per Type regardless:
Trying to infer something like this from Generics at Runtime and branch the logic based on that information is only a path of pain and makes your code extremely hard to understand and easier to break.
What you are trying to do is more like an abuse of the type system than leveraging it. As soon as you get to testing for types with instanceof
or .getClass()
or any of the TypeToken
magic you are probably doing it wrong, especially for something that can be done without all that mumbo-jumbo.
There are only so many Number
subclasses, just hard code them and chain them where the first non-null return value from a Converter
is the appropriate type.
Guava has something called Converter
just for things like this.
For example:
final static ShortConverter sc = new ShortConverter();
final static IntegerConverter ic = new IntegerConverter();
final static DoubleConverter dc = new DoubleConverter();
public static void main(String[] args) throws ParseException
{
System.out.println("getNumber(\"1\").getClass().toString() = " + getNumber("1").getClass().toString());
System.out.println("getNumber(\"64000\").getClass().toString() = " + getNumber("64000").getClass().toString());
System.out.println("getNumber(\"3.14\").getClass().toString() = " + getNumber("3.14").getClass().toString());
}
public static Number getNumber(@Nonnull final String s)
{
/* nest the firstNonNull() as deeply as you need for the limited
number of types */
return firstNonNull(sc.doForward(s), firstNonNull(ic.doForward(s), dc.doForward(s)));
}
public static class DoubleConverter extends Converter<String, Double>
{
@Override
protected String doBackward(@Nonnull final Double d) { return d.toString(); }
@Override
protected Double doForward(@Nonnull final String s) { return Doubles.tryParse(s); }
}
public static class IntegerConverter extends Converter<String, Integer>
{
@Override
protected String doBackward(@Nonnull final Integer i) { return i.toString(); }
@Override
protected Integer doForward(@Nonnull final String s) { return Ints.tryParse(s); }
}
public static class ShortConverter extends Converter<String, Short>
{
@Override
protected String doBackward(@Nonnull final Short s) { return s.toString(); }
@Override
protected Short doForward(@Nonnull final String s) { try { return Short.parseShort(s); } catch (NumberFormatException e) { return null; } }
}
Outputs:
getNumber("1").getClass().toString() = class java.lang.Short
getNumber("64000").getClass().toString() = class java.lang.Integer
getNumber("3.14").getClass().toString() = class java.lang.Double
In case how to apply this to the question is not obvious:
public class MyClass<T extends Number>
{
T value;
final Converter<String,T> converter;
public MyClass(final Converter<String,T> c)
{
this.converter = c;
}
public void setValueFromString(String s)
{
this.value = this.converter.doForward(s);
}
}