com.couchbase.client.deps.com.fasterxml.jackson.databind.jsontype.impl.StdSubtypeResolver Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of core-io Show documentation
Show all versions of core-io Show documentation
The official Couchbase JVM Core IO Library
package com.couchbase.client.deps.com.fasterxml.jackson.databind.jsontype.impl;
import java.util.*;
import com.couchbase.client.deps.com.fasterxml.jackson.databind.AnnotationIntrospector;
import com.couchbase.client.deps.com.fasterxml.jackson.databind.JavaType;
import com.couchbase.client.deps.com.fasterxml.jackson.databind.cfg.MapperConfig;
import com.couchbase.client.deps.com.fasterxml.jackson.databind.introspect.*;
import com.couchbase.client.deps.com.fasterxml.jackson.databind.jsontype.NamedType;
import com.couchbase.client.deps.com.fasterxml.jackson.databind.jsontype.SubtypeResolver;
/**
* Standard {@link SubtypeResolver} implementation.
*/
public class StdSubtypeResolver
extends SubtypeResolver
implements java.io.Serializable
{
private static final long serialVersionUID = 1L;
protected LinkedHashSet _registeredSubtypes;
public StdSubtypeResolver() { }
/*
/**********************************************************
/* Public API
/**********************************************************
*/
@Override
public void registerSubtypes(NamedType... types) {
if (_registeredSubtypes == null) {
_registeredSubtypes = new LinkedHashSet();
}
for (NamedType type : types) {
_registeredSubtypes.add(type);
}
}
@Override
public void registerSubtypes(Class... classes) {
NamedType[] types = new NamedType[classes.length];
for (int i = 0, len = classes.length; i < len; ++i) {
types[i] = new NamedType(classes[i]);
}
registerSubtypes(types);
}
/**
*
* @param property Base member to use for type resolution: either annotated type (class),
* or property (field, getter/setter)
*
* @since 2.1
*/
@Override
public Collection collectAndResolveSubtypes(AnnotatedMember property,
MapperConfig config, AnnotationIntrospector ai, JavaType baseType)
{
// for backwards compatibility, must allow null here:
Class rawBase = (baseType == null) ? property.getRawType() : baseType.getRawClass();
HashMap collected = new HashMap();
// start with registered subtypes (which have precedence)
if (_registeredSubtypes != null) {
for (NamedType subtype : _registeredSubtypes) {
// is it a subtype of root type?
if (rawBase.isAssignableFrom(subtype.getType())) { // yes
AnnotatedClass curr = AnnotatedClass.constructWithoutSuperTypes(subtype.getType(), ai, config);
_collectAndResolve(curr, subtype, config, ai, collected);
}
}
}
// then annotated types for property itself
Collection st = ai.findSubtypes(property);
if (st != null) {
for (NamedType nt : st) {
AnnotatedClass ac = AnnotatedClass.constructWithoutSuperTypes(nt.getType(), ai, config);
_collectAndResolve(ac, nt, config, ai, collected);
}
}
NamedType rootType = new NamedType(rawBase, null);
AnnotatedClass ac = AnnotatedClass.constructWithoutSuperTypes(rawBase, ai, config);
// and finally subtypes via annotations from base type (recursively)
_collectAndResolve(ac, rootType, config, ai, collected);
return new ArrayList(collected.values());
}
@Override
public Collection collectAndResolveSubtypes(AnnotatedClass type,
MapperConfig config, AnnotationIntrospector ai)
{
HashMap subtypes = new HashMap();
// [JACKSON-257] then consider registered subtypes (which have precedence over annotations)
if (_registeredSubtypes != null) {
Class rawBase = type.getRawType();
for (NamedType subtype : _registeredSubtypes) {
// is it a subtype of root type?
if (rawBase.isAssignableFrom(subtype.getType())) { // yes
AnnotatedClass curr = AnnotatedClass.constructWithoutSuperTypes(subtype.getType(), ai, config);
_collectAndResolve(curr, subtype, config, ai, subtypes);
}
}
}
// and then check subtypes via annotations from base type (recursively)
NamedType rootType = new NamedType(type.getRawType(), null);
_collectAndResolve(type, rootType, config, ai, subtypes);
return new ArrayList(subtypes.values());
}
/*
/**********************************************************
/* Internal methods
/**********************************************************
*/
/**
* Method called to find subtypes for a specific type (class)
*/
protected void _collectAndResolve(AnnotatedClass annotatedType, NamedType namedType,
MapperConfig config, AnnotationIntrospector ai,
HashMap collectedSubtypes)
{
if (!namedType.hasName()) {
String name = ai.findTypeName(annotatedType);
if (name != null) {
namedType = new NamedType(namedType.getType(), name);
}
}
// First things first: is base type itself included?
if (collectedSubtypes.containsKey(namedType)) {
// if so, no recursion; however, may need to update name?
if (namedType.hasName()) {
NamedType prev = collectedSubtypes.get(namedType);
if (!prev.hasName()) {
collectedSubtypes.put(namedType, namedType);
}
}
return;
}
// if it wasn't, add and check subtypes recursively
collectedSubtypes.put(namedType, namedType);
Collection st = ai.findSubtypes(annotatedType);
if (st != null && !st.isEmpty()) {
for (NamedType subtype : st) {
AnnotatedClass subtypeClass = AnnotatedClass.constructWithoutSuperTypes(subtype.getType(), ai, config);
// One more thing: name may be either in reference, or in subtype:
if (!subtype.hasName()) {
subtype = new NamedType(subtype.getType(), ai.findTypeName(subtypeClass));
}
_collectAndResolve(subtypeClass, subtype, config, ai, collectedSubtypes);
}
}
}
}