protected Converter<Object, Object> findConverter(DeserializationContext ctxt, Annotated a) throws JsonMappingException { Object convDef = ctxt.getAnnotationIntrospector().findDeserializationConverter(a); if (convDef == null) { return null; } return ctxt.converterInstance(a, convDef); }
/** * Helper method called to check if a class or method has annotation that tells which class to use * for deserialization. Returns null if no such annotation found. */ protected JsonDeserializer<Object> findDeserializerFromAnnotation( DeserializationContext ctxt, Annotated ann) throws JsonMappingException { Object deserDef = ctxt.getAnnotationIntrospector().findDeserializer(ann); if (deserDef == null) { return null; } JsonDeserializer<Object> deser = ctxt.deserializerInstance(ann, deserDef); // One more thing however: may need to also apply a converter: return findConvertingDeserializer(ctxt, ann, deser); }
/** * Helper method that will check whether given annotated entity (usually class, but may also be a * property accessor) indicates that a {@link Converter} is to be used; and if so, to construct * and return suitable serializer for it. If not, will simply return given serializer as is. */ protected JsonDeserializer<Object> findConvertingDeserializer( DeserializationContext ctxt, Annotated a, JsonDeserializer<Object> deser) throws JsonMappingException { Converter<Object, Object> conv = findConverter(ctxt, a); if (conv == null) { return deser; } JavaType delegateType = conv.getInputType(ctxt.getTypeFactory()); return (JsonDeserializer<Object>) new StdDelegatingDeserializer<Object>(conv, delegateType, deser); }
/** * Method that does the heavy lifting of checking for per-type annotations, find out full type, * and figure out which actual factory method to call. */ @SuppressWarnings("unchecked") protected JsonDeserializer<Object> _createDeserializer( DeserializationContext ctxt, DeserializerFactory factory, JavaType type) throws JsonMappingException { final DeserializationConfig config = ctxt.getConfig(); // First things first: do we need to use abstract type mapping? if (type.isAbstract() || type.isMapLikeType() || type.isCollectionLikeType()) { type = factory.mapAbstractType(config, type); } BeanDescription beanDesc = config.introspect(type); // Then: does type define explicit deserializer to use, with annotation(s)? JsonDeserializer<Object> deser = findDeserializerFromAnnotation(ctxt, beanDesc.getClassInfo()); if (deser != null) { return deser; } // If not, may have further type-modification annotations to check: JavaType newType = modifyTypeByAnnotation(ctxt, beanDesc.getClassInfo(), type); if (newType != type) { type = newType; beanDesc = config.introspect(newType); } // We may also have a Builder type to consider... Class<?> builder = beanDesc.findPOJOBuilder(); if (builder != null) { return (JsonDeserializer<Object>) factory.createBuilderBasedDeserializer(ctxt, type, beanDesc, builder); } // Or perhaps a Converter? Converter<Object, Object> conv = beanDesc.findDeserializationConverter(); if (conv == null) { // nope, just construct in normal way return (JsonDeserializer<Object>) _createDeserializer2(ctxt, factory, type, beanDesc); } // otherwise need to do bit of introspection JavaType delegateType = conv.getInputType(ctxt.getTypeFactory()); return new StdDelegatingDeserializer<Object>( conv, delegateType, _createDeserializer2(ctxt, factory, delegateType, beanDesc)); }
protected JsonDeserializer<?> _createDeserializer2( DeserializationContext ctxt, DeserializerFactory factory, JavaType type, BeanDescription beanDesc) throws JsonMappingException { final DeserializationConfig config = ctxt.getConfig(); // If not, let's see which factory method to use: if (type.isEnumType()) { return factory.createEnumDeserializer(ctxt, type, beanDesc); } if (type.isContainerType()) { if (type.isArrayType()) { return factory.createArrayDeserializer(ctxt, (ArrayType) type, beanDesc); } if (type.isMapLikeType()) { MapLikeType mlt = (MapLikeType) type; if (mlt.isTrueMapType()) { return factory.createMapDeserializer(ctxt, (MapType) mlt, beanDesc); } return factory.createMapLikeDeserializer(ctxt, mlt, beanDesc); } if (type.isCollectionLikeType()) { /* 03-Aug-2012, tatu: As per [Issue#40], one exception is if shape * is to be Shape.OBJECT. Ideally we'd determine it bit later on * (to allow custom handler checks), but that won't work for other * reasons. So do it here. */ JsonFormat.Value format = beanDesc.findExpectedFormat(null); if (format == null || format.getShape() != JsonFormat.Shape.OBJECT) { CollectionLikeType clt = (CollectionLikeType) type; if (clt.isTrueCollectionType()) { return factory.createCollectionDeserializer(ctxt, (CollectionType) clt, beanDesc); } return factory.createCollectionLikeDeserializer(ctxt, clt, beanDesc); } } } if (JsonNode.class.isAssignableFrom(type.getRawClass())) { return factory.createTreeDeserializer(config, type, beanDesc); } return factory.createBeanDeserializer(ctxt, type, beanDesc); }
/** * Method called to see if given method has annotations that indicate a more specific type than * what the argument specifies. If annotations are present, they must specify compatible Class; * instance of which can be assigned using the method. This means that the Class has to be raw * class of type, or its sub-class (or, implementing class if original Class instance is an * interface). * * @param a Method or field that the type is associated with * @param type Type derived from the setter argument * @return Original type if no annotations are present; or a more specific type derived from it if * type annotation(s) was found * @throws JsonMappingException if invalid annotation is found */ private JavaType modifyTypeByAnnotation(DeserializationContext ctxt, Annotated a, JavaType type) throws JsonMappingException { // first: let's check class for the instance itself: AnnotationIntrospector intr = ctxt.getAnnotationIntrospector(); Class<?> subclass = intr.findDeserializationType(a, type); if (subclass != null) { try { type = type.narrowBy(subclass); } catch (IllegalArgumentException iae) { throw new JsonMappingException( "Failed to narrow type " + type + " with concrete-type annotation (value " + subclass.getName() + "), method '" + a.getName() + "': " + iae.getMessage(), null, iae); } } // then key class if (type.isContainerType()) { Class<?> keyClass = intr.findDeserializationKeyType(a, type.getKeyType()); if (keyClass != null) { // illegal to use on non-Maps if (!(type instanceof MapLikeType)) { throw new JsonMappingException( "Illegal key-type annotation: type " + type + " is not a Map(-like) type"); } try { type = ((MapLikeType) type).narrowKey(keyClass); } catch (IllegalArgumentException iae) { throw new JsonMappingException( "Failed to narrow key type " + type + " with key-type annotation (" + keyClass.getName() + "): " + iae.getMessage(), null, iae); } } JavaType keyType = type.getKeyType(); /* 21-Mar-2011, tatu: ... and associated deserializer too (unless already assigned) * (not 100% why or how, but this does seem to get called more than once, which * is not good: for now, let's just avoid errors) */ if (keyType != null && keyType.getValueHandler() == null) { Object kdDef = intr.findKeyDeserializer(a); if (kdDef != null) { KeyDeserializer kd = ctxt.keyDeserializerInstance(a, kdDef); if (kd != null) { type = ((MapLikeType) type).withKeyValueHandler(kd); keyType = type.getKeyType(); // just in case it's used below } } } // and finally content class; only applicable to structured types Class<?> cc = intr.findDeserializationContentType(a, type.getContentType()); if (cc != null) { try { type = type.narrowContentsBy(cc); } catch (IllegalArgumentException iae) { throw new JsonMappingException( "Failed to narrow content type " + type + " with content-type annotation (" + cc.getName() + "): " + iae.getMessage(), null, iae); } } // ... as well as deserializer for contents: JavaType contentType = type.getContentType(); if (contentType.getValueHandler() == null) { // as with above, avoid resetting (which would trigger exception) Object cdDef = intr.findContentDeserializer(a); if (cdDef != null) { JsonDeserializer<?> cd = null; if (cdDef instanceof JsonDeserializer<?>) { cdDef = (JsonDeserializer<?>) cdDef; } else { Class<?> cdClass = _verifyAsClass(cdDef, "findContentDeserializer", JsonDeserializer.None.class); if (cdClass != null) { cd = ctxt.deserializerInstance(a, cdClass); } } if (cd != null) { type = type.withContentValueHandler(cd); } } } } return type; }