Lombok: Lombok 1.16.20 and Jackson 2.9.4 produces Jackson MismatchedInputException

Created on 15 Mar 2018  ·  12Comments  ·  Source: projectlombok/lombok

Given this class

@RequiredArgsConstructor()
public class ResponseObject
{
  public final String id;
}

And this simple code:

 final String json = "{\"id\":\"123\"}";
 final ObjectMapper objectMapper = new ObjectMapper();
 final ResponseObject responseObject1 = objectMapper.readValue(json, ResponseObject.class);

Produces the following exception:

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `dropbear.ResponseObject` (although at least one Creator exists): cannot deserialize from Object value (no delegate- or property-based Creator)
 at [Source: (String)"{"id":"123"}"; line: 1, column: 2]

Switching back to 1.16.18 resolves the error. Any Suggestions?

parked

Most helpful comment

As @mcherb menioned, in lombok.config you can add:

lombok.anyConstructor.addConstructorProperties=true

This is also mentioned in the changelog.

All 12 comments

This is highly likely to be caused by the fact that later versions of
lombok do not put a @Generated annotation on the generated constructor.
Mostly because java 9 puts that annotation semi-out of reach.
There is a lombok property to put that back, or you can put the
@JsonCreator annotation on the constructor by hand.

Disclaimer: I am not a member of the lombok team, I just lurk here ;-)

On Thu, Mar 15, 2018 at 5:45 PM, John Norton notifications@github.com
wrote:

Given this class

@RequiredArgsConstructor()
public class ResponseObject
{
public final String id;
}

And this simple code:

final String json = "{\"id\":\"123\"}";
final ObjectMapper objectMapper = new ObjectMapper();
final ResponseObject responseObject1 = objectMapper.readValue(json, ResponseObject.class);

Produces the following exception:

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of dropbear.ResponseObject (although at least one Creator exists): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: (String)"{"id":"123"}"; line: 1, column: 2]

Switching back to 1.16.18 resolves the error. Any Suggestions?


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/rzwitserloot/lombok/issues/1612, or mute the thread
https://github.com/notifications/unsubscribe-auth/AAKCRdIgC0WHmZwnu8EPR_9PJSHB1oHuks5tepq5gaJpZM4SsgNP
.

--
"Don't only practice your art, but force your way into it's secrets, for it
and knowledge can raise men to the divine."
-- Ludwig von Beethoven

Tried but no dice. Thanks for the suggestion.

Have you tried out the @ConstructorProperties annotation? Jackson 2.9.4 should be able to make use of that:

@RequiredArgsConstructor(onConstructor = @__({@ConstructorProperties({"id"})}))

@JsonCreator should work too, I think.

Op 16 mrt. 2018 23:28 schreef "Máté Szabó" notifications@github.com:

Have you tried out the @ConstructorProperties annotation? Jackson 2.9.4
should be able to make use of that:

@RequiredArgsConstructor(onConstructor = @__({@ConstructorProperties({"id"})}))


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/rzwitserloot/lombok/issues/1612#issuecomment-373861993,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAKCRRrkgYXu7YaITEFY5tz6-iwWF3gPks5tfDykgaJpZM4SsgNP
.

Similar problem with spring boot upgrade 1.5.8 -> 2.0.0
The behavior of creating classes has changed

Class example:

@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class A {
    @JsonProperty("id")
    private final long id;
}

Parsing json string:

A item = new ObjectMapper().readValue("{'id' : 10}", A.class);

Lombok 1.16.18 + Jackson 2.8.10 - _OK_
Lombok 1.16.20 + Jackson 2.9.4 - _Cannot construct instance of A (although at least one Creator exists): cannot deserialize from Object value (no delegate- or property-based Creator)_

i have the same problem when i migrated to v = 1.16.20.

java.lang.RuntimeException: com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of xx.xxx.xxx.Actions: no suitable constructor found, can not deserialize from Object value (missing default constructor or creator, or perhaps need to add/enable type information?)

but it works if i add the followings to lombok.config file:

lombok.anyConstructor.addConstructorProperties=true
config.stopBubbling = true

As @mcherb menioned, in lombok.config you can add:

lombok.anyConstructor.addConstructorProperties=true

This is also mentioned in the changelog.

Is this still an issue?

Yes

@chandresh-pancholi Can you explain how adding lombok.anyConstructor.addConstructorProperties=true to your lombok.config does not solve your problem?

Since v1.18.8 lombok added better understanding of @JsonProperty and @JsonSetter

Using @Value does not copy the @JsonProperty annotation on the constructor fields, however destructuring @Value has the intended behavior i.e. to copy the @JsonProperty on the constructor.

Here's the setup

  • lombok 1.18.10
  • jackson 2.10.1
  • lombok.config :
config.stopBubbling = true
lombok.addLombokGeneratedAnnotation = true

# https://github.com/rzwitserloot/lombok/issues/1563
# due to JDK9 compatibility lombok introduced a breaking change by removing the
# java.beans.ConstrustorProperties (because it belongs to java.desktop) from the
# generated constructors, the issue indicate one shoud add the following property
#
# lombok.anyConstructor.addConstructorProperties = true
#
# however it will still require anyone to import java.desktop, which is not
# what we want for a server. The issue can be avoided if the code uses a
# constructor compiled with the -parameters option which is the case here.
# So it is possible to keep this option to false.
#
# However jackson had special understanding of the ConstructorProperties for his
# dynamic way to guess how to instanciate some classes. Without this jackson failed
# to find the constructor, so some classes needed a small help by adding the @JsonCreator
# or add @JsonProperty on the constructor parameter (this issue helped me in the matter
# https://github.com/FasterXML/jackson-databind/issues/1318)


lombok.copyableAnnotations += com.fasterxml.jackson.annotation.JsonFormat

Adding lombok.copyableAnnotations += com.fasterxml.jackson.annotation.JsonProperty has no effect.

  • Deserialisation of {"apple_token":"token"} by new ObjectMapper().readValue(content, AppleToken.class);

  • Java 11

Using @Value only ❌

@Value
public class AppleToken {
    @JsonProperty("apple_token")
    String appleToken;
}
public final class AppleToken {
    @JsonProperty("apple_token")
    private final String appleToken;

    @Generated
    public AppleToken(final String appleToken) {
        this.appleToken = appleToken;
    }

    @Generated
    public String getAppleToken() {
        return this.appleToken;
    }

    @Generated
    public boolean equals(final Object o) {
        if (o == this) {
            return true;
        } else if (!(o instanceof AppleToken)) {
            return false;
        } else {
            AppleToken other = (AppleToken)o;
            Object this$appleToken = this.getAppleToken();
            Object other$appleToken = other.getAppleToken();
            if (this$appleToken == null) {
                if (other$appleToken != null) {
                    return false;
                }
            } else if (!this$appleToken.equals(other$appleToken)) {
                return false;
            }

            return true;
        }
    }

    @Generated
    public int hashCode() {
        int PRIME = true;
        int result = 1;
        Object $appleToken = this.getAppleToken();
        int result = result * 59 + ($appleToken == null ? 43 : $appleToken.hashCode());
        return result;
    }

    @Generated
    public String toString() {
        return "AppleToken(appleToken=" + this.getAppleToken() + ")";
    }
}

adding @JSonCreator(mode = Mode.PROPERTIES) on the constructor ❌

@Value
@AllArgsConstructor(onConstructor = @__(@JsonCreator(mode = Mode.PROPERTIES)))
public class AppleToken {
    @JsonProperty("apple_token")
    public final String appleToken;
}
public final class AppleToken {
    @JsonProperty("apple_token")
    private final String appleToken;

    @Generated
    public String getAppleToken() {
        return this.appleToken;
    }

    @Generated
    public boolean equals(final Object o) {
        if (o == this) {
            return true;
        } else if (!(o instanceof AppleToken)) {
            return false;
        } else {
            AppleToken other = (AppleToken)o;
            Object this$appleToken = this.getAppleToken();
            Object other$appleToken = other.getAppleToken();
            if (this$appleToken == null) {
                if (other$appleToken != null) {
                    return false;
                }
            } else if (!this$appleToken.equals(other$appleToken)) {
                return false;
            }

            return true;
        }
    }

    @Generated
    public int hashCode() {
        int PRIME = true;
        int result = 1;
        Object $appleToken = this.getAppleToken();
        int result = result * 59 + ($appleToken == null ? 43 : $appleToken.hashCode());
        return result;
    }

    @Generated
    public String toString() {
        return "AppleToken(appleToken=" + this.getAppleToken() + ")";
    }

    @JsonCreator(
        mode = Mode.PROPERTIES
    )
    @Generated
    public AppleToken(final String appleToken) {
        this.appleToken = appleToken;
    }
}

Destructuring @Value

@Getter
@FieldDefaults(makeFinal=true, level= AccessLevel.PRIVATE)
@EqualsAndHashCode
@ToString
@AllArgsConstructor
public class AppleToken {
    @JsonProperty("apple_token")
    String appleToken;
}
public class AppleToken {
    @JsonProperty("apple_token")
    String appleToken;

    @JsonProperty("apple_token")
    @Generated
    public String getAppleToken() {
        return this.appleToken;
    }

    @Generated
    public boolean equals(final Object o) {
        if (o == this) {
            return true;
        } else if (!(o instanceof AppleToken)) {
            return false;
        } else {
            AppleToken other = (AppleToken)o;
            if (!other.canEqual(this)) {
                return false;
            } else {
                Object this$appleToken = this.getAppleToken();
                Object other$appleToken = other.getAppleToken();
                if (this$appleToken == null) {
                    if (other$appleToken != null) {
                        return false;
                    }
                } else if (!this$appleToken.equals(other$appleToken)) {
                    return false;
                }

                return true;
            }
        }
    }

    @Generated
    protected boolean canEqual(final Object other) {
        return other instanceof AppleToken;
    }

    @Generated
    public int hashCode() {
        int PRIME = true;
        int result = 1;
        Object $appleToken = this.getAppleToken();
        int result = result * 59 + ($appleToken == null ? 43 : $appleToken.hashCode());
        return result;
    }

    @Generated
    public String toString() {
        return "AppleToken(appleToken=" + this.getAppleToken() + ")";
    }

    @Generated
    public AppleToken(@JsonProperty("apple_token") final String appleToken) {
        this.appleToken = appleToken;
    }
}

Destructuring @Value, with public final field and without getter ✅

//@Value
@FieldDefaults(makeFinal=true, level= AccessLevel.PUBLIC)
@EqualsAndHashCode
@ToString
@AllArgsConstructor
public class AppleToken {
    @JsonProperty("apple_token")
    String appleToken;
}
public class AppleToken {
    @JsonProperty("apple_token")
    public final String appleToken;

    @Generated
    public boolean equals(final Object o) {
        if (o == this) {
            return true;
        } else if (!(o instanceof AppleToken)) {
            return false;
        } else {
            AppleToken other = (AppleToken)o;
            if (!other.canEqual(this)) {
                return false;
            } else {
                Object this$appleToken = this.appleToken;
                Object other$appleToken = other.appleToken;
                if (this$appleToken == null) {
                    if (other$appleToken != null) {
                        return false;
                    }
                } else if (!this$appleToken.equals(other$appleToken)) {
                    return false;
                }

                return true;
            }
        }
    }

    @Generated
    protected boolean canEqual(final Object other) {
        return other instanceof AppleToken;
    }

    @Generated
    public int hashCode() {
        int PRIME = true;
        int result = 1;
        Object $appleToken = this.appleToken;
        int result = result * 59 + ($appleToken == null ? 43 : $appleToken.hashCode());
        return result;
    }

    @Generated
    public String toString() {
        return "AppleToken(appleToken=" + this.appleToken + ")";
    }

    @Generated
    public AppleToken(@JsonProperty("apple_token") final String appleToken) {
        this.appleToken = appleToken;
    }
}


edit: I'm not sure but I may have been played by the gradle cache when toggling the lombok.config (adding lombok.copyableAnnotations += com.fasterxml.jackson.annotation.JsonProperty)

Was this page helpful?
0 / 5 - 0 ratings