CurrentValueDeser5980Test.java
package tools.jackson.databind.ser.filter;
import java.util.List;
import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.annotation.*;
import tools.jackson.core.JsonParser;
import tools.jackson.databind.*;
import tools.jackson.databind.annotation.JsonDeserialize;
import tools.jackson.databind.testutil.DatabindTestUtil;
import static org.junit.jupiter.api.Assertions.*;
// [databind#5980]: property-based-creator deserialization of an earlier property
// must not clobber the enclosing value's `JsonParser.currentValue()`
public class CurrentValueDeser5980Test extends DatabindTestUtil
{
static class Project {
public Source source;
@JsonDeserialize(using = AssetDeserializer.class)
public List<Asset> assets;
}
// Properties-based creator (simulates `-parameters` / Lombok @AllArgsConstructor auto-detection)
static class Source {
public String id;
@JsonCreator
public Source(@JsonProperty("id") String id) { this.id = id; }
}
// Properties-based creator AND has an `@JsonUnwrapped` property: exercises the
// `deserializeUsingPropertyBasedWithUnwrapped()` path.
static class UnwrappedSource {
String id;
Name name;
@JsonCreator
public UnwrappedSource(@JsonProperty("id") String id) { this.id = id; }
@JsonUnwrapped
public void setName(Name name) { this.name = name; }
}
static class Name {
public String first;
public String last;
}
static class ProjectWithUnwrapped {
public UnwrappedSource source;
@JsonDeserialize(using = AssetDeserializer.class)
public List<Asset> assets;
}
static class Asset {
public String name;
}
// Captures `currentValue()` seen while deserializing the `assets` property,
// so each test can positively assert the expected enclosing type.
static Object CURRENT_VALUE;
// Consume the whole array first (pops stream context back to enclosing object),
// then capture currentValue -- as the reporter's deserializer does.
static class AssetDeserializer extends ValueDeserializer<List<Asset>> {
@Override
public List<Asset> deserialize(JsonParser p, DeserializationContext ctxt) {
p.readValueAsTree();
CURRENT_VALUE = p.currentValue();
return List.of();
}
}
/*
/**********************************************************************
/* Test methods
/**********************************************************************
*/
private final ObjectMapper MAPPER = newJsonMapper();
// Property-based creator sibling must not clobber enclosing currentValue
@Test
public void currentValueNotClobberedByCreator() throws Exception {
CURRENT_VALUE = null;
String json = """
{ "source": { "id": "s1" }, "assets": [ { "name": "a1" } ] }
""";
MAPPER.readValue(json, Project.class);
assertInstanceOf(Project.class, CURRENT_VALUE);
}
// Same, but for the property-based-creator + `@JsonUnwrapped` path
@Test
public void currentValueNotClobberedByUnwrappedCreator() throws Exception {
CURRENT_VALUE = null;
String json = """
{ "source": { "id": "s1", "first": "Bob", "last": "Smith" },
"assets": [ { "name": "a1" } ] }
""";
MAPPER.readValue(json, ProjectWithUnwrapped.class);
assertInstanceOf(ProjectWithUnwrapped.class, CURRENT_VALUE);
}
}