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

Can't deserialize an object with a single field in constructor #2984

Closed
Sam-Kruglov opened this issue Dec 13, 2020 · 3 comments
Closed

Can't deserialize an object with a single field in constructor #2984

Sam-Kruglov opened this issue Dec 13, 2020 · 3 comments

Comments

@Sam-Kruglov
Copy link

Describe the bug
The snippet below should be deserializable, I can't see what's wrong with it.

Also, it throws MismatchedInputException as if it's clients fault but it's not, so I suggest to throw a non-client subtype of JsonMappingException for the case over here (com.fasterxml.jackson.databind.DeserializationContext#handleMissingInstantiator):

msg = String.format("Cannot construct instance of %s (although at least one Creator exists): %s",

Also, it causes JsonMappingException#getPath to be empty, which was unexpected in my error handling. If there is no guarantee, it probably should be documented.

Version information
2.12.0

To Reproduce

static class Dto{
    private final String bla;

    Dto(String bla) {
        this.bla = bla;
    }

    public String getBla() {
        return bla;
    }
}
public static void main(String[] args) throws JsonProcessingException {
    val mapper = new ObjectMapper().findAndRegisterModules();
    mapper.readValue(mapper.writeValueAsString(new Dto("")), Dto.class);
}

Expected behavior
success

Actual behavior

Exception in thread "main" com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `Main$Dto` (although at least one Creator exists): cannot deserialize from Object value (no delegate- or property-based Creator)
 at [Source: (String)"{"bla":""}"; line: 1, column: 2]
	at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:63)
	at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1590)
	at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1215)
	at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1400)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:362)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:195)
	at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:322)
	at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4591)
	at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3546)
	at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3514)

Additional context
I have javac -parameters flag enabled.

If I add @JsonCreator onto the constructor then the example above works.

If I add a second field, then the example above works.

@Sam-Kruglov Sam-Kruglov added the to-evaluate Issue that has been received but not yet evaluated label Dec 13, 2020
@cowtowncoder
Copy link
Member

Ok, I suspect: this may be due to #2983, which would prevent registration of module needed to find parameter name. This in turn is related to problem that #1498 addresses: fundamental ambiguity for non-annotated single-argument constructor; what happens here is that constructor is assumed to be "delegating" one (although exception is slightly misleading as String-taking one is not considered as general-purpose one), but serialization is as JSON Object, not String.

If this is due to #2893 then solving that would solve this problem. I would however recommend either using new functionality from #1498 for making sure heuristics are not used if you always want Properties-based constructors and not delegating (you can still annotate if you want latter), or specifying

@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)

which will definitely declare what you want regardless of any other settings.

As to exception: I think it is actually client problem in the sense that there is a valid representation to send (JSON String) but client send something that is not valid for definition. But that is secondary issue here as your intent is to take JSON Object.

@cowtowncoder cowtowncoder removed the to-evaluate Issue that has been received but not yet evaluated label Dec 13, 2020
@Sam-Kruglov
Copy link
Author

I take it that was fixed? I can't find any info in the mentioned issues, they were closed before this one was opened

@cowtowncoder
Copy link
Member

@Sam-Kruglov Solution here is to either annotate constructor appropriately to ensure it is properties-based, or to use configuration functionality of #1498. Otherwise exact type (properties- or delegation-based) of the constructor is ambiguous and may or may not work as expected, depending on a few things, including whether user has registered Java 8 parameter name module or not. Original report did not indicate version information to indicate if it was thought to be regression or not but I am not aware of recent (2.10, 2.11, 2.12) changes that would affect behavior here.

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

2 participants