15

I want to make generic function that return Object representation of XML document (using JAXB). I need to pass "class" object to JAXBContext constructor, but how I can get it from T?

public <T> readXmlToObject(String xmlFileName, T  jaxbClass) {
   JAXBContext context = JAXBContext.newInstance(T.class); // T.class - here error, how to get it?
   .......
}
WelcomeTo
  • 19,843
  • 53
  • 170
  • 286

6 Answers6

17

Pass the class object instead and it's easy.

public <T> T readXmlToObject(String xmlFileName, Class<T>  jaxbClass) {
       JAXBContext context = JAXBContext.newInstance( jaxbClass ); // T.class - here error, how to get it?
       Object o = context.createUnmarshaller().unmarshal( new File( xmlFileName ) );
       return jaxbClass.cast( o );
}

The idea here is that since you can't extract the type parameter from the object, you have to do it the other way around: start with the class and then manipulate the object to match the type parameter.

biziclop
  • 48,926
  • 12
  • 77
  • 104
7

Don't listen to the others... you CAN get it.

Simply change the type of the jaxbClass parameter to Class<T>:

public <T> T readXmlToObject(String xmlFileName, Class<T> jaxbClass) {
   JAXBContext context = JAXBContext.newInstance(jaxbClass);
   .......
}
Bohemian
  • 412,405
  • 93
  • 575
  • 722
3

You cannot get the class of at run time. Java implements Generics using Type Safe Erasure which means that the understanding of the Generic type is only applied at up through compilation. You must interogate the actual object at run time if you want to get its class.

Bohemian
  • 412,405
  • 93
  • 575
  • 722
Rich Hill
  • 463
  • 2
  • 6
  • 2
    -1 Wrong! The class is being passed in. The problem is with the method signature – Bohemian May 29 '12 at 13:56
  • 1
    Thanks for the input. As written it wouldn't work, but I see your point to with changing the input to Class instead of T. That would be fine. It would be nice though, if it wasn't even a concern because of Java's bad generics impl. – Rich Hill May 29 '12 at 14:34
1

Take a look at this SO answer.

Basically, the type T isn't available at runtime - Java generics are subject to erasure by the compiler.

Fortunately you already have an instance of your class, so you can get the type information from there:

public <T> readXmlToObject(String xmlFileName, T jaxbClass) {

   // if jaxbClass is an instance of the data object, you can do this: 
   JAXBContext context = JAXBContext.newInstance(jaxbClass.getClass());

   // alternatively if jaxbClass is an instance of the Class object: 
   JAXBContext context = JAXBContext.newInstance(jaxbClass);
   // ......
}
Community
  • 1
  • 1
Dan Vinton
  • 26,401
  • 9
  • 37
  • 79
  • -1 Totally won't work. `jaxbClass.getClass()` will return `Class.class`. And you're wrong too - erasure isn't a problem here because the class is being passed in. – Bohemian May 29 '12 at 13:54
  • ah - I assumed that because it was constrained to T rather than Class that it was an instance of the class (if you get my drift...) – Dan Vinton May 29 '12 at 13:56
  • I do get you, but think that's his problem - he's coded the wrong type for the parameter. He *isn't* passing in a `T`, because he won't have an instance of `T` until after the call, but he can pass in an instance of `Class`. I admit I'm going by the parameter name `jaxbClass`, which pretty strongly suggests it's a `class`. – Bohemian May 29 '12 at 14:05
  • I un-downvoting this - your answer isn't *so* wrong that it deserved downvoting :) – Bohemian May 29 '12 at 14:40
1

try to pass the class itself, something like this

public <T> readXmlToObject(String xmlFileName, Class<T> class) {
bpgergo
  • 15,669
  • 5
  • 44
  • 68
0
public class XYZ<T> {
    ...
    private Class<T> tClass;    
    ...
    public <T> readXmlToObject(String xmlFileName) {
       JAXBContext context = JAXBContext.newInstance(tClass);
       ...
    }
    ...
} 
  • I don't think this will work because tClass is not initialized and you end up passing in a null to the "JAXBContext.newInstance(..)" call. – Go Rose-Hulman Jan 17 '15 at 18:26
  • 1
    In my code I did it like this: private Class entityClass; final ParameterizedType type = (ParameterizedType)getClass().getGenericSuperclass(); entityClass = (Class)type.getActualTypeArguments()[0]; – Anderson Junqueira Jan 26 '15 at 18:55