package com.fasterxml.jackson.databind.jsontype.impl;
import java.lang.reflect.Modifier;
import java.util.*;
import com.fasterxml.jackson.databind.AnnotationIntrospector;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.cfg.MapperConfig;
import com.fasterxml.jackson.databind.introspect.*;
import com.fasterxml.jackson.databind.jsontype.NamedType;
import com.fasterxml.jackson.databind.jsontype.SubtypeResolver;
public class StdSubtypeResolver
extends SubtypeResolver
implements java.io.Serializable
{
private static final long serialVersionUID = 1L;
protected LinkedHashSet<NamedType> _registeredSubtypes;
public StdSubtypeResolver() { }
@Override
public void registerSubtypes(NamedType... types) {
if (_registeredSubtypes == null) {
_registeredSubtypes = new LinkedHashSet<NamedType>();
}
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);
}
@Override
public void registerSubtypes(Collection<Class<?>> subtypes) {
int len = subtypes.size();
NamedType[] types = new NamedType[len];
int i = 0;
for (Class<?> subtype : subtypes) {
types[i++] = new NamedType(subtype);
}
registerSubtypes(types);
}
@Override
public Collection<NamedType> collectAndResolveSubtypesByClass(MapperConfig<?> config,
AnnotatedMember property, JavaType baseType)
{
final AnnotationIntrospector ai = config.getAnnotationIntrospector();
Class<?> rawBase = (baseType == null) ? property.getRawType() : baseType.getRawClass();
HashMap<NamedType, NamedType> collected = new HashMap<NamedType, NamedType>();
if (_registeredSubtypes != null) {
for (NamedType subtype : _registeredSubtypes) {
if (rawBase.isAssignableFrom(subtype.getType())) {
AnnotatedClass curr = AnnotatedClassResolver.resolveWithoutSuperTypes(config,
subtype.getType());
_collectAndResolve(curr, subtype, config, ai, collected);
}
}
}
if (property != null) {
Collection<NamedType> st = ai.findSubtypes(property);
if (st != null) {
for (NamedType nt : st) {
AnnotatedClass ac = AnnotatedClassResolver.resolveWithoutSuperTypes(config,
nt.getType());
_collectAndResolve(ac, nt, config, ai, collected);
}
}
}
NamedType rootType = new NamedType(rawBase, null);
AnnotatedClass ac = AnnotatedClassResolver.resolveWithoutSuperTypes(config, rawBase);
_collectAndResolve(ac, rootType, config, ai, collected);
return new ArrayList<NamedType>(collected.values());
}
@Override
public Collection<NamedType> collectAndResolveSubtypesByClass(MapperConfig<?> config,
AnnotatedClass type)
{
final AnnotationIntrospector ai = config.getAnnotationIntrospector();
HashMap<NamedType, NamedType> subtypes = new HashMap<NamedType, NamedType>();
if (_registeredSubtypes != null) {
Class<?> rawBase = type.getRawType();
for (NamedType subtype : _registeredSubtypes) {
if (rawBase.isAssignableFrom(subtype.getType())) {
AnnotatedClass curr = AnnotatedClassResolver.resolveWithoutSuperTypes(config,
subtype.getType());
_collectAndResolve(curr, subtype, config, ai, subtypes);
}
}
}
NamedType rootType = new NamedType(type.getRawType(), null);
_collectAndResolve(type, rootType, config, ai, subtypes);
return new ArrayList<NamedType>(subtypes.values());
}
@Override
public Collection<NamedType> collectAndResolveSubtypesByTypeId(MapperConfig<?> config,
AnnotatedMember property, JavaType baseType)
{
final AnnotationIntrospector ai = config.getAnnotationIntrospector();
Class<?> rawBase = baseType.getRawClass();
Set<Class<?>> typesHandled = new HashSet<Class<?>>();
Map<String,NamedType> byName = new LinkedHashMap<String,NamedType>();
NamedType rootType = new NamedType(rawBase, null);
AnnotatedClass ac = AnnotatedClassResolver.resolveWithoutSuperTypes(config,
rawBase);
_collectAndResolveByTypeId(ac, rootType, config, typesHandled, byName);
if (property != null) {
Collection<NamedType> st = ai.findSubtypes(property);
if (st != null) {
for (NamedType nt : st) {
ac = AnnotatedClassResolver.resolveWithoutSuperTypes(config, nt.getType());
_collectAndResolveByTypeId(ac, nt, config, typesHandled, byName);
}
}
}
if (_registeredSubtypes != null) {
for (NamedType subtype : _registeredSubtypes) {
if (rawBase.isAssignableFrom(subtype.getType())) {
AnnotatedClass curr = AnnotatedClassResolver.resolveWithoutSuperTypes(config,
subtype.getType());
_collectAndResolveByTypeId(curr, subtype, config, typesHandled, byName);
}
}
}
return _combineNamedAndUnnamed(rawBase, typesHandled, byName);
}
@Override
public Collection<NamedType> collectAndResolveSubtypesByTypeId(MapperConfig<?> config,
AnnotatedClass baseType)
{
final Class<?> rawBase = baseType.getRawType();
Set<Class<?>> typesHandled = new HashSet<Class<?>>();
Map<String,NamedType> byName = new LinkedHashMap<String,NamedType>();
NamedType rootType = new NamedType(rawBase, null);
_collectAndResolveByTypeId(baseType, rootType, config, typesHandled, byName);
if (_registeredSubtypes != null) {
for (NamedType subtype : _registeredSubtypes) {
if (rawBase.isAssignableFrom(subtype.getType())) {
AnnotatedClass curr = AnnotatedClassResolver.resolveWithoutSuperTypes(config,
subtype.getType());
_collectAndResolveByTypeId(curr, subtype, config, typesHandled, byName);
}
}
}
return _combineNamedAndUnnamed(rawBase, typesHandled, byName);
}
protected void _collectAndResolve(AnnotatedClass annotatedType, NamedType namedType,
MapperConfig<?> config, AnnotationIntrospector ai,
HashMap<NamedType, NamedType> collectedSubtypes)
{
if (!namedType.hasName()) {
String name = ai.findTypeName(annotatedType);
if (name != null) {
namedType = new NamedType(namedType.getType(), name);
}
}
if (collectedSubtypes.containsKey(namedType)) {
if (namedType.hasName()) {
NamedType prev = collectedSubtypes.get(namedType);
if (!prev.hasName()) {
collectedSubtypes.put(namedType, namedType);
}
}
return;
}
collectedSubtypes.put(namedType, namedType);
Collection<NamedType> st = ai.findSubtypes(annotatedType);
if (st != null && !st.isEmpty()) {
for (NamedType subtype : st) {
AnnotatedClass subtypeClass = AnnotatedClassResolver.resolveWithoutSuperTypes(config,
subtype.getType());
_collectAndResolve(subtypeClass, subtype, config, ai, collectedSubtypes);
}
}
}
protected void _collectAndResolveByTypeId(AnnotatedClass annotatedType, NamedType namedType,
MapperConfig<?> config,
Set<Class<?>> typesHandled, Map<String,NamedType> byName)
{
final AnnotationIntrospector ai = config.getAnnotationIntrospector();
if (!namedType.hasName()) {
String name = ai.findTypeName(annotatedType);
if (name != null) {
namedType = new NamedType(namedType.getType(), name);
}
}
if (namedType.hasName()) {
byName.put(namedType.getName(), namedType);
}
if (typesHandled.add(namedType.getType())) {
Collection<NamedType> st = ai.findSubtypes(annotatedType);
if (st != null && !st.isEmpty()) {
for (NamedType subtype : st) {
AnnotatedClass subtypeClass = AnnotatedClassResolver.resolveWithoutSuperTypes(config,
subtype.getType());
_collectAndResolveByTypeId(subtypeClass, subtype, config, typesHandled, byName);
}
}
}
}
protected Collection<NamedType> _combineNamedAndUnnamed(Class<?> rawBase,
Set<Class<?>> typesHandled, Map<String,NamedType> byName)
{
ArrayList<NamedType> result = new ArrayList<NamedType>(byName.values());
for (NamedType t : byName.values()) {
typesHandled.remove(t.getType());
}
for (Class<?> cls : typesHandled) {
if ((cls == rawBase) && Modifier.isAbstract(cls.getModifiers())) {
continue;
}
result.add(new NamedType(cls));
}
return result;
}
}