Skip to content

JsonInfoType Using annotationHolder as actual baseType for id as clas… #4988

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

Draft
wants to merge 1 commit into
base: 2.19
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all 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 @@ -1583,7 +1583,26 @@ protected TypeResolverBuilder<?> _findTypeResolver(MapperConfig<?> config,
if (typeInfo.getIdType() == JsonTypeInfo.Id.NONE) {
return _constructNoTypeResolverBuilder();
}
b = _constructStdTypeResolverBuilder(config, typeInfo, baseType);

// Search for the annotation through the parent classes/hierarchies
// BEWARE: What if the annotation appears on multiple places? Is there any specific ordering?
// Could/should this be a method of Annotated?
List<JavaType> superTypes;
if (ann instanceof AnnotatedClass) {
superTypes = new ArrayList<>(((AnnotatedClass) ann)._superTypes);
// We want to iterate from
// Collections.reverse(superTypes);
} else {
// Could walk the class hierarchy, but how can we get a JavaType from a Class?
superTypes = Collections.emptyList();
}
Optional<JavaType> optAnnotatedClass = superTypes.stream().filter(javaType -> null != javaType.getRawClass().getAnnotation(JsonTypeInfo.class)).findFirst();

// Fallback on the provided baseType if we can not find the annotation from the parent hierarchy of classes
// Or no fallback, as we want to keep the information later we had no clear annotationHolder
JavaType annotatedClass = optAnnotatedClass.orElse(null);

b = _constructStdTypeResolverBuilder(config, typeInfo, baseType, annotatedClass);
}
// Does it define a custom type id resolver?
JsonTypeIdResolver idResInfo = _findAnnotation(ann, JsonTypeIdResolver.class);
Expand Down Expand Up @@ -1624,12 +1643,13 @@ protected StdTypeResolverBuilder _constructStdTypeResolverBuilder() {
/**
* Helper method for constructing standard {@link TypeResolverBuilder}
* implementation.
* @param annotatedClass
*
* @since 2.16 (backported from Jackson 3.0)
*/
protected TypeResolverBuilder<?> _constructStdTypeResolverBuilder(MapperConfig<?> config,
JsonTypeInfo.Value typeInfo, JavaType baseType) {
return new StdTypeResolverBuilder(typeInfo);
JsonTypeInfo.Value typeInfo, JavaType baseType, JavaType annotatedClass) {
return new StdTypeResolverBuilder(typeInfo, annotatedClass);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ public class StdTypeResolverBuilder
protected JsonTypeInfo.Id _idType;

protected JsonTypeInfo.As _includeAs;

/**
* The type representing the base class. Typically the class holding the JsonTypeInfo annotation
*/
protected JavaType _jsonTypeInfoAnnotatedClass;

protected String _typeProperty;

Expand Down Expand Up @@ -91,10 +96,11 @@ protected StdTypeResolverBuilder(StdTypeResolverBuilder base,
/**
* @since 2.16
*/
public StdTypeResolverBuilder(JsonTypeInfo.Value settings) {
public StdTypeResolverBuilder(JsonTypeInfo.Value settings, JavaType annotatedClass) {
if (settings != null) {
withSettings(settings);
}
this._jsonTypeInfoAnnotatedClass = annotatedClass;
}

public static StdTypeResolverBuilder noTypeInfoBuilder() {
Expand Down Expand Up @@ -353,16 +359,19 @@ protected TypeIdResolver idResolver(MapperConfig<?> config,
// Custom id resolver?
if (_customIdResolver != null) { return _customIdResolver; }
if (_idType == null) throw new IllegalStateException("Cannot build, 'init()' not yet called");

JavaType actualBaseType = _jsonTypeInfoAnnotatedClass != null ? _jsonTypeInfoAnnotatedClass : baseType;

switch (_idType) {
case DEDUCTION: // Deduction produces class names to be resolved
case CLASS:
return ClassNameIdResolver.construct(baseType, config, subtypeValidator);
return ClassNameIdResolver.construct(actualBaseType, config, subtypeValidator);
case MINIMAL_CLASS:
return MinimalClassNameIdResolver.construct(baseType, config, subtypeValidator);
return MinimalClassNameIdResolver.construct(actualBaseType, config, subtypeValidator);
case SIMPLE_NAME:
return SimpleNameIdResolver.construct(config, baseType, subtypes, forSer, forDeser);
return SimpleNameIdResolver.construct(config, actualBaseType, subtypes, forSer, forDeser);
case NAME:
return TypeNameIdResolver.construct(config, baseType, subtypes, forSer, forDeser);
return TypeNameIdResolver.construct(config, actualBaseType, subtypes, forSer, forDeser);
case NONE: // hmmh. should never get this far with 'none'
return null;
case CUSTOM: // need custom resolver...
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.fasterxml.jackson.databind.jsontype;

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

import org.junit.jupiter.api.Test;

import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.TestSubtypesSubPackage.SuperType.InnerType;
import com.fasterxml.jackson.databind.jsontype.subpackage.SubCSubPackage;
import com.fasterxml.jackson.databind.testutil.DatabindTestUtil;

public class TestSubtypesSubPackage extends DatabindTestUtil
{
// Extended by SubCSubPackage which is in a sub package
@JsonTypeInfo(use=JsonTypeInfo.Id.MINIMAL_CLASS)
public static abstract class SuperType {

public static class InnerType extends SuperType {
public int b = 2;
}
}

/*
/**********************************************************
/* Unit tests
/**********************************************************
*/

private final ObjectMapper MAPPER = new ObjectMapper();

@Test
public void testSubPackage() throws Exception
{
// type should be computed consider base=SuperType (as it provides the annotation)
SubCSubPackage bean = new SubCSubPackage();
assertEquals("{\"@c\":\".subpackage.SubCSubPackage\",\"c\":2}", MAPPER.writeValueAsString(bean));
}

@Test
public void testInner() throws Exception
{
// type should be computed consider base=SuperType (as it provides the annotation)
InnerType bean = new InnerType();
assertEquals("{\"@c\":\".TestSubtypesSubPackage$SuperType$InnerType\",\"b\":2}", MAPPER.writeValueAsString(bean));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.fasterxml.jackson.databind.jsontype.subpackage;

import com.fasterxml.jackson.databind.jsontype.TestSubtypesSubPackage;

public class SubCSubPackage extends TestSubtypesSubPackage.SuperType {
public int c = 2;
}