-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Open
Labels
to-evaluateIssue that has been received but not yet evaluatedIssue that has been received but not yet evaluated
Description
Search before asking
- I searched in the issues and found nothing similar.
Describe the bug
import static org.assertj.core.api.Assertions.*;
import tools.jackson.databind.json.JsonMapper;
import java.util.stream.Stream;
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.TestFactory;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonUnwrapped;
class Jackson3Test {
@TestFactory
Stream<DynamicTest> usesFieldForDeserialization() {
var mapper = new JsonMapper();
var typeFactory = mapper.getTypeFactory();
var working = typeFactory.constructParametricType(Wrapper.class, WorkingSample.class);
var notWorking = typeFactory.constructParametricType(Wrapper.class, Sample.class);
var types = Stream.of(working, notWorking);
return DynamicTest.stream(types, "Should deserialize %s."::formatted, it -> {
Wrapper<? extends ValueLookup> result = mapper.readValue("""
{
"sampleValue" : "SampleValue"
}
""", it);
assertThat(result.getWrapped().getSampleValue()).isEqualTo("SampleValue");
});
}
public static class Wrapper<T> {
private T wrapped;
@JsonCreator
public Wrapper(T wrapped) {
this.wrapped = wrapped;
}
@JsonUnwrapped
public T getWrapped() {
return wrapped;
}
}
interface ValueLookup {
String getSampleValue();
}
// Does not consume the property as creator property
public static class Sample implements ValueLookup {
private String sampleValue;
public Sample() {}
@JsonProperty
public String getSampleValue() {
return sampleValue;
}
}
// Consumes the property as creator property
public static class WorkingSample implements ValueLookup {
private String sampleValue;
@JsonCreator
public WorkingSample(@JsonProperty("sampleValue") String sampleValue) {
this.sampleValue = sampleValue;
}
/**
* @return the sampleValue
*/
@JsonProperty
public String getSampleValue() {
return sampleValue;
}
}
}
Exception for the failing case:
tools.jackson.databind.exc.MismatchedInputException: Unexpected end-of-input when trying read value of type `example.three.Jackson3Test$Sample`
at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); byte offset: #UNKNOWN]
at tools.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:63)
at tools.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1821)
at tools.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1617)
at tools.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1566)
at tools.jackson.databind.deser.bean.BeanDeserializer._handleUnexpectedWithin(BeanDeserializer.java:1355)
at tools.jackson.databind.deser.bean.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:542)
at tools.jackson.databind.deser.bean.BeanDeserializer.deserialize(BeanDeserializer.java:200)
at tools.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:552)
at tools.jackson.databind.deser.impl.UnwrappedPropertyHandler.processUnwrappedCreatorProperties(UnwrappedPropertyHandler.java:86)
at tools.jackson.databind.deser.bean.BeanDeserializer.deserializeUsingPropertyBasedWithUnwrapped(BeanDeserializer.java:1134)
at tools.jackson.databind.deser.bean.BeanDeserializer.deserializeWithUnwrapped(BeanDeserializer.java:895)
at tools.jackson.databind.deser.bean.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:475)
at tools.jackson.databind.deser.bean.BeanDeserializer.deserialize(BeanDeserializer.java:200)
at tools.jackson.databind.deser.DeserializationContextExt.readRootValue(DeserializationContextExt.java:265)
at tools.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:2688)
at tools.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:1642)
at example.three.Jackson3Test.lambda$1(Jackson3Test.java:32)
at java.base/java.util.Optional.ifPresent(Optional.java:178)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
The crucial difference seems to be whether the wrapped type consumes the properties as creator properties. If it does, the instance creation pulls values from the buffer. If not, for some reason the parser seems to try to advance on the input. This works on the Jackson 2 (switch the import for JsonMapper
back to com.fasterxml.…
).
Version Information
No response
Reproduction
Expected behavior
No response
Additional context
No response
Metadata
Metadata
Assignees
Labels
to-evaluateIssue that has been received but not yet evaluatedIssue that has been received but not yet evaluated