package com.fasterxml.jackson.databind.deser; import java.util.LinkedHashMap; import com.fasterxml.jackson.annotation.ObjectIdGenerator; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.annotation.NoClass; import com.fasterxml.jackson.databind.cfg.HandlerInstantiator; import com.fasterxml.jackson.databind.deser.impl.ReadableObjectId; import com.fasterxml.jackson.databind.introspect.Annotated; import com.fasterxml.jackson.databind.introspect.ObjectIdInfo; import com.fasterxml.jackson.databind.util.ClassUtil; /** * Complete {@link DeserializationContext} implementation that adds * extended API for {@link ObjectMapper} (and {@link ObjectReader}) * to call, as well as implements certain parts that base class * has left abstract. * The remaining abstract methods ({@link #createInstance}, {@link #with}) * are left so that custom implementations will properly implement them * to return intended subtype. */ public abstract class DefaultDeserializationContext extends DeserializationContext implements java.io.Serializable // since 2.1 { private static final long serialVersionUID = 1L; protected transient LinkedHashMap<ObjectIdGenerator.IdKey, ReadableObjectId> _objectIds; /** * Constructor that will pass specified deserializer factory and * cache: cache may be null (in which case default implementation * will be used), factory can not be null */ protected DefaultDeserializationContext(DeserializerFactory df, DeserializerCache cache) { super(df, cache); } protected DefaultDeserializationContext(DefaultDeserializationContext src, DeserializationConfig config, JsonParser jp, InjectableValues values) { super(src, config, jp, values); } protected DefaultDeserializationContext(DefaultDeserializationContext src, DeserializerFactory factory) { super(src, factory); } /* /********************************************************** /* Abstract methods impls, Object Id /********************************************************** */ @Override public ReadableObjectId findObjectId(Object id, ObjectIdGenerator<?> generator) { final ObjectIdGenerator.IdKey key = generator.key(id); if (_objectIds == null) { _objectIds = new LinkedHashMap<ObjectIdGenerator.IdKey, ReadableObjectId>(); } else { ReadableObjectId entry = _objectIds.get(key); if (entry != null) { return entry; } } ReadableObjectId entry = new ReadableObjectId(id); _objectIds.put(key, entry); return entry; } @Override public ObjectIdGenerator<?> objectIdGeneratorInstance(Annotated annotated, ObjectIdInfo objectIdInfo) throws JsonMappingException { Class<?> implClass = objectIdInfo.getGeneratorType(); HandlerInstantiator hi = _config.getHandlerInstantiator(); ObjectIdGenerator<?> gen; if (hi != null) { gen = hi.objectIdGeneratorInstance(_config, annotated, implClass); } else { gen = (ObjectIdGenerator<?>) ClassUtil.createInstance(implClass, _config.canOverrideAccessModifiers()); } return gen.forScope(objectIdInfo.getScope()); } /* /********************************************************** /* Abstract methods impls, other factory methods /********************************************************** */ @SuppressWarnings("unchecked") @Override public JsonDeserializer<Object> deserializerInstance(Annotated annotated, Object deserDef) throws JsonMappingException { if (deserDef == null) { return null; } JsonDeserializer<?> deser; if (deserDef instanceof JsonDeserializer) { deser = (JsonDeserializer<?>) deserDef; } else { /* Alas, there's no way to force return type of "either class * X or Y" -- need to throw an exception after the fact */ if (!(deserDef instanceof Class)) { throw new IllegalStateException("AnnotationIntrospector returned deserializer definition of type "+deserDef.getClass().getName()+"; expected type JsonDeserializer or Class<JsonDeserializer> instead"); } Class<?> deserClass = (Class<?>)deserDef; // there are some known "no class" markers to consider too: if (deserClass == JsonDeserializer.None.class || deserClass == NoClass.class) { return null; } if (!JsonDeserializer.class.isAssignableFrom(deserClass)) { throw new IllegalStateException("AnnotationIntrospector returned Class "+deserClass.getName()+"; expected Class<JsonDeserializer>"); } HandlerInstantiator hi = _config.getHandlerInstantiator(); if (hi != null) { deser = hi.deserializerInstance(_config, annotated, deserClass); } else { deser = (JsonDeserializer<?>) ClassUtil.createInstance(deserClass, _config.canOverrideAccessModifiers()); } } // First: need to resolve if (deser instanceof ResolvableDeserializer) { ((ResolvableDeserializer) deser).resolve(this); } return (JsonDeserializer<Object>) deser; } @Override public final KeyDeserializer keyDeserializerInstance(Annotated annotated, Object deserDef) throws JsonMappingException { if (deserDef == null) { return null; } KeyDeserializer deser; if (deserDef instanceof KeyDeserializer) { deser = (KeyDeserializer) deserDef; } else { if (!(deserDef instanceof Class)) { throw new IllegalStateException("AnnotationIntrospector returned key deserializer definition of type " +deserDef.getClass().getName() +"; expected type KeyDeserializer or Class<KeyDeserializer> instead"); } Class<?> deserClass = (Class<?>)deserDef; // there are some known "no class" markers to consider too: if (deserClass == KeyDeserializer.None.class || deserClass == NoClass.class) { return null; } if (!KeyDeserializer.class.isAssignableFrom(deserClass)) { throw new IllegalStateException("AnnotationIntrospector returned Class "+deserClass.getName() +"; expected Class<KeyDeserializer>"); } HandlerInstantiator hi = _config.getHandlerInstantiator(); if (hi != null) { deser = hi.keyDeserializerInstance(_config, annotated, deserClass); } else { deser = (KeyDeserializer) ClassUtil.createInstance(deserClass, _config.canOverrideAccessModifiers()); } } // First: need to resolve if (deser instanceof ResolvableDeserializer) { ((ResolvableDeserializer) deser).resolve(this); } return deser; } /* /********************************************************** /* Extended API /********************************************************** */ /** * Fluent factory method used for constructing a blueprint instance * with different factory */ public abstract DefaultDeserializationContext with(DeserializerFactory factory); /** * Method called to create actual usable per-deserialization * context instance. */ public abstract DefaultDeserializationContext createInstance( DeserializationConfig config, JsonParser jp, InjectableValues values); /* /********************************************************** /* And then the concrete implementation class /********************************************************** */ /** * Actual full concrete implementation */ public final static class Impl extends DefaultDeserializationContext { private static final long serialVersionUID = 1L; /** * Default constructor for a blueprint object, which will use the standard * {@link DeserializerCache}, given factory. */ public Impl(DeserializerFactory df) { super(df, null); } protected Impl(Impl src, DeserializationConfig config, JsonParser jp, InjectableValues values) { super(src, config, jp, values); } protected Impl(Impl src, DeserializerFactory factory) { super(src, factory); } @Override public DefaultDeserializationContext createInstance(DeserializationConfig config, JsonParser jp, InjectableValues values) { return new Impl(this, config, jp, values); } @Override public DefaultDeserializationContext with(DeserializerFactory factory) { return new Impl(this, factory); } } }