1 package com.fasterxml.jackson.databind.node; 2 3 import java.io.IOException; 4 import java.util.ArrayList; 5 import java.util.Iterator; 6 import java.util.List; 7 8 import com.fasterxml.jackson.core.*; 9 10 import com.fasterxml.jackson.databind.*; 11 import com.fasterxml.jackson.databind.deser.*; 12 import com.fasterxml.jackson.databind.deser.std.CollectionDeserializer; 13 import com.fasterxml.jackson.databind.deser.std.DelegatingDeserializer; 14 import com.fasterxml.jackson.databind.type.CollectionLikeType; 15 16 public class NodeContext2049Test extends BaseMapTest 17 { 18 public interface HasParent { setParent(Parent parent)19 void setParent(Parent parent); getParent()20 Parent getParent(); 21 } 22 23 static class Child implements HasParent { 24 public Parent parent; 25 public String property; 26 27 @Override setParent(Parent p)28 public void setParent(Parent p) { parent = p; } 29 @Override getParent()30 public Parent getParent() { return parent; } 31 } 32 33 static class Parent { 34 public List<Child> children; 35 public Child singleChild; 36 } 37 38 static class ListValueInstantiator extends ValueInstantiator { 39 @Override getValueTypeDesc()40 public String getValueTypeDesc() { 41 return List.class.getName(); 42 } 43 44 @Override createUsingDefault(DeserializationContext ctxt)45 public Object createUsingDefault(DeserializationContext ctxt) throws IOException { 46 return new ArrayList<>(); 47 } 48 } 49 50 static class ParentSettingDeserializerModifier extends BeanDeserializerModifier { 51 @Override updateBuilder(DeserializationConfig config, BeanDescription beanDesc, BeanDeserializerBuilder builder)52 public BeanDeserializerBuilder updateBuilder(DeserializationConfig config, BeanDescription beanDesc, 53 BeanDeserializerBuilder builder) { 54 for (Iterator<SettableBeanProperty> propertyIt = builder.getProperties(); propertyIt.hasNext(); ) { 55 SettableBeanProperty property = propertyIt.next(); 56 builder.addOrReplaceProperty(property.withValueDeserializer(new ParentSettingDeserializerContextual()), false); 57 } 58 return builder; 59 } 60 } 61 62 @SuppressWarnings("serial") 63 static class ParentSettingDeserializer extends DelegatingDeserializer { ParentSettingDeserializer(JsonDeserializer<?> delegatee)64 public ParentSettingDeserializer(JsonDeserializer<?> delegatee) { 65 super(delegatee); 66 } 67 68 @Override deserialize(JsonParser jp, DeserializationContext ctxt)69 public Object deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { 70 Object retValue = super.deserialize(jp, ctxt); 71 if (retValue instanceof HasParent) { 72 HasParent obj = (HasParent) retValue; 73 Parent parent = null; 74 JsonStreamContext parsingContext = jp.getParsingContext(); 75 while (parent == null && parsingContext != null) { 76 Object currentValue = parsingContext.getCurrentValue(); 77 if (currentValue != null && currentValue instanceof Parent) { 78 parent = (Parent) currentValue; 79 } 80 parsingContext = parsingContext.getParent(); 81 } 82 if (parent != null) { 83 obj.setParent(parent); 84 } 85 } 86 return retValue; 87 } 88 89 @Override newDelegatingInstance(JsonDeserializer<?> newDelegatee)90 protected JsonDeserializer<?> newDelegatingInstance(JsonDeserializer<?> newDelegatee) { 91 return new ParentSettingDeserializer(newDelegatee); 92 } 93 94 } 95 96 static class ParentSettingDeserializerContextual extends JsonDeserializer<Object> implements ContextualDeserializer { 97 98 @Override createContextual(DeserializationContext ctxt, BeanProperty property)99 public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) 100 throws JsonMappingException { 101 JavaType propertyType = property.getType(); 102 JavaType contentType = propertyType; 103 if (propertyType.isCollectionLikeType()) { 104 contentType = propertyType.getContentType(); 105 } 106 JsonDeserializer<Object> delegatee = ctxt.findNonContextualValueDeserializer(contentType); 107 JsonDeserializer<Object> objectDeserializer = new ParentSettingDeserializer(delegatee); 108 JsonDeserializer<?> retValue; 109 if (propertyType.isCollectionLikeType()) { 110 CollectionLikeType collectionType = ctxt.getTypeFactory().constructCollectionLikeType(propertyType.getRawClass(), 111 contentType); 112 ValueInstantiator instantiator = new ListValueInstantiator(); 113 retValue = new CollectionDeserializer(collectionType, objectDeserializer, null, instantiator); 114 } else { 115 retValue = objectDeserializer; 116 } 117 return retValue; 118 } 119 120 @Override deserialize(JsonParser p, DeserializationContext ctxt)121 public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { 122 // TODO Auto-generated method stub 123 return null; 124 } 125 126 } 127 128 /* 129 /********************************************************************** 130 /* Test methods 131 /********************************************************************** 132 */ 133 134 private ObjectMapper objectMapper; 135 { 136 objectMapper = new ObjectMapper(); objectMapper.registerModule(new com.fasterxml.jackson.databind.Module() { @Override public String getModuleName() { return "parentSetting"; } @Override public Version version() { return Version.unknownVersion(); } @Override public void setupModule(SetupContext context) { context.addBeanDeserializerModifier(new ParentSettingDeserializerModifier()); } })137 objectMapper.registerModule(new com.fasterxml.jackson.databind.Module() { 138 @Override 139 public String getModuleName() { 140 return "parentSetting"; 141 } 142 @Override 143 public Version version() { 144 return Version.unknownVersion(); 145 } 146 @Override 147 public void setupModule(SetupContext context) { 148 context.addBeanDeserializerModifier(new ParentSettingDeserializerModifier()); 149 } 150 }); 151 } 152 153 final static String JSON = "{\n" + 154 " \"children\": [\n" + 155 " {\n" + 156 " \"property\": \"value1\"\n" + 157 " },\n" + 158 " {\n" + 159 " \"property\": \"value2\"\n" + 160 " }\n" + 161 " ],\n" + 162 " \"singleChild\": {\n" + 163 " \"property\": \"value3\"\n" + 164 " }\n" + 165 "}"; 166 testReadNoBuffering()167 public void testReadNoBuffering() throws IOException { 168 Parent obj = objectMapper.readerFor(Parent.class).readValue(JSON); 169 assertSame(obj, obj.singleChild.getParent()); 170 for (Child child : obj.children) { 171 assertSame(obj, child.getParent()); 172 } 173 } 174 testReadFromTree()175 public void testReadFromTree() throws IOException { 176 JsonNode tree = objectMapper.readTree(JSON); 177 Parent obj = objectMapper.reader().forType(Parent.class).readValue(tree); 178 assertSame(obj, obj.singleChild.getParent()); 179 for (Child child : obj.children) { 180 assertSame(obj, child.getParent()); 181 } 182 } 183 } 184