Saturday, July 12, 2008
Java Enum Puzzler
What does the following print ?
FOO is an enum value in FooEnum. The class of FOO must therefore be an enum, and it should print "true". Right ? If you give it a try, surprisingly it will print "false". Why ?
Peeking into the JDK source code of Class.java,
To me, this looks like a bug either in the javac compiler, or in the implementation of Class.isEnum().
Why is it probably a bug in the javac compiler ? Well, shouldn't the super class of FOO.class be Enum.class, instead of FooEnum.class ? (Special thanks to Dhanji R. Prasanna for pointing this out.)
Why is it probably a bug in Class.isEnum() ? Well, shouldn't it recursively check all the super classes of FOO.class for Enum.class, instead of just the direct super class ? And why does it need to compare the super class with Enum.class at all, when there is already the checking for the ENUM class modifier ?
What do you think ?
Update on 7/13/2008: Please vote for bug 6710708.
Answer:public enum FooEnum {
FOO { @Override public void bar() {} };
public abstract void bar();
public static void main(String...args) {
System.out.println(FOO.getClass().isEnum());
}
}
FOO is an enum value in FooEnum. The class of FOO must therefore be an enum, and it should print "true". Right ? If you give it a try, surprisingly it will print "false". Why ?
Peeking into the JDK source code of Class.java,
Now if you tried to print out the super class of FOO.class, it would print FooEnum.class, rather than Enum.class. The comparison of the super class of FOO.class against Enum.class would therefore fail in the second condition of the return statement.public boolean isEnum() {
// An enum must both directly extend java.lang.Enum and have
// the ENUM bit set; classes for specialized enum constants
// don't do the former.
return (this.getModifiers() & ENUM) != 0 &&
this.getSuperclass() == java.lang.Enum.class;
}
To me, this looks like a bug either in the javac compiler, or in the implementation of Class.isEnum().
Why is it probably a bug in the javac compiler ? Well, shouldn't the super class of FOO.class be Enum.class, instead of FooEnum.class ? (Special thanks to Dhanji R. Prasanna for pointing this out.)
Why is it probably a bug in Class.isEnum() ? Well, shouldn't it recursively check all the super classes of FOO.class for Enum.class, instead of just the direct super class ? And why does it need to compare the super class with Enum.class at all, when there is already the checking for the ENUM class modifier ?
What do you think ?
Update on 7/13/2008: Please vote for bug 6710708.
Friday, July 11, 2008
Dumping a JavaBean as name/value pairs ?
Sometimes it's useful to deeply dump out the properties of a complex JavaBean as name/value pairs, perhaps for debugging purposes, even when none of the toString methods of the classes involved are defined. This is especially the case when the JavaBean classes are written by a third party.
Now how would you go about doing that ?
How about using the Jarkarta commons-lang's ToStringBuilder.reflectionToString method ? It doesn't cut it, as it relies on the toString method of the individual classes involved.
How about XMLEncoder or XStream ? They work pretty nicely. However, by default XStream generates not just the public properties but all other fields as well. In both cases, the generated XML would need to be further transformed into name/value pairs.
Another way I can think of is to take advantage of the latest BeanSourceHandler SPI as a side effect of performing a deep clone via the open-source library Beanlib (beanlib-3.3.0beta18). What do I mean ? Here is an example:
Now how would you go about doing that ?
How about using the Jarkarta commons-lang's ToStringBuilder.reflectionToString method ? It doesn't cut it, as it relies on the toString method of the individual classes involved.
How about XMLEncoder or XStream ? They work pretty nicely. However, by default XStream generates not just the public properties but all other fields as well. In both cases, the generated XML would need to be further transformed into name/value pairs.
Another way I can think of is to take advantage of the latest BeanSourceHandler SPI as a side effect of performing a deep clone via the open-source library Beanlib (beanlib-3.3.0beta18). What do I mean ? Here is an example:
Object bean = ...
// Dump out the entire JavaBean
// when none of the toString methods are defined.
BeanReplicator.newBeanReplicatable(customTransformer()).replicateBean(bean);
private static BeanTransformerSpi customTransformer() {
BeanTransformerSpi beanTransformer = BeanTransformer.newBeanTransformer();
return beanTransformer.initBeanSourceHandler(new BeanSourceHandler() {
public void handleBeanSource(Object fromBean, Method readerMethod, Object propertyValue) {
System.out.println(
String.valueOf(fromBean.getClass().getSimpleName() + "."
+ readerMethod.getName() + "=" + propertyValue));
}
});
}
Wednesday, July 02, 2008
Little Java Quiz - File loaded from classpath
Given:
(Don't peek if you want to give it a try!)
Answer:
- a file with a given name;
- the file is located in the file system;
- the file can be loaded via the classpath;
(Don't peek if you want to give it a try!)
Answer:
String filePath = Thread.currentThread()
.getContextClassLoader()
.getResource(filename)
.getFile();