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

Lombok 1.16.20 and Jackson 2.9.4 produces Jackson MismatchedInputException #1612

Open
johnnorton opened this issue Mar 15, 2018 · 15 comments
Open
Labels
parked Without further feedback this bug cannot be processed. If no feedback is provided, we close these.

Comments

@johnnorton
Copy link

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?

@randakar
Copy link

randakar commented Mar 15, 2018 via email

@johnnorton
Copy link
Author

johnnorton commented Mar 15, 2018

Tried but no dice. Thanks for the suggestion.

@mszabo-wikia
Copy link
Contributor

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

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

@randakar
Copy link

randakar commented Mar 17, 2018 via email

@xMandrake
Copy link

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)

@mcherb
Copy link

mcherb commented Apr 10, 2018

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

@rspilker
Copy link
Collaborator

rspilker commented Apr 11, 2018

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

lombok.anyConstructor.addConstructorProperties=true

This is also mentioned in the changelog.

@rspilker
Copy link
Collaborator

Is this still an issue?

@rspilker rspilker added the parked Without further feedback this bug cannot be processed. If no feedback is provided, we close these. label May 22, 2019
@chandresh-pancholi
Copy link

Yes

@rspilker
Copy link
Collaborator

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

@rspilker
Copy link
Collaborator

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

@bric3
Copy link

bric3 commented Feb 24, 2020

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)

@rajmondx
Copy link

rajmondx commented Sep 23, 2021

This is an extremely annoying issue.

I tried all provided solutions/hacks here (except using @JsonProperty because it would just take too much effort) and also tried to use the prev. generated class files as well but failed so far.

@rzwitserloot
Copy link
Collaborator

rzwitserloot commented Sep 23, 2021

@rajmondx We fixed it - see @rspilker's comment about adding addConstructorProperties to the config. If this fix doesn't work we need detailed information on what doesn't work. Alternatively, you'll have to wait for us to learn jackson, get familiar with it, attempt to figure out what the bug is that you're running into, and then fix it. We're kinda swamped, so I would expect that to take at least 4 years.

In other words, somebody familiar with JsonProperty needs to do the legwork. Make a project or jar or zip that can be used to readily reproduce the problem, which either stands on its own or includes a readme that spells out, starting with a vanilla java install and no knowledge of jackson, how to run it and what the desired result is. Explain why adding lombok.anyConstructor.addConstructorProperties=true doesn't work, or at least investigate and give us something on that topic.

For example, @bric3 talks about 'destructuring' but I have no idea what that means.

We have a few contributors that do appear to use jackson on a daily basis and they are not reporting any issues right now.

@janrieke
Copy link
Contributor

janrieke commented Sep 23, 2021

There's also a StackOverflow topic that covers this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
parked Without further feedback this bug cannot be processed. If no feedback is provided, we close these.
Projects
None yet
Development

No branches or pull requests