3

I am trying to deserialize a JSON string to a java pojo class that only has an all parameters constructor and getters. All the fields are final and the class is immutable. Here is my java pojo object:

Foo.java

public class Foo {
    private final int id;
    private final int cId;
    private final String cName;
    private final String code;
    private final String display;

    public Foo(final int id, 
               final int cId,
               final String cName,
               final String code,
               final String display) {
        this.id = id;
        this.cId = cId;
        this.cName = cName;
        this.code = code;
        this.display = display;
    }

    //Some copy constructor
    public Foo(final FooB fooB) {
        this.id = fooB.getId();
        this.cId = fooB.getCId();
        this.cName = fooB.getContractorCName();
        this.code = fooB.getCode();
        this.display = fooB.getDisplay();
    }

    public int getId() {
        return id;
    }

    public int getCId() {
        return cId;
    }

    public String getCName() {
        return cName;
    }

    public String getCode() {
        return code;
    }

    public String getDisplay() {
        return display;
    }
}

And here's my test:

public static void main(String[] args) {
    ParameterNamesModule pnm = new ParameterNamesModule(JsonCreator.Mode.PROPERTIES);
    ObjectMapper mapper = new ObjectMapper().enable(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES).registerModule(pnm);
    String json = "{\"id\":19,\"cId\":13234,\"cName\":\"SOME NAME\",\"code\":\"8EJ4\",\"display\":\"SOME DISPLAY NAME\"}";
    try {
        mapper.readValue(json, Foo.class);
    } catch (JsonProcessingException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

However when I run this I get the following error:

objc[58537]: Class JavaLaunchHelper is implemented in both /Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/bin/java (0x109dbf4c0) and /Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/jre/lib/libinstrument.dylib (0x109e874e0). One of the two will be used. Which one is undefined.
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.test.Foo` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
 at [Source: (String)"{"id":19,"cId":13234,"cName":"SOME NAME","code":"8EJ4","display":"SOME DISPLAY NAME"}"; line: 1, column: 2]
    at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67)
    at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1451)
    at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1027)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1290)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:326)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:159)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4001)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2992)
    at JacksonCreator.main(JacksonCreator.java:18)

What am I doing wrong? I am using version 2.9.4 of the Jackson

Richard
  • 5,840
  • 36
  • 123
  • 208
  • 1
    It looks like it's expecting a default constructor and setters. Good candidate for a builder? – Joe C Mar 06 '18 at 22:41
  • Did you compile with `-parameters`? – Sotirios Delimanolis Mar 06 '18 at 22:41
  • @SotiriosDelimanolis I think that's the problem. I am not running that as a command. Is there absolutely no way to get this module to work without that runtime argument? – Richard Mar 06 '18 at 22:44
  • 7
    If you can change the class, annotated the parameters with `@JsonProperty` and the constructor with `@JsonCreator`. Otherwise, use the mixin as explained [here](https://stackoverflow.com/questions/47570931/jackson-deserialize-class-with-private-fields-and-arg-constructor-without-annot). – Sotirios Delimanolis Mar 06 '18 at 22:45
  • @SotiriosDelimanolis yeah i was trying to use the parameter module as a way to _avoid_ having annotations in the POJO and I don't want to have to create an additional class for every single POJO. But adding in compiler arguments is even worse so I'll just stick with the annotations – Richard Mar 06 '18 at 22:47
  • I would advice two things. First - use lombok, there is just too much of boilerplate there. Second - configure @JsonDeserialize(builder = Foo.Builder.class) and @JsonPOJOBuilder(withPrefix = "") That's the cleanest way i've found to work with immutable objects and jackson. – Daniel Hajduk Jan 21 '19 at 21:14

1 Answers1

1

try this

@JsonCreator(mode = JsonCreator.Mode.PROPERTIES) public Foo(@JsonProperty ("id") final int id, @JsonProperty ("cId") final int cId, ...) { this.id = id; this.cId = cId; ... }

Omid Rostami
  • 524
  • 6
  • 10