Skip to content

Make @JsonAlias be respected by polymorphic deduction for deserialization #4335

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

Merged
merged 16 commits into from
Jan 24, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;

import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.introspect.AnnotatedField;
import com.fasterxml.jackson.databind.introspect.AnnotatedMethod;
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
import com.fasterxml.jackson.databind.jsontype.NamedType;
import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
Expand Down Expand Up @@ -79,6 +82,12 @@ protected Map<BitSet, String> buildFingerprints(DeserializationConfig config, Co
bitIndex = nextField;
fieldBitIndex.put(name, nextField++);
}
// [databind#4327] 2.17 @JsonAlias should be respected by polymorphic deduction
List<String> aliases = _findAliases(config, property);
for (String alias : aliases) {
if (ignoreCase) alias = alias.toLowerCase();
fieldBitIndex.put(alias, bitIndex);
}
fingerprint.set(bitIndex);
}

Expand All @@ -94,6 +103,37 @@ protected Map<BitSet, String> buildFingerprints(DeserializationConfig config, Co
return fingerprints;
}

private List<String> _findAliases(DeserializationConfig config, BeanPropertyDefinition property)
{
AnnotationIntrospector ai = config.getAnnotationIntrospector();
List<PropertyName> aliases = new ArrayList<>();
AnnotatedField field = property.getField();
AnnotatedMethod setter = property.getSetter();
AnnotatedMethod getter = property.getGetter();

if (setter != null) {
List<PropertyName> names = ai.findPropertyAliases(setter);
if (names != null) {
aliases.addAll(names);
}
}
if (getter != null) {
List<PropertyName> names = ai.findPropertyAliases(getter);
if (names != null) {
aliases.addAll(names);
}
}
if (field != null) {
List<PropertyName> names = ai.findPropertyAliases(field);
if (names != null) {
aliases.addAll(names);
}
}
return aliases.stream()
.map(PropertyName::getSimpleName)
.collect(Collectors.toList());
}

@Override
public Object deserializeTypedFromObject(JsonParser p, DeserializationContext ctxt) throws IOException {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.fasterxml.jackson.databind.records;

import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

import com.fasterxml.jackson.databind.ObjectMapper;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

import static com.fasterxml.jackson.databind.testutil.DatabindTestUtil.a2q;
import static com.fasterxml.jackson.databind.testutil.DatabindTestUtil.jsonMapperBuilder;

// [databind#4327] JsonAlias should respsect with Polymorphic Deduction
public class JsonAliasWithDeduction4327RecordTest
{
@JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION)
@JsonSubTypes({
@JsonSubTypes.Type(value = DeductionBean1.class),
@JsonSubTypes.Type(value = DeductionBean2.class)
})
interface Deduction { }

record DeductionBean1(int x) implements Deduction { }

record DeductionBean2(
@JsonAlias(value = {"Y", "yy", "ff", "X"}) int y
) implements Deduction { }


private final ObjectMapper mapper = jsonMapperBuilder().build();

@ParameterizedTest
@ValueSource(strings = {"Y", "yy", "ff", "X"})
public void testAliasWithPolymorphicDeduction(String field) throws Exception {
String json = a2q(String.format("{'%s': 2 }", field));
Deduction value = mapper.readValue(json, Deduction.class);
assertNotNull(value);
assertEquals(2, ((DeductionBean2) value).y());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.fasterxml.jackson.databind.jsontype;

import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

import com.fasterxml.jackson.databind.ObjectMapper;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

import static com.fasterxml.jackson.databind.testutil.DatabindTestUtil.a2q;
import static com.fasterxml.jackson.databind.testutil.DatabindTestUtil.jsonMapperBuilder;

// [databind#4327] JsonAlias should respsect with Polymorphic Deduction
public class JsonAliasWithDeduction4327Test
{
@JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION)
@JsonSubTypes({
@JsonSubTypes.Type(value = DeductionBean1.class),
@JsonSubTypes.Type(value = DeductionBean2.class)
})
interface Deduction { }

static class DeductionBean1 implements Deduction {
public int x;
}

static class DeductionBean2 implements Deduction {
@JsonAlias(value = {"Y", "yy", "ff", "X"})
public int y;
}


private final ObjectMapper mapper = jsonMapperBuilder().build();

@ParameterizedTest
@ValueSource(strings = {"Y", "yy", "ff", "X"})
public void testAliasWithPolymorphicDeduction(String field) throws Exception {
String json = a2q(String.format("{'%s': 2 }", field));
Deduction value = mapper.readValue(json, Deduction.class);
assertNotNull(value);
assertEquals(2, ((DeductionBean2) value).y);
}
}