0

I have this code:

public class JsonFileHandler<T> {


    public  T getContent(File file) {
        T t = null;
        ObjectMapper mapper = new ObjectMapper();

        if (!file.exists()) {
            return null;
        } else try {
            t = mapper.readValue(file, T.class);
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        return t;
    }
}

but I get compilation error on this line:

t = mapper.readValue(file, T.class);

which has this signature:

public <T> T readValue(File src, Class<T> valueType)

how can I fix this?

Elad Benda
  • 35,076
  • 87
  • 265
  • 471

5 Answers5

2

I think your only option is to match the signature of readValue:

public T getContent(File file, Class<T> clazz) {
  //
  t = mapper.readValue(file, clazz);
  //
}

Alternatively, you could do that at your class constructor level:

public JsonFileHandler(Class<T> clazz) { this.clazz = clazz; }
assylias
  • 321,522
  • 82
  • 660
  • 783
0

You can't, the type parameter is compiled away. It's called type erasure.

ReyCharles
  • 1,772
  • 10
  • 30
  • In fact you can (though not very reliably) using Guava's TypeToken, see https://code.google.com/p/guava-libraries/wiki/ReflectionExplained#TypeToken – llogiq Jul 07 '15 at 10:00
0

Due to runtime erasure, T is unknown at runtime. The simplest solution is to pass a type token to the constructor:

public class JsonFileHandler<T> {

    private final Class<T> cls;
    public JsonFileHandler(Class<T> cls) {
        this.cls = cls;
    }

    public  T getContent(File file) {
        T t = null;
        ObjectMapper mapper = new ObjectMapper();

        if (!file.exists()) {
            return null;
        } else try {
            t = mapper.readValue(file, cls);
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        return t;
    }
}
Bohemian
  • 412,405
  • 93
  • 575
  • 722
0

Java's limited generics system does not allow you to use 'T.class'. (Scala is more powerful with regards to this)

To solve this, you have to pass a Class instance to the getContent method.

public T getContent(File file, tpe: Class<T>) { ... }

If you're using Java 8 (if not, why not?), then consider returning an Optional instead to get rid of null's and NPE's. Even better would be to return something which would indicate a success or failure (like Scala's Try) so you don't have to use null or throw an exception and handle the error properly at the right place.

Joost den Boer
  • 4,556
  • 4
  • 25
  • 39
0

What you can do is to cast to the class:

     t = (T) mapper.readValue(file, Object.class);

This has the same semantic as what you want to do!

pokeRex110
  • 833
  • 2
  • 14
  • 26