auto: Generated builder can't be used for Jackson deserialization

Jackson 2.x supports deserializing JSON by using the builder pattern, so it would be really cool if the following worked:

@AutoValue
@JsonDeserialize(builder = AutoValue_Project.Builder.class)
public abstract class Project {
    public abstract int getId();
    public abstract String getPath();

    public abstract Builder toBuilder();

    @AutoValue.Builder
    interface Builder {
        Project build();

        Builder withId(int id);
        Builder withPath(String path);
    }
}

Unfortunately, the class AutoValue_Project.Builder doesn’t exist at the point the compiler sees the @JsonDeserialize annotation, so this fails to compile. Is there a workaround for this problem?

NB: the best workaround I have at the moment is a creator method

    @JsonCreator
    static Project create(@JsonProperty("id") int id, @JsonProperty("path") String path) {
        return builder()
                .withId(id)
                .withPath(path)
                .build();
    } 

About this issue

  • Original URL
  • State: closed
  • Created 9 years ago
  • Comments: 23 (2 by maintainers)

Most upvoted comments

@vanniktech You need to use your own builder class and put a @JsonCreator method inside the builder:

@AutoValue
@JsonDeserialize(builder = A.Builder.class)
abstract class A {
  static Builder builder() {
    return new AutoValue_A.Builder().a(true).b("default");
  }

  @JsonProperty abstract boolean a();
  @JsonProperty abstract String b();

  @AutoValue.Builder
  @JsonPOJOBuilder(withPrefix = "")
  abstract static class Builder {
    @JsonCreator private static Builder create() { return A.builder(); }
    abstract Builder a(boolean a);
    abstract Builder b(String b);
    abstract A build();
  }

  public static void main(String[] args) throws Exception {
    ObjectMapper mapper = new ObjectMapper();
    System.out.println(mapper.writeValueAsString(A.builder().build()));
    A a = mapper.readValue("{\"a\": false, \"b\": \"non-default\"}", A.class);
    System.out.println(mapper.writeValueAsString(a));
    a = mapper.readValue("{}", A.class);
    System.out.println(mapper.writeValueAsString(a));
  }
}

Has anyone been able to make it work with default values? Right now in our builder() method we’ll set some default values.

public static Builder builder() {
    return new AutoValue_Class.Builder().a(2).b(3);
}

Unfortunately Jackson won’t take the builder from the builder() method and instead create a new one where the default values for a and b would be missing.

My class is annotated with @JsonDeserialize(builder = AutoValue_Class.Builder.class). I’ve also tried putting @JsonCreator onto the builder() method but that won’t work either.

any on can help how to do

Yep, I’m here if you want some help — feel free to connect me!

Actually, Jackson is powerful enough to handle classes with Builders without changes in AutoValue/Jackson.

You can check the example: https://github.com/artem-zinnatullin/AutoJackson