package com.fasterxml.jackson.databind.jsontype.impl;
import java.util.*;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.DatabindContext;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.cfg.MapperConfig;
import com.fasterxml.jackson.databind.jsontype.NamedType;
public class TypeNameIdResolver extends TypeIdResolverBase
{
protected final MapperConfig<?> _config;
protected final Map<String, String> _typeToId;
protected final Map<String, JavaType> _idToType;
protected TypeNameIdResolver(MapperConfig<?> config, JavaType baseType,
Map<String, String> typeToId, Map<String, JavaType> idToType)
{
super(baseType, config.getTypeFactory());
_config = config;
_typeToId = typeToId;
_idToType = idToType;
}
public static TypeNameIdResolver construct(MapperConfig<?> config, JavaType baseType,
Collection<NamedType> subtypes, boolean forSer, boolean forDeser)
{
if (forSer == forDeser) throw new IllegalArgumentException();
Map<String, String> typeToId = null;
Map<String, JavaType> idToType = null;
if (forSer) {
typeToId = new HashMap<String, String>();
}
if (forDeser) {
idToType = new HashMap<String, JavaType>();
typeToId = new TreeMap<String, String>();
}
if (subtypes != null) {
for (NamedType t : subtypes) {
Class<?> cls = t.getType();
String id = t.hasName() ? t.getName() : _defaultTypeId(cls);
if (forSer) {
typeToId.put(cls.getName(), id);
}
if (forDeser) {
JavaType prev = idToType.get(id);
if (prev != null) {
if (cls.isAssignableFrom(prev.getRawClass())) {
continue;
}
}
idToType.put(id, config.constructType(cls));
}
}
}
return new TypeNameIdResolver(config, baseType, typeToId, idToType);
}
@Override
public JsonTypeInfo.Id getMechanism() { return JsonTypeInfo.Id.NAME; }
@Override
public String idFromValue(Object value) {
return idFromClass(value.getClass());
}
protected String idFromClass(Class<?> clazz)
{
if (clazz == null) {
return null;
}
Class<?> cls = _typeFactory.constructType(clazz).getRawClass();
final String key = cls.getName();
String name;
synchronized (_typeToId) {
name = _typeToId.get(key);
if (name == null) {
if (_config.isAnnotationProcessingEnabled()) {
BeanDescription beanDesc = _config.introspectClassAnnotations(cls);
name = _config.getAnnotationIntrospector().findTypeName(beanDesc.getClassInfo());
}
if (name == null) {
name = _defaultTypeId(cls);
}
_typeToId.put(key, name);
}
}
return name;
}
@Override
public String idFromValueAndType(Object value, Class<?> type) {
if (value == null) {
return idFromClass(type);
}
return idFromValue(value);
}
@Override
public JavaType typeFromId(DatabindContext context, String id) {
return _typeFromId(id);
}
protected JavaType _typeFromId(String id) {
return _idToType.get(id);
}
@Override
public String getDescForKnownTypeIds() {
return new TreeSet<String>(_idToType.keySet()).toString();
}
@Override
public String toString() {
return String.format("[%s; id-to-type=%s]", getClass().getName(), _idToType);
}
protected static String _defaultTypeId(Class<?> cls)
{
String n = cls.getName();
int ix = n.lastIndexOf('.');
return (ix < 0) ? n : n.substring(ix+1);
}
}