I am trying to parse the following JSON in Jackson:
{
"x:y" : 1,
"x:z" : 2,
"u:v" : 3,
// Several dynamically generated entries...
}
The data is formatted this way and outside of my control. The entries are somewhat dynamic, but always of the form:
"first:second" : value
I've been trying to serialize that into a container class:
private static class MyClass {
String first;
String second;
Number value;
@JsonCreator
public MyClass(@JsonProperty("both") String both, @JsonProperty("value") Number value) {
String[] split = both.split(":");
first = split[0];
second = split[1];
this.value = value;
}
}
But it I get an error:
Exception in thread "main" com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of entry.JacksonObjectTest$MyClass[] out of START_OBJECT token
Makes sense to me; I'm trying to parse each field of a JSON Object into an Array of Objects, and Jackson obviously isn't too pleased about it. Neglecting the @JsonProperty("both") yields:
Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Invalid type definition for type entry.JacksonObjectTest$MyClass: Argument #0 has no property name, is not Injectable: can not use as Creator [constructor for entry.JacksonObjectTest$MyClass, annotations: {interface com.fasterxml.jackson.annotation.JsonCreator=@com.fasterxml.jackson.annotation.JsonCreator(mode=DEFAULT)}]
Which also makes sense to me; it has no clue how to parse this constructor (which is really the same problem as above; me putting the annotation in is just masking that error with a different one).
So my question is; how to I make Jackson understand what I want here?
MCVE:
public class JacksonObjectTest {
public static void main(String[] args) throws IOException {
String data = "{\"x:y\":1,\"x:z\":2,\"u:v\":3}";
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(data);
MyClass[] out = mapper.readValue(node.traverse(), MyClass[].class);
System.out.println(out);
}
private static class MyClass {
String first;
String second;
Number value;
@JsonCreator
public MyClass(@JsonProperty("both") String both, @JsonProperty("value") Number value) {
String[] split = both.split(":");
first = split[0];
second = split[1];
this.value = value;
}
}
}
EDIT: As mentioned in the comments, I do know about the method of using a TypeReference<Map<String,Number>>. This works, but I was trying to make my parsing code as contained and generic as possible, and using this solution means I have to do further conversion post-parsing to get a MyClass[] (first parse for the Map<String,Number>, then process that for the MyClass[]). Is there a way to skip the middleman (IE: tell Jackson how to process a blob of JSON of known formatting into a data type)?
MyClass[]without having to handle all the interim data types explicitly?