Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using strict builders gives Jackson deserialize failures #1505

Open
bpasson opened this issue Mar 15, 2024 · 0 comments
Open

Using strict builders gives Jackson deserialize failures #1505

bpasson opened this issue Mar 15, 2024 · 0 comments

Comments

@bpasson
Copy link

bpasson commented Mar 15, 2024

When generating with strictBuilder = true, there is no @JsonProperty("lines") annotation on any of the
methods related to collections, which makes Jackson fail with an UnrecognizedPropertyException for the collections.

A reproducer can be found here: https://github.com/bpasson/immutables-issue-1505

Detailed Example

Consider the following objects:

@Value.Immutable
@Value.Style(overshadowImplementation = true,
        jdkOnly = true, strictBuilder = true)
@JsonDeserialize(builder = Order.Builder.class)
public interface Order {

    @JsonProperty("id")
    Long getId();

    @JsonProperty("lines")
    List<OrderLine> getOrderLines();

    static Builder builder() {
        return new Builder();
    }

    class Builder extends ImmutableOrder.Builder {
    }
}
@Value.Immutable
@Value.Style(overshadowImplementation = true,
        jdkOnly = true, strictBuilder = true)
@JsonDeserialize(builder = OrderLine.Builder.class)
public interface OrderLine {

    @JsonProperty("id")
    Long getId();

    @JsonProperty("description")
    String description();

    static Builder builder() {
        return new Builder();
    }

    class Builder extends ImmutableOrderLine.Builder {
    }
}

When the immutable values are generated with strictBuilder = false the generated ImmutableOrder.Builder class gets
the following methods for the order lines collection:

/**
     * Adds one element to {@link Order#getOrderLines() orderLines} list.
     * @param element A orderLines element
     * @return {@code this} builder for use in a chained invocation
     */
    public final Order.Builder addOrderLines(OrderLine element) {
      this.orderLines.add(Objects.requireNonNull(element, "orderLines element"));
      return (Order.Builder) this;
    }

    /**
     * Adds elements to {@link Order#getOrderLines() orderLines} list.
     * @param elements An array of orderLines elements
     * @return {@code this} builder for use in a chained invocation
     */
    public final Order.Builder addOrderLines(OrderLine... elements) {
      for (OrderLine element : elements) {
        this.orderLines.add(Objects.requireNonNull(element, "orderLines element"));
      }
      return (Order.Builder) this;
    }


    /**
     * Sets or replaces all elements for {@link Order#getOrderLines() orderLines} list.
     * @param elements An iterable of orderLines elements
     * @return {@code this} builder for use in a chained invocation
     */
    @JsonProperty("lines")
    public final Order.Builder orderLines(Iterable<? extends OrderLine> elements) {
      this.orderLines.clear();
      return addAllOrderLines(elements);
    }

    /**
     * Adds elements to {@link Order#getOrderLines() orderLines} list.
     * @param elements An iterable of orderLines elements
     * @return {@code this} builder for use in a chained invocation
     */
    public final Order.Builder addAllOrderLines(Iterable<? extends OrderLine> elements) {
      for (OrderLine element : elements) {
        this.orderLines.add(Objects.requireNonNull(element, "orderLines element"));
      }
      return (Order.Builder) this;
    }

When deserializing everything works as expected. Jackson deserializes the order lines as it finds the @JsonProperty("lines") on the orderLines(Iterable<? extends OrderLine> elements) method.

When generated with strictBuilder = true the generated ImmutableOrder.Builder class gets
the following methods for the order lines collection:

/**
     * Adds one element to {@link Order#getOrderLines() orderLines} list.
     * @param element A orderLines element
     * @return {@code this} builder for use in a chained invocation
     */
    public final Order.Builder addOrderLines(OrderLine element) {
      this.orderLines.add(Objects.requireNonNull(element, "orderLines element"));
      return (Order.Builder) this;
    }

    /**
     * Adds elements to {@link Order#getOrderLines() orderLines} list.
     * @param elements An array of orderLines elements
     * @return {@code this} builder for use in a chained invocation
     */
    public final Order.Builder addOrderLines(OrderLine... elements) {
      for (OrderLine element : elements) {
        this.orderLines.add(Objects.requireNonNull(element, "orderLines element"));
      }
      return (Order.Builder) this;
    }
    
    /**
     * Adds elements to {@link Order#getOrderLines() orderLines} list.
     * @param elements An iterable of orderLines elements
     * @return {@code this} builder for use in a chained invocation
     */
    public final Order.Builder addAllOrderLines(Iterable<? extends OrderLine> elements) {
      for (OrderLine element : elements) {
        this.orderLines.add(Objects.requireNonNull(element, "orderLines element"));
      }
      return (Order.Builder) this;
    }

When deserializing Jackson fails with com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "lines" (class com.example.Order$Builder), not marked as ignorable (one known property: "id"]) at [Source: REDACTED ('StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION' disabled); line: 3, column: 13] (through reference chain: com.example.Order$Builder["lines"]).

The exception is thrown because there is no method annotated with @JsonProperty("lines") in the ImmutableOrder.Builder class. If the addAllOrderLines(Iterable<? extends OrderLine> elements) method get the annotation it all works again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant