Skip to content

Commit

Permalink
Merge branch 'custom-id-resolution' of https://github.com/pgelinas/ja…
Browse files Browse the repository at this point in the history
…ckson-databind into pgelinas-custom-id-resolution

Conflicts:
	src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerBase.java
  • Loading branch information
cowtowncoder committed Feb 19, 2014
2 parents 7d0445b + 184cae3 commit 72ce52f
Show file tree
Hide file tree
Showing 16 changed files with 243 additions and 35 deletions.
17 changes: 15 additions & 2 deletions src/main/java/com/fasterxml/jackson/databind/DatabindContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import java.lang.reflect.Type;

import com.fasterxml.jackson.annotation.ObjectIdGenerator;

import com.fasterxml.jackson.annotation.ObjectIdResolver;
import com.fasterxml.jackson.databind.annotation.NoClass;
import com.fasterxml.jackson.databind.cfg.HandlerInstantiator;
import com.fasterxml.jackson.databind.cfg.MapperConfig;
Expand Down Expand Up @@ -159,7 +159,20 @@ public ObjectIdGenerator<?> objectIdGeneratorInstance(Annotated annotated,
}
return gen.forScope(objectIdInfo.getScope());
}


public ObjectIdResolver objectIdResolverInstance(Annotated annotated, ObjectIdInfo objectIdInfo)
{
Class<? extends ObjectIdResolver> implClass = objectIdInfo.getResolverType();
final MapperConfig<?> config = getConfig();
HandlerInstantiator hi = config.getHandlerInstantiator();
ObjectIdResolver resolver = (hi == null) ? null : hi.resolverIdGeneratorInstance(config, annotated, implClass);
if (resolver == null) {
resolver = ClassUtil.createInstance(implClass, config.canOverrideAccessModifiers());
}

return resolver;
}

/**
* Helper method to use to construct a {@link Converter}, given a definition
* that may be either actual converter instance, or Class for instantiating one.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import java.util.concurrent.atomic.AtomicReference;

import com.fasterxml.jackson.annotation.ObjectIdGenerator;
import com.fasterxml.jackson.annotation.ObjectIdResolver;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.cfg.ContextAttributes;
import com.fasterxml.jackson.databind.deser.*;
Expand All @@ -15,6 +16,7 @@
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException;
import com.fasterxml.jackson.databind.introspect.Annotated;
import com.fasterxml.jackson.databind.introspect.ObjectIdInfo;
import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.type.TypeFactory;
Expand Down Expand Up @@ -420,8 +422,10 @@ public final KeyDeserializer findKeyDeserializer(JavaType keyType,
* Method called to find and return entry corresponding to given
* Object Id: will add an entry if necessary, and never returns null
*/
public abstract ReadableObjectId findObjectId(Object id,
ObjectIdGenerator<?> generator);
public abstract ReadableObjectId findObjectId(Object id, ObjectIdGenerator<?> generator, ObjectIdResolver resolver);

@Deprecated
public abstract ReadableObjectId findObjectId(Object id, ObjectIdGenerator<?> generator);

/**
* Method called to ensure that every object id encounter during processing
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.fasterxml.jackson.databind.cfg;

import com.fasterxml.jackson.annotation.ObjectIdGenerator;
import com.fasterxml.jackson.annotation.ObjectIdResolver;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.deser.ValueInstantiator;
import com.fasterxml.jackson.databind.introspect.Annotated;
Expand Down Expand Up @@ -123,6 +124,11 @@ public ObjectIdGenerator<?> objectIdGeneratorInstance(MapperConfig<?> config,
return null;
}

public ObjectIdResolver resolverIdGeneratorInstance(MapperConfig<?> config, Annotated annotated, Class<?> implClass)
{
return null;
}

/**
* Method called to construct a NamingStrategy instance used for specified
* class.
Expand All @@ -143,4 +149,5 @@ public Converter<?,?> converterInstance(MapperConfig<?> config,
Annotated annotated, Class<?> implClass) {
return null;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -196,9 +196,9 @@ protected Object _deserializeFromObjectId(JsonParser jp, DeserializationContext
throws IOException, JsonProcessingException
{
Object id = _objectIdReader.readObjectReference(jp, ctxt);
ReadableObjectId roid = ctxt.findObjectId(id, _objectIdReader.generator);
ReadableObjectId roid = ctxt.findObjectId(id, _objectIdReader.generator, _objectIdReader.resolver);
// do we have it resolved?
Object pojo = roid.item;
Object pojo = roid.resolve();
if (pojo == null) { // not yet; should wait...
throw new IllegalStateException("Could not resolve Object Id ["+id+"] -- unresolved forward-reference?");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerator;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import com.fasterxml.jackson.annotation.ObjectIdResolver;

import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.deser.impl.*;
Expand Down Expand Up @@ -577,6 +579,7 @@ public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
JavaType idType;
SettableBeanProperty idProp;
ObjectIdGenerator<?> idGen;
ObjectIdResolver resolver = ctxt.objectIdResolverInstance(accessor, objectIdInfo);
if (implClass == ObjectIdGenerators.PropertyGenerator.class) {
PropertyName propName = objectIdInfo.getPropertyName();
idProp = findProperty(propName);
Expand All @@ -594,7 +597,7 @@ public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
}
JsonDeserializer<?> deser = ctxt.findRootValueDeserializer(idType);
oir = ObjectIdReader.construct(idType, objectIdInfo.getPropertyName(),
idGen, deser, idProp);
idGen, deser, idProp, resolver);
}
}
// either way, need to resolve serializer:
Expand Down Expand Up @@ -965,7 +968,7 @@ protected Object _handleTypedObjectId(JsonParser jp, DeserializationContext ctxt
id = _convertObjectId(jp, ctxt, rawId, idDeser);
}

ReadableObjectId roid = ctxt.findObjectId(id, _objectIdReader.generator);
ReadableObjectId roid = ctxt.findObjectId(id, _objectIdReader.generator, _objectIdReader.resolver);
roid.bindItem(pojo);
// also: may need to set a property value as well
SettableBeanProperty idProp = _objectIdReader.idProperty;
Expand Down Expand Up @@ -1028,9 +1031,9 @@ protected Object deserializeFromObjectId(JsonParser jp, DeserializationContext c
throws IOException, JsonProcessingException
{
Object id = _objectIdReader.readObjectReference(jp, ctxt);
ReadableObjectId roid = ctxt.findObjectId(id, _objectIdReader.generator);
ReadableObjectId roid = ctxt.findObjectId(id, _objectIdReader.generator, _objectIdReader.resolver);
// do we have it resolved?
Object pojo = roid.item;
Object pojo = roid.resolve();
if (pojo == null) { // not yet; should wait...
throw new UnresolvedForwardReference("Could not resolve Object Id ["+id+"] (for "
+_beanType+").", jp.getCurrentLocation(), roid);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import com.fasterxml.jackson.annotation.ObjectIdGenerator;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;

import com.fasterxml.jackson.annotation.ObjectIdResolver;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
import com.fasterxml.jackson.databind.cfg.DeserializerFactoryConfig;
Expand Down Expand Up @@ -369,6 +369,8 @@ protected void addObjectIdReader(DeserializationContext ctxt,
SettableBeanProperty idProp;
ObjectIdGenerator<?> gen;

ObjectIdResolver resolver = ctxt.objectIdResolverInstance(beanDesc.getClassInfo(), objectIdInfo);

// Just one special case: Property-based generator is trickier
if (implClass == ObjectIdGenerators.PropertyGenerator.class) { // most special one, needs extra work
PropertyName propName = objectIdInfo.getPropertyName();
Expand All @@ -388,7 +390,7 @@ protected void addObjectIdReader(DeserializationContext ctxt,
// also: unlike with value deserializers, let's just resolve one we need here
JsonDeserializer<?> deser = ctxt.findRootValueDeserializer(idType);
builder.setObjectIdReader(ObjectIdReader.construct(idType,
objectIdInfo.getPropertyName(), gen, deser, idProp));
objectIdInfo.getPropertyName(), gen, deser, idProp, resolver));
}

@SuppressWarnings("unchecked")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package com.fasterxml.jackson.databind.deser;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map.Entry;

import com.fasterxml.jackson.annotation.ObjectIdGenerator;
import com.fasterxml.jackson.annotation.ObjectIdResolver;
import com.fasterxml.jackson.annotation.ObjectIdGenerator.IdKey;
import com.fasterxml.jackson.annotation.SimpleObjectIdResolver;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.annotation.NoClass;
Expand All @@ -32,6 +36,8 @@ public abstract class DefaultDeserializationContext

protected transient LinkedHashMap<ObjectIdGenerator.IdKey, ReadableObjectId> _objectIds;

private List<ObjectIdResolver> _objectIdResolvers;

/**
* Constructor that will pass specified deserializer factory and
* cache: cache may be null (in which case default implementation
Expand All @@ -58,44 +64,70 @@ protected DefaultDeserializationContext(DefaultDeserializationContext src,
*/

@Override
public ReadableObjectId findObjectId(Object id,
ObjectIdGenerator<?> generator)
public ReadableObjectId findObjectId(Object id, ObjectIdGenerator<?> generator, ObjectIdResolver resolverType)
{
final ObjectIdGenerator.IdKey key = generator.key(id);
if (_objectIds == null) {
_objectIds = new LinkedHashMap<ObjectIdGenerator.IdKey, ReadableObjectId>();
_objectIds = new LinkedHashMap<ObjectIdGenerator.IdKey,ReadableObjectId>();
} else {
ReadableObjectId entry = _objectIds.get(key);
if (entry != null) {
return entry;
}
}
ReadableObjectId entry = new ReadableObjectId(id);

// Not seen yet, must create entry and configure resolver.
ObjectIdResolver resolver = null;

if (_objectIdResolvers == null) {
_objectIdResolvers = new ArrayList<ObjectIdResolver>(8);
} else {
for (ObjectIdResolver res : _objectIdResolvers) {
if (res.canUseFor(resolverType)) {
resolver = res;
break;
}
}
}
if (resolver == null) {
resolver = resolverType.newForDeserialization(this);
_objectIdResolvers.add(resolver);
}

ReadableObjectId entry = new ReadableObjectId(key);
entry.setResolver(resolver);
_objectIds.put(key, entry);
return entry;
}

@Override
public void checkUnresolvedObjectId() throws UnresolvedForwardReference
public ReadableObjectId findObjectId(Object id, ObjectIdGenerator<?> generator)
{
if(_objectIds == null){
return findObjectId(id, generator, new SimpleObjectIdResolver());
}

@Override
public void checkUnresolvedObjectId()
throws UnresolvedForwardReference
{
if (_objectIds == null) {
return;
}

UnresolvedForwardReference exception = null;
for (Entry<IdKey,ReadableObjectId> entry : _objectIds.entrySet()) {
ReadableObjectId roid = entry.getValue();
if(roid.hasReferringProperties()){
if(exception == null){
if (roid.hasReferringProperties()) {
if (exception == null) {
exception = new UnresolvedForwardReference("Unresolved forward references for: ");
}
for (Iterator<Referring> iterator = roid.referringProperties(); iterator.hasNext();) {
Referring referring = iterator.next();
exception.addUnresolvedId(roid.id, referring.getBeanType(), referring.getLocation());
exception.addUnresolvedId(roid.getKey().key, referring.getBeanType(), referring.getLocation());
}
}
}
if(exception != null){
if (exception != null) {
throw exception;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public ReadableObjectId getRoid() {
}

public Object getUnresolvedId() {
return _roid.id;
return _roid.getKey().key;
}

public void addUnresolvedId(Object id, Class<?> type, JsonLocation where) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import java.io.IOException;

import com.fasterxml.jackson.annotation.ObjectIdGenerator;
import com.fasterxml.jackson.annotation.ObjectIdResolver;
import com.fasterxml.jackson.annotation.SimpleObjectIdResolver;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.*;
Expand All @@ -26,7 +28,12 @@ public class ObjectIdReader
* the key.
*/
public final ObjectIdGenerator<?> generator;


/**
*
*/
public final ObjectIdResolver resolver;

/**
* Deserializer used for deserializing id values.
*/
Expand All @@ -42,15 +49,23 @@ public class ObjectIdReader

@SuppressWarnings("unchecked")
protected ObjectIdReader(JavaType t, PropertyName propName, ObjectIdGenerator<?> gen,
JsonDeserializer<?> deser, SettableBeanProperty idProp)
JsonDeserializer<?> deser, SettableBeanProperty idProp, ObjectIdResolver resolver)
{
_idType = t;
propertyName = propName;
generator = gen;
this.resolver = resolver;
_deserializer = (JsonDeserializer<Object>) deser;
idProperty = idProp;
}

@Deprecated // since 2.4
protected ObjectIdReader(JavaType t, PropertyName propName, ObjectIdGenerator<?> gen,
JsonDeserializer<?> deser, SettableBeanProperty idProp)
{
this(t,propName, gen, deser, idProp, new SimpleObjectIdResolver());
}

@Deprecated // since 2.3
protected ObjectIdReader(JavaType t, String propName, ObjectIdGenerator<?> gen,
JsonDeserializer<?> deser, SettableBeanProperty idProp)
Expand All @@ -63,11 +78,19 @@ protected ObjectIdReader(JavaType t, String propName, ObjectIdGenerator<?> gen,
* with the initial information based on standard settings for the type
* for which serializer is being built.
*/
public static ObjectIdReader construct(JavaType idType, PropertyName propName,
ObjectIdGenerator<?> generator, JsonDeserializer<?> deser,
SettableBeanProperty idProp, ObjectIdResolver resolver)
{
return new ObjectIdReader(idType, propName, generator, deser, idProp, resolver);
}

@Deprecated // since 2.4
public static ObjectIdReader construct(JavaType idType, PropertyName propName,
ObjectIdGenerator<?> generator, JsonDeserializer<?> deser,
SettableBeanProperty idProp)
{
return new ObjectIdReader(idType, propName, generator, deser, idProp);
return construct(idType, propName, generator, deser, idProp, new SimpleObjectIdResolver());
}

@Deprecated // since 2.3
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public Object deserializeSetAndReturn(JsonParser jp,
{
// note: no null checks (unlike usually); deserializer should fail if one found
Object id = _valueDeserializer.deserialize(jp, ctxt);
ReadableObjectId roid = ctxt.findObjectId(id, _objectIdReader.generator);
ReadableObjectId roid = ctxt.findObjectId(id, _objectIdReader.generator, _objectIdReader.resolver);
roid.bindItem(instance);
// also: may need to set a property value as well
SettableBeanProperty idProp = _objectIdReader.idProperty;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ public Object handleIdValue(final DeserializationContext ctxt, Object bean)
{
if (_objectIdReader != null) {
if (_idValue != null) {
ReadableObjectId roid = ctxt.findObjectId(_idValue, _objectIdReader.generator);
ReadableObjectId roid = ctxt.findObjectId(_idValue, _objectIdReader.generator, _objectIdReader.resolver);
roid.bindItem(bean);
// also: may need to set a property value as well
SettableBeanProperty idProp = _objectIdReader.idProperty;
Expand Down
Loading

0 comments on commit 72ce52f

Please sign in to comment.