It is possible to deserialize to a class with private fields and a custom argument constructor without using annotations and without modifying the class, using Jackson?
I know it's possible in Jackson when using this combination: 1) Java 8, 2) compile with "-parameters" option, and 3) the parameters names match JSON. But it's also possible in GSON by default without all these restrictions.
For example:
public class Person { private final String firstName; private final String lastName; private final int age; public Person(String firstName, String lastName, int age) { this.firstName = firstName; this.lastName = lastName; this.age = age; } public static void main(String[] args) throws IOException { String json = "{firstName: \"Foo\", lastName: \"Bar\", age: 30}"; System.out.println("GSON: " + deserializeGson(json)); // works fine System.out.println("Jackson: " + deserializeJackson(json)); // error } public static Person deserializeJackson(String json) throws IOException { ObjectMapper mapper = new ObjectMapper(); mapper.enable(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES); mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY); return mapper.readValue(json, Person.class); } public static Person deserializeGson(String json) { Gson gson = new GsonBuilder().create(); return gson.fromJson(json, Person.class); } }
Wich works fine for GSON, but Jackson throws:
Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `jacksonParametersTest.Person` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator) at [Source: (String)"{firstName: "Foo", lastName: "Bar", age: 30}"; line: 1, column: 2] at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67)
It's possible in GSON, so I would expect that there must be some way in Jackson without modifying the Person class, without Java 8, and without an explicit custom deserializer. Does anybody know a solution?
- Update, additional info
Gson seems to skip the argument constructor, so it must be creating a no-argument constructor behind the scenes using reflections.
Also, there exists a Kotlin Jackson module which is able to do this for Kotlin data classes, even without the "-parameters" compiler flag. So it is strange that such a solution doesn't seem to exist for Java Jackson.
This is the (nice and clean) solution available in Kotlin Jackson (which IMO should also become available in Java Jackson via a custom module):
val mapper = ObjectMapper() .enable(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES) .registerModule(KotlinModule()) val person: Person = mapper.readValue(json, Person::class.java)