This method that uses method-level generics, that parses the values from a custom POJO, JXlistOfKeyValuePairs (which is exactly that). The only thing is that both the keys and values in JXlistOfKeyValuePairs are Strings.
This method wants to taken in, in addition to the JXlistOfKeyValuePairs instance, a Class<T> that defines which data type to convert the values to (assume that only Boolean, Integer and Float are possible). It then outputs a HashMap with the specified type for the values in its entries.
This is the code that I have got, and it is obviously broken.
private <T extends Object> Map<String, T>
fromListOfKeyValuePairs(JXlistOfKeyValuePairs jxval, Class<T> clasz)
{
Map<String, T> val = new HashMap<String, T>();
List<Entry> jxents = jxval.getEntry();
T value;
String str;
for (Entry jxent : jxents)
{
str = jxent.getValue();
value = null;
if (clasz.isAssignableFrom(Boolean.class))
{
value = (T)(Boolean.parseBoolean(str));
} else if (clasz.isAssignableFrom(Integer.class))
{
value = (T)(Integer.parseInt(str));
} else if (clasz.isAssignableFrom(Float.class))
{
value = (T)(Float.parseFloat(str));
}
else {
logger.warn("Unsupported value type encountered in key-value pairs, continuing anyway: " +
clasz.getName());
}
val.put(jxent.getKey(), value);
}
return val;
}
This is the bit that I want to solve:
if (clasz.isAssignableFrom(Boolean.class))
{
value = (T)(Boolean.parseBoolean(str));
} else if (clasz.isAssignableFrom(Integer.class))
{
value = (T)(Integer.parseInt(str));
}
I get: Inconvertible types required: T found: Boolean
Also, if possible, I would like to be able to do this with more elegant code, avoiding Class#isAssignableFrom.
Any suggestions?
Sample method invocation:
Map<String, Boolean> foo = fromListOfKeyValuePairs(bar, Boolean.class);
Solved, thanks to both @Chris Dolan and @polygenelubricants. The cause was the typecast was getting confused when combine with the autoboxing of the primitive. Compiler warnings are avoided because the method parameter clasz is of the type Class<T>, instead of just Class or Class<?>, so invoking the cast method was typesafe.
Impl. soln.:
private <T extends Object> Map<String, T> fromListOfKeyValuePairs(
JXlistOfKeyValuePairs jxval, Class<T> clasz)
{
Map<String, T> val = new HashMap<String, T>();
List<Entry> jxents = jxval.getEntry();
T value;
String str;
for (Entry jxent : jxents)
{
str = jxent.getValue();
value = null;
if (clasz.isAssignableFrom(Boolean.class))
{
value = clasz.cast(Boolean.parseBoolean(str));
}
else if (clasz.isAssignableFrom(Integer.class))
{
value = clasz.cast(Integer.valueOf(Integer.parseInt(str)));
}
else if (clasz.isAssignableFrom(Float.class))
{
value = clasz.cast((Object)Float.parseFloat(str));
}
else
{
logger.warn("Unsupporteded value type encountered in key-value pairs, continuing anyway: " +
clasz.getName());
}
val.put(jxent.getKey(), value);
}
return val;
}
You can use the
Class<T>.castmethod instead of doing your own unchecked(T)cast.No compiler warning.
As for why the original code doesn’t compile, it’s because you’re trying to cast a primitive directly to an unknown reference type. Casting directly from primitive to a reference type only works in very specific cases, and in all those cases, the type must be known at compile time.
The last line is analogous to your cast from a primitive directly to an unknown parameterized type
T(i.e.(T) Integer.parseInt(s)), which is why it doesn’t compile. It’s true that you’re trying to write the code such thatTwould be the proper type, but there’s no way of confirming that at compile-time, sinceTcan be any type in general.The previous to last line gets around the compile-time error by indirectly casting the primitive to
String, after it had already been converted to anObjectreference type. That’s why it compiles, although of course it will throw aClassCastExceptionat run-time.Here’s a parameterized type generic example: it’s a bit silly, but reillustrates the problem with casting primitives directly to an unknown reference type:
References