blob: dbab578ee9d9103123ddd5b4105822d1eaeb9537 [file] [log] [blame]
package com.fasterxml.jackson.databind.introspect;
import com.fasterxml.jackson.databind.AnnotationIntrospector;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
import com.fasterxml.jackson.databind.cfg.MapperConfig;
import com.fasterxml.jackson.databind.type.SimpleType;
public class BasicClassIntrospector
extends ClassIntrospector
implements java.io.Serializable
{
private static final long serialVersionUID = 1L;
/* We keep a small set of pre-constructed descriptions to use for
* common non-structured values, such as Numbers and Strings.
* This is strictly performance optimization to reduce what is
* usually one-time cost, but seems useful for some cases considering
* simplicity.
*/
protected final static BasicBeanDescription STRING_DESC;
static {
AnnotatedClass ac = AnnotatedClass.constructWithoutSuperTypes(String.class, null, null);
STRING_DESC = BasicBeanDescription.forOtherUse(null, SimpleType.constructUnsafe(String.class), ac);
}
protected final static BasicBeanDescription BOOLEAN_DESC;
static {
AnnotatedClass ac = AnnotatedClass.constructWithoutSuperTypes(Boolean.TYPE, null, null);
BOOLEAN_DESC = BasicBeanDescription.forOtherUse(null, SimpleType.constructUnsafe(Boolean.TYPE), ac);
}
protected final static BasicBeanDescription INT_DESC;
static {
AnnotatedClass ac = AnnotatedClass.constructWithoutSuperTypes(Integer.TYPE, null, null);
INT_DESC = BasicBeanDescription.forOtherUse(null, SimpleType.constructUnsafe(Integer.TYPE), ac);
}
protected final static BasicBeanDescription LONG_DESC;
static {
AnnotatedClass ac = AnnotatedClass.constructWithoutSuperTypes(Long.TYPE, null, null);
LONG_DESC = BasicBeanDescription.forOtherUse(null, SimpleType.constructUnsafe(Long.TYPE), ac);
}
/*
/**********************************************************
/* Life cycle
/**********************************************************
*/
public final static BasicClassIntrospector instance = new BasicClassIntrospector();
public BasicClassIntrospector() { }
/*
/**********************************************************
/* Factory method impls
/**********************************************************
*/
@Override
public BasicBeanDescription forSerialization(SerializationConfig cfg,
JavaType type, MixInResolver r)
{
// minor optimization: for JDK types do minimal introspection
BasicBeanDescription desc = _findCachedDesc(type);
if (desc == null) {
desc = BasicBeanDescription.forSerialization(collectProperties(cfg,
type, r, true, "set"));
}
return desc;
}
@Override
public BasicBeanDescription forDeserialization(DeserializationConfig cfg,
JavaType type, MixInResolver r)
{
// minor optimization: for JDK types do minimal introspection
BasicBeanDescription desc = _findCachedDesc(type);
if (desc == null) {
desc = BasicBeanDescription.forDeserialization(collectProperties(cfg,
type, r, false, "set"));
}
return desc;
}
@Override
public BasicBeanDescription forDeserializationWithBuilder(DeserializationConfig cfg,
JavaType type, MixInResolver r)
{
// no caching for Builders (no standard JDK builder types):
return BasicBeanDescription.forDeserialization(collectPropertiesWithBuilder(cfg,
type, r, false));
}
@Override
public BasicBeanDescription forCreation(DeserializationConfig cfg,
JavaType type, MixInResolver r)
{
BasicBeanDescription desc = _findCachedDesc(type);
if (desc == null) {
desc = BasicBeanDescription.forDeserialization(
collectProperties(cfg, type, r, false, "set"));
}
return desc;
}
@Override
public BasicBeanDescription forClassAnnotations(MapperConfig<?> cfg,
JavaType type, MixInResolver r)
{
boolean useAnnotations = cfg.isAnnotationProcessingEnabled();
AnnotatedClass ac = AnnotatedClass.construct(type.getRawClass(),
(useAnnotations ? cfg.getAnnotationIntrospector() : null), r);
return BasicBeanDescription.forOtherUse(cfg, type, ac);
}
@Override
public BasicBeanDescription forDirectClassAnnotations(MapperConfig<?> cfg,
JavaType type, MixInResolver r)
{
boolean useAnnotations = cfg.isAnnotationProcessingEnabled();
AnnotationIntrospector ai = cfg.getAnnotationIntrospector();
AnnotatedClass ac = AnnotatedClass.constructWithoutSuperTypes(type.getRawClass(),
(useAnnotations ? ai : null), r);
return BasicBeanDescription.forOtherUse(cfg, type, ac);
}
/*
/**********************************************************
/* Overridable helper methods
/**********************************************************
*/
protected POJOPropertiesCollector collectProperties(MapperConfig<?> config,
JavaType type, MixInResolver r, boolean forSerialization,
String mutatorPrefix)
{
boolean useAnnotations = config.isAnnotationProcessingEnabled();
AnnotatedClass ac = AnnotatedClass.construct(type.getRawClass(),
(useAnnotations ? config.getAnnotationIntrospector() : null), r);
return constructPropertyCollector(config, ac, type, forSerialization, mutatorPrefix).collect();
}
protected POJOPropertiesCollector collectPropertiesWithBuilder(MapperConfig<?> config,
JavaType type, MixInResolver r, boolean forSerialization)
{
boolean useAnnotations = config.isAnnotationProcessingEnabled();
AnnotationIntrospector ai = useAnnotations ? config.getAnnotationIntrospector() : null;
AnnotatedClass ac = AnnotatedClass.construct(type.getRawClass(), ai, r);
JsonPOJOBuilder.Value builderConfig = (ai == null) ? null : ai.findPOJOBuilderConfig(ac);
String mutatorPrefix = (builderConfig == null) ? "with" : builderConfig.withPrefix;
return constructPropertyCollector(config, ac, type, forSerialization, mutatorPrefix).collect();
}
/**
* Overridable method called for creating {@link POJOPropertiesCollector} instance
* to use; override is needed if a custom sub-class is to be used.
*/
protected POJOPropertiesCollector constructPropertyCollector(MapperConfig<?> config,
AnnotatedClass ac, JavaType type, boolean forSerialization, String mutatorPrefix)
{
return new POJOPropertiesCollector(config, forSerialization, type, ac, mutatorPrefix);
}
/**
* Method called to see if type is one of core JDK types
* that we have cached for efficiency.
*/
protected BasicBeanDescription _findCachedDesc(JavaType type)
{
Class<?> cls = type.getRawClass();
if (cls == String.class) {
return STRING_DESC;
}
if (cls == Boolean.TYPE) {
return BOOLEAN_DESC;
}
if (cls == Integer.TYPE) {
return INT_DESC;
}
if (cls == Long.TYPE) {
return LONG_DESC;
}
return null;
}
}