1 package com.fasterxml.jackson.databind.ser.impl;
2
3 import java.util.Iterator;
4 import java.util.Map.Entry;
5
6 import com.fasterxml.jackson.core.JsonGenerator;
7 import com.fasterxml.jackson.core.io.SerializedString;
8 import com.fasterxml.jackson.databind.JavaType;
9 import com.fasterxml.jackson.databind.JsonMappingException;
10 import com.fasterxml.jackson.databind.JsonNode;
11 import com.fasterxml.jackson.databind.JsonSerializer;
12 import com.fasterxml.jackson.databind.SerializerProvider;
13 import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper;
14 import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonObjectFormatVisitor;
15 import com.fasterxml.jackson.databind.node.ObjectNode;
16 import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
17 import com.fasterxml.jackson.databind.util.NameTransformer;
18
19 /**
20  * Variant of {@link BeanPropertyWriter} which will handle unwrapping
21  * of JSON Object (including of properties of Object within surrounding
22  * JSON object, and not as sub-object).
23  */

24 public class UnwrappingBeanPropertyWriter
25     extends BeanPropertyWriter
26     implements java.io.Serializable
27 {
28     private static final long serialVersionUID = 1L;
29
30     /**
31      * Transformer used to add prefix and/or suffix for properties
32      * of unwrapped POJO.
33      */

34     protected final NameTransformer _nameTransformer;
35
36     /*
37     /**********************************************************
38     /* Life-cycle
39     /**********************************************************
40      */

41
42     public UnwrappingBeanPropertyWriter(BeanPropertyWriter base, NameTransformer unwrapper) {
43         super(base);
44         _nameTransformer = unwrapper;
45     }
46
47     protected UnwrappingBeanPropertyWriter(UnwrappingBeanPropertyWriter base, NameTransformer transformer,
48             SerializedString name) {
49         super(base, name);
50         _nameTransformer = transformer;
51     }
52
53     @Override
54     public UnwrappingBeanPropertyWriter rename(NameTransformer transformer)
55     {
56         String oldName = _name.getValue();
57         String newName = transformer.transform(oldName);
58
59         // important: combine transformers:
60         transformer = NameTransformer.chainedTransformer(transformer, _nameTransformer);
61     
62         return _new(transformer, new SerializedString(newName));
63     }
64
65     /**
66      * Overridable factory method used by sub-classes
67      *
68      * @since 2.6.0
69      */

70     protected UnwrappingBeanPropertyWriter _new(NameTransformer transformer, SerializedString newName)
71     {
72         return new UnwrappingBeanPropertyWriter(this, transformer, newName);
73     }
74
75     /*
76     /**********************************************************
77     /* Overrides, public methods
78     /**********************************************************
79      */

80
81     @Override
82     public boolean isUnwrapping() {
83         return true;
84     }
85
86     @Override
87     public void serializeAsField(Object bean, JsonGenerator gen, SerializerProvider prov)
88             throws Exception
89     {
90         final Object value = get(bean);
91         if (value == null) {
92             // Hmmh. I assume we MUST pretty much suppress nulls, since we
93             // can't really unwrap them...
94             return;
95         }
96         JsonSerializer<Object> ser = _serializer;
97         if (ser == null) {
98             Class<?> cls = value.getClass();
99             PropertySerializerMap map = _dynamicSerializers;
100             ser = map.serializerFor(cls);
101             if (ser == null) {
102                 ser = _findAndAddDynamic(map, cls, prov);
103             }
104         }
105         if (_suppressableValue != null) {
106             if (MARKER_FOR_EMPTY == _suppressableValue) {
107                 if (ser.isEmpty(prov, value)) {
108                     return;
109                 }
110             } else if (_suppressableValue.equals(value)) {
111                 return;
112             }
113         }
114         // For non-nulls, first: simple check for direct cycles
115         if (value == bean) {
116             if (_handleSelfReference(bean, gen, prov, ser)) {
117                 return;
118             }
119         }
120
121         // note: must verify we are using unwrapping serializer; if not, will write field name
122         if (!ser.isUnwrappingSerializer()) {
123             gen.writeFieldName(_name);
124         }
125
126         if (_typeSerializer == null) {
127             ser.serialize(value, gen, prov);
128         } else {
129             ser.serializeWithType(value, gen, prov, _typeSerializer);
130         }
131     }
132
133     // need to override as we must get unwrapping instance...
134     @Override
135     public void assignSerializer(JsonSerializer<Object> ser)
136     {
137         if (ser != null) {
138             NameTransformer t = _nameTransformer;
139             if (ser.isUnwrappingSerializer()
140                     // as per [databind#2060], need to also check this, in case someone writes
141                     // custom implementation that does not extend standard implementation:
142                     && (ser instanceof UnwrappingBeanSerializer)) {
143                 t = NameTransformer.chainedTransformer(t, ((UnwrappingBeanSerializer) ser)._nameTransformer);
144             }
145             ser = ser.unwrappingSerializer(t);
146         }
147         super.assignSerializer(ser);
148     }
149
150     /*
151     /**********************************************************
152     /* Overrides: schema generation
153     /**********************************************************
154      */

155
156     @Override
157     public void depositSchemaProperty(final JsonObjectFormatVisitor visitor,
158             SerializerProvider provider) throws JsonMappingException
159     {
160         JsonSerializer<Object> ser = provider
161                 .findValueSerializer(this.getType(), this)
162                 .unwrappingSerializer(_nameTransformer);
163
164         if (ser.isUnwrappingSerializer()) {
165             ser.acceptJsonFormatVisitor(new JsonFormatVisitorWrapper.Base(provider) {
166                 // an unwrapping serializer will always expect ObjectFormat,
167                 // hence, the other cases do not have to be implemented
168                 @Override
169                 public JsonObjectFormatVisitor expectObjectFormat(JavaType type)
170                         throws JsonMappingException {
171                     return visitor;
172                 }
173             }, this.getType());
174         } else {
175             super.depositSchemaProperty(visitor, provider);
176         }
177     }
178
179     // Override needed to support legacy JSON Schema generator
180     @Override
181     protected void _depositSchemaProperty(ObjectNode propertiesNode, JsonNode schemaNode)
182     {
183         JsonNode props = schemaNode.get("properties");
184         if (props != null) {
185             Iterator<Entry<String, JsonNode>> it = props.fields();
186             while (it.hasNext()) {
187                 Entry<String,JsonNode> entry = it.next();
188                 String name = entry.getKey();
189                 if (_nameTransformer != null) {
190                     name = _nameTransformer.transform(name);
191                 }
192                 propertiesNode.set(name, entry.getValue());
193             }
194         }
195     }
196
197     /*
198     /**********************************************************
199     /* Overrides: internal, other
200     /**********************************************************
201      */

202     
203     // need to override as we must get unwrapping instance...
204     @Override
205     protected JsonSerializer<Object> _findAndAddDynamic(PropertySerializerMap map,
206             Class<?> type, SerializerProvider provider) throws JsonMappingException
207     {
208         JsonSerializer<Object> serializer;
209         if (_nonTrivialBaseType != null) {
210             JavaType subtype = provider.constructSpecializedType(_nonTrivialBaseType, type);
211             serializer = provider.findValueSerializer(subtype, this);
212         } else {
213             serializer = provider.findValueSerializer(type, this);
214         }
215         NameTransformer t = _nameTransformer;
216         if (serializer.isUnwrappingSerializer()
217             // as per [databind#2060], need to also check this, in case someone writes
218             // custom implementation that does not extend standard implementation:
219             && (serializer instanceof UnwrappingBeanSerializer)) {
220                 t = NameTransformer.chainedTransformer(t, ((UnwrappingBeanSerializer) serializer)._nameTransformer);
221         }
222         serializer = serializer.unwrappingSerializer(t);
223         
224         _dynamicSerializers = _dynamicSerializers.newWith(type, serializer);
225         return serializer;
226     }
227 }
228