This code smells. Yes, this passes under Java 7, and yes it runs alright with Java 7, but there is something definitely wrong here.
First, let's talk about this generic type.
@SuppressWarnings("unchecked")
public <T> T getProperty(String name) {
return (T) properties.get(name);
}
Can you at a glance infer what T
should be? If I run those casts in Java 7 compliance mode with IntelliJ at that exact line, I get back this very helpful ClassCastException
:
Cannot cast java.util.Date to T
So this implies that at some level, Java knew there was something off here, but it elected to change that cast instead from (T)
to (Object)
.
@SuppressWarnings("unchecked")
public <T> Object getProperty(String name) {
return (Object) properties.get(name);
}
In this case, the cast is redundant, and you get back an Object
from the map, as you would expect. Then, the correct overload is called.
Now, in Java 8, things are a bit more sane; since you don't truly provide a type to the getProperty
method, it blows up, since it really can't cast java.util.Date
to T
.
Ultimately, I'm glossing over the main point:
This use of generics is broken and incorrect.
You don't even need generics here. Your code can handle either a String
or an Object
, and your map only contains Object
s anyway.
You should only return Object
from the getProperty
method, since that's what you can only return from your map anyhow.
public Object getProperty(String name) {
return properties.get(name);
}
It does mean that you no longer get the ability to call directly into the method with a signature of String
(since you're passing an Object
in now), but it does mean that your broken generics code can finally be put to rest.
If you really want to preserve this behavior though, you would have to introduce a new parameter into your function that actually allowed you to specify which type of object you wanted back from your map.
@SuppressWarnings("unchecked")
public <T> T getProperty(String name, Class<T> clazz) {
return (T) properties.get(name);
}
Then you could invoke your method thus:
StringUtils.isNullOrEmpty(props.getProperty("value", Date.class));
Now we are absolutely certain as to what T
is, and Java 8 is content with this code. This is still a bit of a smell, since you're storing things in a Map<String, Object>
; if you've got the Object
overridden method and you can guarantee that all objects in that map have a meaningful toString
, then I would personally avoid the above code.