Skip to content

Commit

Permalink
Re-route introspect calls via context, to allow for per-context reuse
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Apr 27, 2018
1 parent 54dc162 commit f56b0c1
Show file tree
Hide file tree
Showing 15 changed files with 86 additions and 50 deletions.
Expand Up @@ -609,23 +609,20 @@ public LinkedNode<DeserializationProblemHandler> getProblemHandlers() {
* *
* @param type Type of class to be introspected * @param type Type of class to be introspected
*/ */
@SuppressWarnings("unchecked") public BeanDescription introspect(JavaType type) {
public <T extends BeanDescription> T introspect(JavaType type) { return getClassIntrospector().forDeserialization(this, type, this);
return (T) getClassIntrospector().forDeserialization(this, type, this);
} }


/** /**
* Method that will introspect subset of bean properties needed to * Method that will introspect subset of bean properties needed to
* construct bean instance. * construct bean instance.
*/ */
@SuppressWarnings("unchecked") public BeanDescription introspectForCreation(JavaType type) {
public <T extends BeanDescription> T introspectForCreation(JavaType type) { return getClassIntrospector().forCreation(this, type, this);
return (T) getClassIntrospector().forCreation(this, type, this);
} }


@SuppressWarnings("unchecked") public BeanDescription introspectForBuilder(JavaType type) {
public <T extends BeanDescription> T introspectForBuilder(JavaType type) { return getClassIntrospector().forDeserializationWithBuilder(this, type, this);
return (T) getClassIntrospector().forDeserializationWithBuilder(this, type, this);
} }


/* /*
Expand Down
Expand Up @@ -451,6 +451,28 @@ public final JsonNodeFactory getNodeFactory() {
return _config.getNodeFactory(); return _config.getNodeFactory();
} }


/*
/**********************************************************************
/* Introspection support
/**********************************************************************
*/

/**
* Convenience method for doing full "for serialization" introspection of specified
* type; results may be cached during lifespan of this context as well.
*/
public BeanDescription introspect(JavaType type) throws JsonMappingException {
return _config.introspect(type);
}

public BeanDescription introspectForCreation(JavaType type) throws JsonMappingException{
return _config.introspectForCreation(type);
}

public BeanDescription introspectForBuilder(JavaType type) throws JsonMappingException {
return _config.introspectForBuilder(type);
}

/* /*
/********************************************************************** /**********************************************************************
/* Public API, pass-through to DeserializerCache /* Public API, pass-through to DeserializerCache
Expand Down
Expand Up @@ -555,8 +555,7 @@ public PrettyPrinter getDefaultPrettyPrinter() {
* Method that will introspect full bean properties for the purpose * Method that will introspect full bean properties for the purpose
* of building a bean serializer * of building a bean serializer
*/ */
@SuppressWarnings("unchecked") public BeanDescription introspect(JavaType type) {
public <T extends BeanDescription> T introspect(JavaType type) { return getClassIntrospector().forSerialization(this, type, this);
return (T) getClassIntrospector().forSerialization(this, type, this);
} }
} }
Expand Up @@ -415,6 +415,26 @@ public JsonGenerator getGenerator() {
public abstract WritableObjectId findObjectId(Object forPojo, public abstract WritableObjectId findObjectId(Object forPojo,
ObjectIdGenerator<?> generatorType); ObjectIdGenerator<?> generatorType);


/*
/**********************************************************************
/* Introspection support
/**********************************************************************
*/

/**
* Convenience method for doing full "for serialization" introspection of specified
* type; results may be cached during lifespan of this context as well.
*/
public BeanDescription introspect(JavaType type) throws JsonMappingException
{
return _config.introspect(type);
}

public BeanDescription introspectClassAnnotations(JavaType type) throws JsonMappingException
{
return _config.introspectClassAnnotations(type);
}

/* /*
/********************************************************************** /**********************************************************************
/* Serializer discovery: root/non-property value serializers /* Serializer discovery: root/non-property value serializers
Expand Down Expand Up @@ -665,7 +685,7 @@ public JsonSerializer<Object> findKeySerializer(JavaType keyType, BeanProperty p
{ {
// 16-Mar-2018, tatu: Used to have "default key serializer" in 2.x; dropped to let/make // 16-Mar-2018, tatu: Used to have "default key serializer" in 2.x; dropped to let/make
// custom code use Module interface or similar to provide key serializers // custom code use Module interface or similar to provide key serializers
JsonSerializer<Object> ser = _serializerFactory.createKeySerializer(_config, keyType, null); JsonSerializer<Object> ser = _serializerFactory.createKeySerializer(this, keyType, null);
// _handleContextualResolvable(ser, property): // _handleContextualResolvable(ser, property):
ser.resolve(this); ser.resolve(this);
return handleSecondaryContextualization(ser, property); return handleSecondaryContextualization(ser, property);
Expand Down Expand Up @@ -766,7 +786,7 @@ protected JsonSerializer<Object> _createAndCacheUntypedSerializer(Class<?> rawTy
throws JsonMappingException throws JsonMappingException
{ {
// Important: must introspect all annotations, not just class // Important: must introspect all annotations, not just class
BeanDescription beanDesc = _config.introspect(fullType); BeanDescription beanDesc = introspect(fullType);
JsonSerializer<Object> ser; JsonSerializer<Object> ser;
try { try {
ser = _serializerFactory.createSerializer(this, fullType, beanDesc, null); ser = _serializerFactory.createSerializer(this, fullType, beanDesc, null);
Expand All @@ -783,7 +803,7 @@ protected JsonSerializer<Object> _createAndCacheUntypedSerializer(JavaType type)
throws JsonMappingException throws JsonMappingException
{ {
// Important: must introspect all annotations, not just class // Important: must introspect all annotations, not just class
BeanDescription beanDesc = _config.introspect(type); BeanDescription beanDesc = introspect(type);
JsonSerializer<Object> ser; JsonSerializer<Object> ser;
try { try {
ser = _serializerFactory.createSerializer(this, type, beanDesc, null); ser = _serializerFactory.createSerializer(this, type, beanDesc, null);
Expand Down
Expand Up @@ -273,20 +273,15 @@ public BeanDescription introspectClassAnnotations(JavaType type) {
return getClassIntrospector().forClassAnnotations(this, type, this); return getClassIntrospector().forClassAnnotations(this, type, this);
} }


// 27-Apr-2018, tatu: Appears not to be needed?
/** /**
* Accessor for getting bean description that only contains immediate class * Accessor for getting bean description that only contains immediate class
* annotations: ones from the class, and its direct mix-in, if any, but * annotations: ones from the class, and its direct mix-in, if any, but
* not from super types. * not from super types.
*
* @deprecated Since 3.0
*/ */
public BeanDescription introspectDirectClassAnnotations(Class<?> cls) { @Deprecated // since 3.0
return introspectDirectClassAnnotations(constructType(cls));
}

/**
* Accessor for getting bean description that only contains immediate class
* annotations: ones from the class, and its direct mix-in, if any, but
* not from super types.
*/
public final BeanDescription introspectDirectClassAnnotations(JavaType type) { public final BeanDescription introspectDirectClassAnnotations(JavaType type) {
return getClassIntrospector().forDirectClassAnnotations(this, type, this); return getClassIntrospector().forDirectClassAnnotations(this, type, this);
} }
Expand Down
Expand Up @@ -1184,7 +1184,7 @@ public JsonDeserializer<?> createCollectionDeserializer(DeserializationContext c
} else { } else {
type = implType; type = implType;
// But if so, also need to re-check creators... // But if so, also need to re-check creators...
beanDesc = config.introspectForCreation(type); beanDesc = ctxt.introspectForCreation(type);
} }
} }
if (deser == null) { if (deser == null) {
Expand Down Expand Up @@ -1336,7 +1336,7 @@ public JsonDeserializer<?> createMapDeserializer(DeserializationContext ctxt,
mapClass = fallback; mapClass = fallback;
type = (MapType) config.constructSpecializedType(type, mapClass); type = (MapType) config.constructSpecializedType(type, mapClass);
// But if so, also need to re-check creators... // But if so, also need to re-check creators...
beanDesc = config.introspectForCreation(type); beanDesc = ctxt.introspectForCreation(type);
} else { } else {
// [databind#292]: Actually, may be fine, but only if polymorphic deser enabled // [databind#292]: Actually, may be fine, but only if polymorphic deser enabled
if (type.getTypeHandler() == null) { if (type.getTypeHandler() == null) {
Expand Down Expand Up @@ -1637,7 +1637,7 @@ public KeyDeserializer createKeyDeserializer(DeserializationContext ctxt,
if (type.isEnumType()) { if (type.isEnumType()) {
deser = _createEnumKeyDeserializer(ctxt, type); deser = _createEnumKeyDeserializer(ctxt, type);
} else { } else {
deser = StdKeyDeserializers.findStringBasedKeyDeserializer(config, type); deser = StdKeyDeserializers.findStringBasedKeyDeserializer(ctxt, type);
} }
} }
// and then post-processing // and then post-processing
Expand All @@ -1658,7 +1658,7 @@ private KeyDeserializer _createEnumKeyDeserializer(DeserializationContext ctxt,
final DeserializationConfig config = ctxt.getConfig(); final DeserializationConfig config = ctxt.getConfig();
Class<?> enumClass = type.getRawClass(); Class<?> enumClass = type.getRawClass();


BeanDescription beanDesc = config.introspect(type); BeanDescription beanDesc = ctxt.introspect(type);
// 24-Sep-2015, bim: a key deserializer is the preferred thing. // 24-Sep-2015, bim: a key deserializer is the preferred thing.
KeyDeserializer des = findKeyDeserializerFromAnnotation(ctxt, beanDesc.getClassInfo()); KeyDeserializer des = findKeyDeserializerFromAnnotation(ctxt, beanDesc.getClassInfo());
if (des != null) { if (des != null) {
Expand Down
Expand Up @@ -114,7 +114,7 @@ public JsonDeserializer<Object> createBeanDeserializer(DeserializationContext ct
if (concreteType != null) { if (concreteType != null) {
// important: introspect actual implementation (abstract class or // important: introspect actual implementation (abstract class or
// interface doesn't have constructors, for one) // interface doesn't have constructors, for one)
beanDesc = config.introspect(concreteType); beanDesc = ctxt.introspect(concreteType);
return buildBeanDeserializer(ctxt, concreteType, beanDesc); return buildBeanDeserializer(ctxt, concreteType, beanDesc);
} }
} }
Expand Down Expand Up @@ -148,7 +148,7 @@ public JsonDeserializer<Object> createBuilderBasedDeserializer(
} else { } else {
builderType = ctxt.constructType(builderClass); builderType = ctxt.constructType(builderClass);
} }
BeanDescription builderDesc = ctxt.getConfig().introspectForBuilder(builderType); BeanDescription builderDesc = ctxt.introspectForBuilder(builderType);
return buildBuilderBasedDeserializer(ctxt, valueType, builderDesc); return buildBuilderBasedDeserializer(ctxt, valueType, builderDesc);
} }


Expand Down
Expand Up @@ -329,7 +329,7 @@ protected JsonDeserializer<Object> _createDeserializer(DeserializationContext ct
if (type.isAbstract() || type.isMapLikeType() || type.isCollectionLikeType()) { if (type.isAbstract() || type.isMapLikeType() || type.isCollectionLikeType()) {
type = config.mapAbstractType(type); type = config.mapAbstractType(type);
} }
BeanDescription beanDesc = config.introspect(type); BeanDescription beanDesc = ctxt.introspect(type);
// Then: does type define explicit deserializer to use, with annotation(s)? // Then: does type define explicit deserializer to use, with annotation(s)?
JsonDeserializer<Object> deser = findDeserializerFromAnnotation(ctxt, JsonDeserializer<Object> deser = findDeserializerFromAnnotation(ctxt,
beanDesc.getClassInfo()); beanDesc.getClassInfo());
Expand All @@ -341,7 +341,7 @@ protected JsonDeserializer<Object> _createDeserializer(DeserializationContext ct
JavaType newType = modifyTypeByAnnotation(ctxt, beanDesc.getClassInfo(), type); JavaType newType = modifyTypeByAnnotation(ctxt, beanDesc.getClassInfo(), type);
if (newType != type) { if (newType != type) {
type = newType; type = newType;
beanDesc = config.introspect(newType); beanDesc = ctxt.introspect(newType);
} }


// We may also have a Builder type to consider... // We may also have a Builder type to consider...
Expand All @@ -360,7 +360,7 @@ protected JsonDeserializer<Object> _createDeserializer(DeserializationContext ct
JavaType delegateType = conv.getInputType(ctxt.getTypeFactory()); JavaType delegateType = conv.getInputType(ctxt.getTypeFactory());
// One more twist, as per [databind#288]; probably need to get new BeanDesc // One more twist, as per [databind#288]; probably need to get new BeanDesc
if (!delegateType.hasRawClass(type.getRawClass())) { if (!delegateType.hasRawClass(type.getRawClass())) {
beanDesc = config.introspect(delegateType); beanDesc = ctxt.introspect(delegateType);
} }
return new StdDelegatingDeserializer<Object>(conv, delegateType, return new StdDelegatingDeserializer<Object>(conv, delegateType,
_createDeserializer2(ctxt, factory, delegateType, beanDesc)); _createDeserializer2(ctxt, factory, delegateType, beanDesc));
Expand Down
Expand Up @@ -45,18 +45,19 @@ public static KeyDeserializer constructDelegatingKeyDeserializer(Deserialization
return new StdKeyDeserializer.DelegatingKD(type.getRawClass(), deser); return new StdKeyDeserializer.DelegatingKD(type.getRawClass(), deser);
} }


public static KeyDeserializer findStringBasedKeyDeserializer(DeserializationConfig config, public static KeyDeserializer findStringBasedKeyDeserializer(DeserializationContext ctxt,
JavaType type) JavaType type)
throws JsonMappingException
{ {
/* We don't need full deserialization information, just need to /* We don't need full deserialization information, just need to
* know creators. * know creators.
*/ */
BeanDescription beanDesc = config.introspect(type); BeanDescription beanDesc = ctxt.introspect(type);
// Ok, so: can we find T(String) constructor? // Ok, so: can we find T(String) constructor?
Constructor<?> ctor = beanDesc.findSingleArgConstructor(String.class); Constructor<?> ctor = beanDesc.findSingleArgConstructor(String.class);
if (ctor != null) { if (ctor != null) {
if (config.canOverrideAccessModifiers()) { if (ctxt.canOverrideAccessModifiers()) {
ClassUtil.checkAndFixAccess(ctor, config.isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS)); ClassUtil.checkAndFixAccess(ctor, ctxt.isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS));
} }
return new StdKeyDeserializer.StringCtorKeyDeserializer(ctor); return new StdKeyDeserializer.StringCtorKeyDeserializer(ctor);
} }
Expand All @@ -65,8 +66,8 @@ public static KeyDeserializer findStringBasedKeyDeserializer(DeserializationConf
*/ */
Method m = beanDesc.findFactoryMethod(String.class); Method m = beanDesc.findFactoryMethod(String.class);
if (m != null){ if (m != null){
if (config.canOverrideAccessModifiers()) { if (ctxt.canOverrideAccessModifiers()) {
ClassUtil.checkAndFixAccess(m, config.isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS)); ClassUtil.checkAndFixAccess(m, ctxt.isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS));
} }
return new StdKeyDeserializer.StringFactoryKeyDeserializer(m); return new StdKeyDeserializer.StringFactoryKeyDeserializer(m);
} }
Expand Down
Expand Up @@ -179,12 +179,14 @@ public final SerializerFactory withNullKeySerializer(JsonSerializer<?> nks) {


@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public JsonSerializer<Object> createKeySerializer(SerializationConfig config, public JsonSerializer<Object> createKeySerializer(SerializerProvider ctxt,
JavaType keyType, JsonSerializer<Object> defaultImpl) JavaType keyType, JsonSerializer<Object> defaultImpl)
throws JsonMappingException
{ {
// We should not need any member method info; at most class annotations for Map type // We should not need any member method info; at most class annotations for Map type
// ... at least, not here. // ... at least, not here.
BeanDescription beanDesc = config.introspectClassAnnotations(keyType.getRawClass()); BeanDescription beanDesc = ctxt.introspectClassAnnotations(keyType);
final SerializationConfig config = ctxt.getConfig();
JsonSerializer<?> ser = null; JsonSerializer<?> ser = null;
// Minor optimization: to avoid constructing beanDesc, bail out if none registered // Minor optimization: to avoid constructing beanDesc, bail out if none registered
if (_factoryConfig.hasKeySerializers()) { if (_factoryConfig.hasKeySerializers()) {
Expand All @@ -200,7 +202,7 @@ public JsonSerializer<Object> createKeySerializer(SerializationConfig config,
ser = StdKeySerializers.getStdKeySerializer(config, keyType.getRawClass(), false); ser = StdKeySerializers.getStdKeySerializer(config, keyType.getRawClass(), false);
// As per [databind#47], also need to support @JsonValue // As per [databind#47], also need to support @JsonValue
if (ser == null) { if (ser == null) {
beanDesc = config.introspect(keyType); beanDesc = ctxt.introspect(keyType);
AnnotatedMember am = beanDesc.findJsonValueAccessor(); AnnotatedMember am = beanDesc.findJsonValueAccessor();
if (am != null) { if (am != null) {
final Class<?> rawType = am.getRawType(); final Class<?> rawType = am.getRawType();
Expand Down
Expand Up @@ -145,7 +145,7 @@ public JsonSerializer<Object> createSerializer(SerializerProvider ctxt, JavaType
} else { // changes; assume static typing; plus, need to re-introspect if class differs } else { // changes; assume static typing; plus, need to re-introspect if class differs
staticTyping = true; staticTyping = true;
if (!type.hasRawClass(origType.getRawClass())) { if (!type.hasRawClass(origType.getRawClass())) {
beanDesc = config.introspect(type); beanDesc = ctxt.introspect(type);
} }
} }
// Slight detour: do we have a Converter to consider? // Slight detour: do we have a Converter to consider?
Expand All @@ -155,7 +155,7 @@ public JsonSerializer<Object> createSerializer(SerializerProvider ctxt, JavaType


// One more twist, as per [databind#288]; probably need to get new BeanDesc // One more twist, as per [databind#288]; probably need to get new BeanDesc
if (!delegateType.hasRawClass(type.getRawClass())) { if (!delegateType.hasRawClass(type.getRawClass())) {
beanDesc = config.introspect(delegateType); beanDesc = ctxt.introspect(delegateType);
// [#359]: explicitly check (again) for @JsonSerializer... // [#359]: explicitly check (again) for @JsonSerializer...
ser = findSerializerFromAnnotation(ctxt, beanDesc.getClassInfo()); ser = findSerializerFromAnnotation(ctxt, beanDesc.getClassInfo());
} }
Expand Down
Expand Up @@ -63,7 +63,7 @@ public TypeSerializer findTypeSerializer(SerializationConfig config,
* @return Serializer to use, if factory knows it; null if not (in which case default * @return Serializer to use, if factory knows it; null if not (in which case default
* serializer is to be used) * serializer is to be used)
*/ */
public abstract JsonSerializer<Object> createKeySerializer(SerializationConfig config, public abstract JsonSerializer<Object> createKeySerializer(SerializerProvider ctxt,
JavaType type, JsonSerializer<Object> defaultImpl) JavaType type, JsonSerializer<Object> defaultImpl)
throws JsonMappingException; throws JsonMappingException;


Expand Down Expand Up @@ -125,7 +125,7 @@ public abstract JsonSerializer<Object> createKeySerializer(SerializationConfig c
public JsonSerializer<Object> createSerializer(SerializerProvider prov, JavaType baseType) public JsonSerializer<Object> createSerializer(SerializerProvider prov, JavaType baseType)
throws JsonMappingException throws JsonMappingException
{ {
BeanDescription beanDesc = prov.getConfig().introspect(baseType); BeanDescription beanDesc = prov.introspect(baseType);
return createSerializer(prov, baseType, beanDesc, null); return createSerializer(prov, baseType, beanDesc, null);
} }
} }
Expand Up @@ -98,6 +98,6 @@ public void testMisc() throws Exception
assertNotSame(config, config.with(new ContextAttributes.Impl(Collections.singletonMap("a", "b")))); assertNotSame(config, config.with(new ContextAttributes.Impl(Collections.singletonMap("a", "b"))));


// should also be able to introspect: // should also be able to introspect:
assertNotNull(config.introspectDirectClassAnnotations(getClass())); // assertNotNull(config.introspectDirectClassAnnotations(getClass()));
} }
} }
Expand Up @@ -31,7 +31,7 @@ public void testSerConfig() throws Exception
assertSame(config, config.with(config.getAttributes())); assertSame(config, config.with(config.getAttributes()));
assertNotSame(config, config.with(new ContextAttributes.Impl(Collections.singletonMap("a", "b")))); assertNotSame(config, config.with(new ContextAttributes.Impl(Collections.singletonMap("a", "b"))));


assertNotNull(config.introspectDirectClassAnnotations(getClass())); // assertNotNull(config.introspectDirectClassAnnotations(getClass()));
} }


public void testGeneratorFeatures() throws Exception public void testGeneratorFeatures() throws Exception
Expand Down
Expand Up @@ -417,7 +417,7 @@ public void testSimpleWithType()


public void testInnerClassWithAnnotationsInCreator() throws Exception public void testInnerClassWithAnnotationsInCreator() throws Exception
{ {
BasicBeanDescription beanDesc; BeanDescription beanDesc;
// first with serialization // first with serialization
beanDesc = MAPPER.serializationConfig().introspect(MAPPER.constructType(Issue701Bean.class)); beanDesc = MAPPER.serializationConfig().introspect(MAPPER.constructType(Issue701Bean.class));
assertNotNull(beanDesc); assertNotNull(beanDesc);
Expand All @@ -432,7 +432,7 @@ public void testUseAnnotationsFalse() throws Exception
ObjectMapper mapper = ObjectMapper.builder() ObjectMapper mapper = ObjectMapper.builder()
.disable(MapperFeature.USE_ANNOTATIONS) .disable(MapperFeature.USE_ANNOTATIONS)
.build(); .build();
BasicBeanDescription beanDesc = mapper.serializationConfig().introspect(mapper.constructType(Jackson703.class)); BeanDescription beanDesc = mapper.serializationConfig().introspect(mapper.constructType(Jackson703.class));
assertNotNull(beanDesc); assertNotNull(beanDesc);


Jackson703 bean = new Jackson703(); Jackson703 bean = new Jackson703();
Expand Down

0 comments on commit f56b0c1

Please sign in to comment.