0

I've got the following method:

public <T> T deserialise(String payload, Class<T> expectedClass) {
    try {
        return mapper.readValue(payload, expectedClass);
    } catch (IOException e) {
        throw new IllegalStateException("JSON is not valid!", e);
    }
} 

that I can call using deserialise("{\"foo\": \"123\"}", Foo.class).

What type shall I use if I want to create a map from String to Class and then iterate over this map to deserialise the strings into objects?

E.g., I want something similar to:

Map<String, Class?> contents = ImmutableMap.of(
   "{\"foo\": \"123\"}", Foo.class,
   "{\"bar\": \"123\", \"bar2\": \"123\"}", Bar.class
);

And then I want to be able to:

for (Map.Entry<String, Class?> e : contents.entrySet) {
   Class? obj = deserialise(e.getKey(), e.getValue());
}

What should I put instead of Class??

Update:

ObjectMapper objectMapper = new ObjectMapper();

Map<String, Class<?>> contents = ImmutableMap.of(
        "{\"foo\": \"123\"}", Foo.class,
        "{ \"color\" : \"Black\", \"type\" : \"BMW\" }", Bar.class
);

for (Map.Entry<String, Class<?>> e : contents.entrySet()) {
    try {
        Object obj = objectMapper.readValue(e.getKey(), e.getValue());
        System.out.println(obj);
    } catch (IOException ex) {
        ex.printStackTrace();
    }
}

Update #2:

ObjectMapper objectMapper = new ObjectMapper();

String json = "{ \"color\" : \"Black\", \"type\" : \"BMW\" }";
T typeClass = Foo.class; // TODO: fix syntax error

try {
    Class<?> obj = objectMapper.readValue(json, typeClass); // TODO: fix error and cast obj to Foo.class using typeClass
} catch (IOException e) {
    e.printStackTrace();
}
James Larkin
  • 541
  • 5
  • 18

1 Answers1

1

Your syntax is very close!

You should use Class<?>. The <?> is known as a generic wildcard.

Map<String, Class<?>> contents = ImmutableMap.of(
   "{\"foo\": \"123\"}", Foo.class,
   "{\"bar\": \"123\", \"bar2\": \"123\"}", Bar.class
);


for (Map.Entry<String, Class<?>> e : contents.entrySet) {
   Object obj = deserialise(e.getKey(), e.getValue());
}

Note that obj should not be of type Class<?> because deserialise returns T, not Class<T>.

Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • The last question: I've updated the code in the question, how can I cast `Object obj` to its initial `Class>` (like `Bar/Foo`) to use it as the typical `Bar bar` objects? – James Larkin Aug 21 '19 at 07:11
  • @JamesLarkin You don't know the actual type of `obj`, do you? It could be `Foo` or `Bar`. The type of `obj` changes depending on which iteration the for loop is in. – Sweeper Aug 21 '19 at 07:14
  • sure that makes sense. Let's say there's no loop and please see the updated code #2 in the question. – James Larkin Aug 21 '19 at 07:20
  • basically I want to make something similar to https://stackoverflow.com/questions/57581859/how-do-i-parametrize-response-parsing-in-java but the accepted answer doesn't really suit me. – James Larkin Aug 21 '19 at 07:23
  • @JamesLarkin You should be able to just do `Bar bar = (Bar)objectMapper.readValue(json, typeClass);` – Sweeper Aug 21 '19 at 07:23
  • can I do sth like `(typeClass)objectMapper.readValue(json, typeClass);` though? I don't think `Bar` is available there. – James Larkin Aug 21 '19 at 07:27
  • You have to know the type at compile time to be able to cast. You are telling the _compiler_ what type you want a variable to be. The compiler does not know what type `typeClass` is. This is starting to look like an XY problem. What are you going to do with `obj` after you casted it? – Sweeper Aug 21 '19 at 07:29
  • Hm I see, initially I wanted to have `return parseResponse(json, typeClass)` in different methods that return the corresponding typeClasses (like `parseResonseBar()` in Bar class etc) – James Larkin Aug 21 '19 at 07:41