Skip to content

Commit

Permalink
Initial version of merging-property-deser (#1399)
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Oct 21, 2016
1 parent 17ca894 commit a2d3a5a
Show file tree
Hide file tree
Showing 9 changed files with 169 additions and 134 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -745,15 +745,6 @@ public AnnotationIntrospector getAnnotationIntrospector()
return NopAnnotationIntrospector.instance;
}

/**
* Accessor for getting bean description that only contains class
* annotations: useful if no getter/setter/creator information is needed.
*/
@Override
public BeanDescription introspectClassAnnotations(JavaType type) {
return getClassIntrospector().forClassAnnotations(this, type, this);
}

/**
* Accessor for getting bean description that only contains immediate class
* annotations: ones from the class, and its direct mix-in, if any, but
Expand All @@ -775,32 +766,6 @@ public JsonInclude.Value getDefaultPropertyInclusion() {
return EMPTY_INCLUDE;
}

@Override
public JsonInclude.Value getDefaultPropertyInclusion(Class<?> baseType) {
ConfigOverride overrides = findConfigOverride(baseType);
if (overrides != null) {
JsonInclude.Value v = overrides.getInclude();
if (v != null) {
return v;
}
}
return EMPTY_INCLUDE;
}

@Override
public JsonInclude.Value getDefaultPropertyInclusion(Class<?> baseType,
JsonInclude.Value defaultIncl)
{
ConfigOverride overrides = findConfigOverride(baseType);
if (overrides != null) {
JsonInclude.Value v = overrides.getInclude();
if (v != null) {
return v;
}
}
return defaultIncl;
}

/*
/**********************************************************
/* MapperConfig implementation/overrides: other
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -847,15 +847,6 @@ public AnnotationIntrospector getAnnotationIntrospector()
return AnnotationIntrospector.nopInstance();
}

/**
* Accessor for getting bean description that only contains class
* annotations: useful if no getter/setter/creator information is needed.
*/
@Override
public BeanDescription introspectClassAnnotations(JavaType type) {
return getClassIntrospector().forClassAnnotations(this, type, this);
}

/**
* Accessor for getting bean description that only contains immediate class
* annotations: ones from the class, and its direct mix-in, if any, but
Expand Down Expand Up @@ -887,32 +878,6 @@ public JsonInclude.Value getDefaultPropertyInclusion() {
return _serializationInclusion;
}

@Override
public JsonInclude.Value getDefaultPropertyInclusion(Class<?> baseType) {
ConfigOverride overrides = findConfigOverride(baseType);
if (overrides != null) {
JsonInclude.Value v = overrides.getInclude();
if (v != null) {
return v;
}
}
return _serializationInclusion;
}

@Override
public JsonInclude.Value getDefaultPropertyInclusion(Class<?> baseType,
JsonInclude.Value defaultIncl)
{
ConfigOverride overrides = findConfigOverride(baseType);
if (overrides != null) {
JsonInclude.Value v = overrides.getInclude();
if (v != null) {
return v;
}
}
return defaultIncl;
}

/*
/**********************************************************
/* Configuration: other
Expand Down
31 changes: 26 additions & 5 deletions src/main/java/com/fasterxml/jackson/databind/cfg/MapperConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -319,12 +319,14 @@ public JavaType constructSpecializedType(JavaType baseType, Class<?> subclass) {
public BeanDescription introspectClassAnnotations(Class<?> cls) {
return introspectClassAnnotations(constructType(cls));
}

/**
* Accessor for getting bean description that only contains class
* annotations: useful if no getter/setter/creator information is needed.
*/
public abstract BeanDescription introspectClassAnnotations(JavaType type);
public final BeanDescription introspectClassAnnotations(JavaType type) {
return getClassIntrospector().forClassAnnotations(this, type, this);
}

/**
* Accessor for getting bean description that only contains immediate class
Expand Down Expand Up @@ -363,7 +365,16 @@ public BeanDescription introspectDirectClassAnnotations(Class<?> cls) {
*
* @since 2.7
*/
public abstract JsonInclude.Value getDefaultPropertyInclusion(Class<?> baseType);
public JsonInclude.Value getDefaultPropertyInclusion(Class<?> baseType) {
ConfigOverride overrides = findConfigOverride(baseType);
if (overrides != null) {
JsonInclude.Value v = overrides.getInclude();
if (v != null) {
return v;
}
}
return getDefaultPropertyInclusion();
}

/**
* Accessor for default property inclusion to use for serialization,
Expand All @@ -374,8 +385,18 @@ public BeanDescription introspectDirectClassAnnotations(Class<?> cls) {
*
* @since 2.8.2
*/
public abstract JsonInclude.Value getDefaultPropertyInclusion(Class<?> baseType,
JsonInclude.Value defaultIncl);
public JsonInclude.Value getDefaultPropertyInclusion(Class<?> baseType,
JsonInclude.Value defaultIncl)
{
ConfigOverride overrides = findConfigOverride(baseType);
if (overrides != null) {
JsonInclude.Value v = overrides.getInclude();
if (v != null) {
return v;
}
}
return defaultIncl;
}

/**
* Accessor for default format settings to use for serialization (and, to a degree
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -509,11 +509,27 @@ protected void addBeanProps(DeserializationContext ctxt,
* other types, and only then create constructor parameter, if any.
*/
if (propDef.hasSetter()) {
JavaType propertyType = propDef.getSetter().getParameterType(0);
AnnotatedMethod setter = propDef.getSetter();
JavaType propertyType = setter.getParameterType(0);
prop = constructSettableProperty(ctxt, beanDesc, propDef, propertyType);
if (_isMergeableProperty(ctxt, setter, propertyType)) {
AnnotatedMember accessor = propDef.getAccessor();
if (accessor != null) {
accessor.fixAccess(ctxt.isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS));
prop = MergingSettableBeanProperty.construct(prop, accessor);
}
}
} else if (propDef.hasField()) {
JavaType propertyType = propDef.getField().getType();
AnnotatedField field = propDef.getField();
JavaType propertyType = field.getType();
prop = constructSettableProperty(ctxt, beanDesc, propDef, propertyType);
if (_isMergeableProperty(ctxt, field, propertyType)) {
AnnotatedMember accessor = propDef.getAccessor();
if (accessor != null) {
accessor.fixAccess(ctxt.isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS));
prop = MergingSettableBeanProperty.construct(prop, accessor);
}
}
} else if (useGettersAsSetters && propDef.hasGetter()) {
/* May also need to consider getters
* for Map/Collection properties; but with lowest precedence
Expand Down Expand Up @@ -570,6 +586,22 @@ protected void addBeanProps(DeserializationContext ctxt,
}
}

protected boolean _isMergeableProperty(DeserializationContext ctxt,
AnnotatedMember accessor, JavaType type)
{
AnnotationIntrospector ai = ctxt.getAnnotationIntrospector();
if (ai != null) {
JsonSetter.Value setter = ai.findSetterInfo(accessor);
if (setter != null) {
Boolean b = setter.getMerge();
if (b != null) {
return b.booleanValue();
}
}
}
return false;
}

/**
* Helper method called to filter out explicit ignored properties,
* as well as properties that have "ignorable types".
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ public boolean hasValueDeserializer() {
}

public boolean hasValueTypeDeserializer() { return (_valueTypeDeserializer != null); }

public JsonDeserializer<Object> getValueDeserializer() {
JsonDeserializer<Object> deser = _valueDeserializer;
if (deser == MISSING_VALUE_DESERIALIZER) {
Expand Down Expand Up @@ -485,6 +485,29 @@ public final Object deserialize(JsonParser p, DeserializationContext ctxt) throw
return _valueDeserializer.deserialize(p, ctxt);
}

/**
* @since 2.9
*/
public final Object deserializeWith(JsonParser p, DeserializationContext ctxt,
Object toUpdate) throws IOException
{
JsonToken t = p.getCurrentToken();

// 20-Oct-2016, tatu: Not 100% sure what to do; probably best to simply return
// null value and let caller decide what to do
if (t == JsonToken.VALUE_NULL) {
return _valueDeserializer.getNullValue(ctxt);
}
// 20-Oct-2016, tatu: Also tricky -- for now, report an erro
if (_valueTypeDeserializer != null) {
ctxt.reportBadDefinition(getType(),
String.format("Can not merge polymorphic property '%s'",
getName()));
// return _valueDeserializer.deserializeWithType(p, ctxt, _valueTypeDeserializer);
}
return _valueDeserializer.deserialize(p, ctxt, toUpdate);
}

/*
/**********************************************************
/* Helper methods
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
package com.fasterxml.jackson.databind.deser.impl;

import java.io.IOException;
import java.lang.annotation.Annotation;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.PropertyName;
import com.fasterxml.jackson.databind.deser.*;
import com.fasterxml.jackson.databind.introspect.AnnotatedMember;

Expand All @@ -19,65 +16,44 @@
* @since 2.9
*/
public class MergingSettableBeanProperty
extends SettableBeanProperty
extends SettableBeanProperty.Delegating
{
private static final long serialVersionUID = 1L;

/**
* Underlying actual property (field- or member-backed).
* Member (field, method) used for accessing existing value.
*/
protected final SettableBeanProperty _delegate;
protected final AnnotatedMember _accessor;

/*
/**********************************************************
/* Life-cycle
/**********************************************************
*/

public MergingSettableBeanProperty(SettableBeanProperty delegate)
protected MergingSettableBeanProperty(SettableBeanProperty delegate,
AnnotatedMember accessor)
{
super(delegate);
_delegate = delegate;
_accessor = accessor;
}

protected MergingSettableBeanProperty(MergingSettableBeanProperty src,
SettableBeanProperty delegate)
{
super(src);
_delegate = src._delegate;
}

@Override
public SettableBeanProperty withValueDeserializer(JsonDeserializer<?> deser) {
return _new(_delegate.withValueDeserializer(deser));
}

@Override
public SettableBeanProperty withName(PropertyName newName) {
return _new(_delegate.withName(newName));
}

protected MergingSettableBeanProperty _new(SettableBeanProperty newDelegate) {
if (newDelegate == _delegate) {
return this;
}
return new MergingSettableBeanProperty(this, newDelegate);
super(delegate);
_accessor = src._accessor;
}

/*
/**********************************************************
/* BeanProperty impl
/**********************************************************
*/

@Override
public AnnotatedMember getMember() {
return _delegate.getMember();
public static MergingSettableBeanProperty construct(SettableBeanProperty delegate,
AnnotatedMember accessor)
{
return new MergingSettableBeanProperty(delegate, accessor);
}

@Override
public <A extends Annotation> A getAnnotation(Class<A> acls) {
return _delegate.getAnnotation(acls);
protected SettableBeanProperty withDelegate(SettableBeanProperty d) {
return new MergingSettableBeanProperty(d, _accessor);
}

/*
Expand All @@ -90,25 +66,39 @@ public <A extends Annotation> A getAnnotation(Class<A> acls) {
public void deserializeAndSet(JsonParser p, DeserializationContext ctxt,
Object instance) throws IOException
{
// TODO Auto-generated method stub
delegate.set(instance, _deserialize(p, ctxt, instance));
}

@Override
public Object deserializeSetAndReturn(JsonParser p,
DeserializationContext ctxt, Object instance) throws IOException {
// TODO Auto-generated method stub
return null;
return delegate.setAndReturn(instance, _deserialize(p, ctxt, instance));
}

@Override
public void set(Object instance, Object value) throws IOException {
// TODO Auto-generated method stub
delegate.set(instance, value);
}

@Override
public Object setAndReturn(Object instance, Object value)
throws IOException {
// TODO Auto-generated method stub
return null;
throws IOException
{
return delegate.setAndReturn(instance, value);
}

protected Object _deserialize(JsonParser p, DeserializationContext ctxt,
Object instance) throws IOException
{
Object value = _accessor.getValue(instance);
// 20-Oct-2016, tatu: Couple of possibilities of how to proceed; for
// now, default to "normal" handling without merging
if (value == null) {
return delegate.deserialize(p, ctxt);
}
Object result = delegate.deserializeWith(p, ctxt, value);
// 20-Oct-2016, tatu: Similarly, we may get same object or different one;
// whether to return original or new is an open question.
return result;
}
}
Loading

0 comments on commit a2d3a5a

Please sign in to comment.