In C# I can do actually this:
//This is C#
static T SomeMethod() where T:new()
{
Console.WriteLine("Typeof T: "+typeof(T));
return new T();
}
//And call the method here
SomeMethod();
But for some reason I can't get it to work in Java.
The thing I want to do is, to create a static method on a superclass, so the subclasses can be converted to XML.
//This is Java, but doesn't work
public static T fromXml(String xml) {
try {
JAXBContext context = JAXBContext.newInstance(T.class);
Unmarshaller um = context.createUnmarshaller();
return (T)um.unmarshal(new StringReader(xml));
} catch (JAXBException je) {
throw new RuntimeException("Error interpreting XML response", je);
}
}
//Also the call doesn't work...
fromXml("");
解决方案
public static T fromXml(Class clazz, String xml) {
Called as:
Thing thing = fromXml(Thing.class, xml);
or more explicitly:
Thing thing = MyClass.fromXml(Thing.class, xml);
To be even more confusing you can have constructors that both construct a generic type and have a generic parameter themselves. Can't remember the syntax and have never seen it used in anger (you are probably better off with a static creation method anyway).
The cast (T) is unsafe, and you can't write T.class. So include the T.class as an argument (as JAXBContext.newInstance does) and throw a relevant exception if the type is wrong.
public static T fromXml(Class clazz, String xml) {
try {
JAXBContext context = JAXBContext.newInstance(clazz);
Unmarshaller um = context.createUnmarshaller();
Object obj = um.unmarshal(new StringReader(xml));
try {
return clazz.cast(obj);
} catch (ClassCastException exc) {
throw new RelevantException(
"Expected class "+clazz+
" but was "+obj.getClass()
);
}
} catch (JAXBException exc) {
throw new RelevantException(
"Error unmarshalling XML response",
exc
);
}
}
I believe the next version of JAXB (in 6u14?) has some convenience methods for this sort of thing in the JAXB class.