jackson-databind: Regression: 2.15.0 breaks deserialization for records when mapper.setVisibility(PropertyAccessor.ALL, Visibility.NONE);
Describe the bug This code used to work with 2.14.2, but not with 2.15.0
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, Visibility.NONE);
RecordTest recordTest_deserialized = mapper.readValue("{}", RecordTest.class);
Version information 2.15.0
To Reproduce
/**
* This works fine with Jackson 2.14.2, but not with 2.15.0.
*/
public class Jackson_2_15_0_Regression {
record RecordTest(String string, int integer) {
}
@Test
public void emptyJsonToRecord() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, Visibility.NONE);
// mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
RecordTest recordTest_deserialized = mapper.readValue("{}", RecordTest.class);
System.out.println("RecordTest deserialized: " + recordTest_deserialized);
Assert.assertEquals(new RecordTest(null, 0), recordTest_deserialized);
}
}
Comment out the mapper.setVisibility(PropertyAccessor.ALL, Visibility.NONE)
and it works.
Note that the commented-out mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY)
is included in my actual code to get intended behaviour (i.e. only fields are serialized and deserialized, no methods involved), but this did not make any to or from for the problem.
Exception is:
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `io.mats3.examples.jbang.Jackson_2_15_0_Regression$RecordTest` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: (String)"{}"; line: 1, column: 2]
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67)
at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1915)
at com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:414)
at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1360)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1424)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:352)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:185)
at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:323)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4825)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3772)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3740)
at io.mats3.examples.jbang.Jackson_2_15_0_Regression.emptyJsonToRecord(Jackson_2_15_0_Regression.java:25)
About this issue
- Original URL
- State: closed
- Created a year ago
- Comments: 30 (20 by maintainers)
Commits related to this issue
- Fix #3906 by forcing Record constructors to be visible regardless of overrides — committed to FasterXML/jackson-databind by cowtowncoder a year ago
- Fix #3906 by forcing Record constructors to be visible regardless of overrides — committed to FasterXML/jackson-databind by cowtowncoder a year ago
- Fix #3906 — committed to FasterXML/jackson-databind by cowtowncoder a year ago
- Split/fork test class for #3906: still failing for 3.0 for now — committed to FasterXML/jackson-databind by cowtowncoder a year ago
Need to wait for the core maintainers to make the final decision.
Creators are constructors or factory methods (with name
valueOf
) that have parameters, that will be used for deserialization - they are typically either annotated with@JsonCreator
or “magically” chosen.They are not related to, and nor will that config affects no-arg constructor.
You can use this with both
2.14
&2.15
, but it basically does nothing for2.14
(because again, deserialization was implemented differently). This is basically like number 1, except it only targets Record classes:As for changing Jackson to make Records’ creators always visibility regardless of config, I can/will create a PR if the core maintainers think that’s the way to go.
Yes, but I tried to mention:
It was an attempt to reduce the problem to the bare minimum.
@yihtserns:
No, as I said at top, I have both of:
The full init is:
It is here: https://github.com/centiservice/mats3/blob/main/mats-serial-json/src/main/java/io/mats3/serial/json/MatsSerializerJson.java#L120-L152 - now also with the attempt at handling the 5M chars-in-String limit.
Note: I had accepted that I always need a no-args constructor (as opposed to GSON). (Note: If it is possible to support missing no-args constructor for a class, even with Java 17+, that would be excellent!)
Exactly. Which is why I said: “yes, I agree, which makes me wonder a bit about this plan of jamming records and POJOs into the same regime, as seems suggested by @yihtserns?”
My point is that the construction of a Record and of a Class, and their population of fields, are rather different, so it sounds … ambitious … to do it with the same codebase/flow? Note, I do not try to dictate anything here, it is just an observation. But it would be nice if this - as seen from my side - regression - was not present!
One thing worth noting: Records are technically very different from POJOs/Beans, so there are challenges from Jackson implementation side. Especially regarding access to Record Fields; something that will start failing on newer JDKs. It is not certain handling can be fully unified.
I agree that it is important to be able to have value types, handling that works for both 2.14 and 2.15. But we really did not realize that there was Record usage that relied on explicit Visibility settings – there’s no testing so one can view at as unsupported use case, technically. Assumption rather was that usage wrt Records would use default visibility settings.