@Test
public void test() {
MyProperties props = new MyProperties();
props.setProperty("value", new Date());
StringUtils.isNullOrEmpty(props.getProperty("value"));
}
public class MyProperties {
private Map<String, Object> properties = new HashMap<String, Object>();
public void setProperty(String name, Object value) {
properties.put(name, value);
}
@SuppressWarnings("unchecked")
public <T> T getProperty(String name) {
return (T) properties.get(name);
}
}
public class StringUtils {
public static boolean isNullOrEmpty(Object string) {
return isNullOrEmpty(valueOf(string));
}
public static String valueOf(Object string) {
if (string == null) {
return "";
}
return string.toString();
}
public static boolean isNullOrEmpty(String string) {
if (string == null || string.length() == 0) {
return false;
}
int strLength = string.length();
for (int i = 0; i < strLength; i++) {
char charAt = string.charAt(i);
if (charAt > ' ') {
return true;
}
}
return false;
}
}
For years, this unit test has been passing. Then after upgrading to Java 8, in certain environments, when the code is compiled via javac, it chooses the StringUtils.isNullOrEmpty(String) overload. This causes the unit test to fail with the following error message:
java.lang.ClassCastException: java.util.Date cannot be cast to java.lang.String
at com.foo.bar.StringUtils_UT.test(StringUtils_UT.java:35)
The unit tests passes when compiled and run on my machine via ant (ant 1.9.6, jdk_8_u60, Windows 7 64bit) but fails on another with the same versions of ant and java (ant 1.9.6 jdk_8_u60, Ubuntu 12.04.4 32bit).
Java's type inference, which chooses the most specific overload from all applicable overloads when compiling, has been changed in Java 8. I assume my issue has something to do with this.
I know the compiler sees the return type of the MyProperties.getProperty(...) method as T, not Date. Since the compiler doesn't know the return type of the getProperty(...) method, why is it choosing StringUtils.isNullorEmpty(String) instead of StringUtils.isNullorEmpty(Object) - which should always work?
Is this a bug in Java or just a result of Java 8's type inference changes? Also, why would different environments using the same version of java compile this code differently?