Search code examples
javajsonjacksonjackson-databind

How do I deserialize a string as a custom object with Jackson?


I have this JSON that I want to parse:

{
 "name": "john",
}

I must use the following hierarchy. The classes are immutable and I must access them by the static factory method (this is imperative, so it makes no sense to suggest modifications to either Name or Person).

class Name {
  static Name valueOf(String name) {...}
  private Name() {}
  String name();
}
class Person {
  static Person create(Name name) {...}
  private Person() {...}
  Name name();
}

To that end, I want to deserialize a Person with Jackson, so I wrote this:

public class NameJsonDeserializer extends JsonDeserializer<Name> {
  @Override public Name deserialize(JsonParser parser, DeserializationContext context) {
    var tree = parser.getCodec().readTree(parser);
    var name = tree.asToken().asString();
    return Name.valueOf(name);
  }
}
public class PersonJsonDeserializer extends JsonDeserializer<Person> {
  @Override public Person deserialize(JsonParser parser, DeserializationContext context) {
    var tree = parser.getCodec().readTree(parser);
    var name = (ObjectNode) tree.get("name");
    return Person.create(name);
  }
}

But of course, this doesn't work. It doesn't even compile.

I know I can write something similar to the following, but Name is used all over the place, and not always within a Person, so I really need a separate deserializer for Name.

var tree = parser.getCodec().readTree(parser);
var name = (TextNode) tree.get("name");
return Person.create(Name.valueOf(name.asText()));

How can I deserialize without having recourse to intermediary POJOs?


Solution

  • I must use parser.getValueAsString() for NameDeserializer and codec.treeToValue() for PersonDeserializer:

    public class NameJsonDeserializer extends JsonDeserializer<Name> {
      @Override public Name deserialize(JsonParser parser, DeserializationContext context) {
        var name = parser.getValueAsString();
        return Name.valueOf(name);
      }
    }
    public class PersonJsonDeserializer extends JsonDeserializer<Person> {
      @Override public Person deserialize(JsonParser parser, DeserializationContext context) {
        var codec = parser.getCodec();
        var tree = codec.readTree(parser);
        
        var name = codec.treeToValue(tree.get("name"), Name.class);
    
        return Person.create(name);
      }
    }