RecordDeserialization3906Test.java
package com.fasterxml.jackson.databind.records;
import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.introspect.AnnotatedClass;
import com.fasterxml.jackson.databind.introspect.NopAnnotationIntrospector;
import com.fasterxml.jackson.databind.introspect.VisibilityChecker;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.testutil.DatabindTestUtil;
import static org.junit.jupiter.api.Assertions.*;
/**
* Test case that covers both failing-by-regression tests and passing tests.
* <p>For more details, refer to
* <a href="https://github.com/FasterXML/jackson-databind/issues/3906">
* [databind#3906]: Regression: 2.15.0 breaks deserialization for records when mapper.setVisibility(ALL, NONE);</a>
*/
public class RecordDeserialization3906Test extends DatabindTestUtil
{
record Record3906(String string, int integer) {
}
@JsonAutoDetect(creatorVisibility = Visibility.NON_PRIVATE)
record Record3906Annotated(String string, int integer) {
}
record Record3906Creator(String string, int integer) {
@JsonCreator
Record3906Creator {
}
}
private record PrivateRecord3906(String string, int integer) {
}
/*
/**********************************************************
/* Failing tests that pass in 2.14 (regression)
/**********************************************************
*/
// minimal config for reproduction
@Test
public void testEmptyJsonToRecordMiminal() throws JsonProcessingException {
ObjectMapper mapper = newJsonMapper();
mapper.setVisibility(PropertyAccessor.ALL, Visibility.NONE);
Record3906 recordDeser = mapper.readValue("{}", Record3906.class);
assertEquals(new Record3906(null, 0), recordDeser);
}
// actual config used reproduction
@Test
public void testEmptyJsonToRecordActualImpl() throws JsonProcessingException {
ObjectMapper mapper = newJsonMapper();
mapper.setVisibility(PropertyAccessor.ALL, Visibility.NONE);
mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
Record3906 recordDeser = mapper.readValue("{}", Record3906.class);
assertEquals(new Record3906(null, 0), recordDeser);
}
/*
/**********************************************************
/* Passing Tests : Suggested work-arounds
/* for future modifications
/**********************************************************
*/
@Test
public void testEmptyJsonToRecordWorkAround() throws JsonProcessingException {
ObjectMapper mapper = newJsonMapper();
mapper.setVisibility(PropertyAccessor.ALL, Visibility.NONE);
mapper.setVisibility(PropertyAccessor.CREATOR, Visibility.ANY);
Record3906 recordDeser = mapper.readValue("{}", Record3906.class);
assertEquals(new Record3906(null, 0), recordDeser);
}
@Test
public void testEmptyJsonToRecordCreatorsVisibile() throws JsonProcessingException {
ObjectMapper mapper = newJsonMapper();
mapper.setVisibility(PropertyAccessor.CREATOR, Visibility.NON_PRIVATE);
Record3906 recordDeser = mapper.readValue("{}", Record3906.class);
assertEquals(new Record3906(null, 0), recordDeser);
}
@SuppressWarnings("serial")
@Test
public void testEmptyJsonToRecordUsingModule() throws JsonProcessingException {
ObjectMapper mapper = jsonMapperBuilder().addModule(new SimpleModule() {
@Override
public void setupModule(SetupContext context) {
super.setupModule(context);
context.insertAnnotationIntrospector(new NopAnnotationIntrospector() {
@Override
public VisibilityChecker<?> findAutoDetectVisibility(AnnotatedClass ac,
VisibilityChecker<?> checker) {
return ac.getType().isRecordType()
? checker.withCreatorVisibility(JsonAutoDetect.Visibility.NON_PRIVATE)
: checker;
}
});
}
}).build();
Record3906 recordDeser = mapper.readValue("{}", Record3906.class);
assertEquals(new Record3906(null, 0), recordDeser);
}
@Test
public void testEmptyJsonToRecordDirectAutoDetectConfig() throws JsonProcessingException {
ObjectMapper mapper = newJsonMapper();
Record3906Annotated recordDeser = mapper.readValue("{}", Record3906Annotated.class);
assertEquals(new Record3906Annotated(null, 0), recordDeser);
}
@Test
public void testEmptyJsonToRecordJsonCreator() throws JsonProcessingException {
ObjectMapper mapper = newJsonMapper();
Record3906Creator recordDeser = mapper.readValue("{}", Record3906Creator.class);
assertEquals(new Record3906Creator(null, 0), recordDeser);
}
@SuppressWarnings("serial")
@Test
public void testEmptyJsonToRecordUsingModuleOther() throws JsonProcessingException {
ObjectMapper mapper = jsonMapperBuilder().addModule(
new SimpleModule() {
@Override
public void setupModule(SetupContext context) {
super.setupModule(context);
context.insertAnnotationIntrospector(new NopAnnotationIntrospector() {
@Override
public VisibilityChecker<?> findAutoDetectVisibility(AnnotatedClass ac,
VisibilityChecker<?> checker) {
if (ac.getType() == null) {
return checker;
}
if (!ac.getType().isRecordType()) {
return checker;
}
// If this is a Record, then increase the "creator" visibility again
return checker.withCreatorVisibility(Visibility.ANY);
}
});
}
})
.build();
assertEquals(new Record3906(null, 0),
mapper.readValue("{}", Record3906.class));
assertEquals(new PrivateRecord3906(null, 0),
mapper.readValue("{}", PrivateRecord3906.class));
}
}