last analyzed

Size

Total Lines 6
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 5
dl 0
loc 6
c 1
b 0
f 0
1
package es.webbeta;
2
3
import com.fasterxml.jackson.core.JsonFactory;
4
import com.fasterxml.jackson.core.JsonGenerator;
5
import es.webbeta.serializer.*;
6
import es.webbeta.serializer.base.FieldFormatter;
7
import es.webbeta.serializer.base.Logger;
8
import es.webbeta.serializer.base.ParentFieldData;
9
import es.webbeta.serializer.base.SerializerMetadataProvider;
10
import es.webbeta.serializer.type.DateFormatType;
11
import es.webbeta.serializer.type.FieldAccessType;
12
13
import java.io.IOException;
14
import java.io.StringWriter;
15
import java.math.BigDecimal;
16
import java.math.BigInteger;
17
import java.text.SimpleDateFormat;
18
import java.util.Date;
19
import java.util.Map;
20
21
public class Serializer {
22
23
    private final ConfigurationManager configurationManager;
24
25
    private SerializerMetadataProvider provider;
26
    private FieldFormatter formatter;
27
    private TypeChecker typeChecker;
28
29
    private JsonGenerator generator;
30
    private StringWriter writer;
31
32
    private Logger logger;
33
34
    Serializer(ConfigurationManager configurationManager) {
35
        this.configurationManager = configurationManager;
36
        formatter = configurationManager.getFieldFormatter();
37
    }
38
39
    public void setLogger(Logger logger) {
40
        this.logger = logger;
41
    }
42
43
    /**
44
     * Inits serialization context
45
     *
46
     * @return True if it went ok
47
     */
48
    private Boolean initializeGenerator() {
49
        writer = new StringWriter();
50
        JsonFactory factory = new JsonFactory();
51
        provider = configurationManager.newMetadataProvider();
52
        typeChecker = new TypeChecker(provider);
53
54
        try {
55
            generator = factory.createGenerator(writer);
56
            return true;
57
        } catch (IOException e) {
58
            generator = null;
59
            return false;
60
        }
61
    }
62
63
    private FieldAccessor buildFieldAccessor(Object ob, String fieldName) {
64
        Class<?> klass = ob.getClass();
65
66
        FieldAccessType accessType = configurationManager.getAccessType();
67
        if (provider.hasAccessType(klass))
68
            accessType = provider.getAccessType(klass);
69
        if (provider.hasPropertyAccessType(klass, fieldName))
70
            accessType = provider.getPropertyAccessType(klass, fieldName);
71
72
        String customGetter = provider.getPropertyCustomGetterName(klass, fieldName);
73
74
        FieldAccessor fieldAccessor = new FieldAccessor(ob, fieldName, accessType);
75
        fieldAccessor.setCustomGetterName(customGetter);
76
77
        if (logger != null) {
78
            fieldAccessor.setLogger(logger);
79
        }
80
81
        if (provider.isVirtualProperty(klass, fieldName))
82
            fieldAccessor.setEnsureFieldExists(false);
83
84
        return fieldAccessor;
85
    }
86
87
    private String getSerializedName(Class<?> klass, String fieldName) {
88
        String finalFieldName = formatter.format(fieldName);
89
        if (provider.hasPropertySerializedName(klass, fieldName))
90
            finalFieldName = provider.getPropertySerializedName(klass, fieldName);
91
92
        return finalFieldName;
93
    }
94
95
    private void fillDateValue(JsonGenerator gen, final Date date) throws IOException {
96
        if (configurationManager.getDateFormatType() == DateFormatType.ISO8601) {
97
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
98
            gen.writeString(format.format(date));
99
        } else if (configurationManager.getDateFormatType() == DateFormatType.UNIX_TIMESTAMP)
100
            gen.writeNumber(date.getTime());
101
    }
102
103
    private void fillRawValue(JsonGenerator gen, final ParentFieldData parentFieldData, final Object value, final String[] group) throws IOException {
104
        typeChecker.check(value, new TypeCallback() {
105
106
            @Override
107
            public void itsByte(Byte value) throws IOException {
108
                gen.writeNumber(value);
109
            }
110
111
            @Override
112
            public void itsShort(Short value) throws IOException {
113
                gen.writeNumber(value);
114
            }
115
116
            @Override
117
            public void itsInteger(Integer value) throws IOException {
118
                gen.writeNumber(value);
119
            }
120
121
            @Override
122
            public void itsBigInteger(BigInteger value) throws IOException {
123
                gen.writeNumber(value);
124
            }
125
126
            @Override
127
            public void itsLong(Long value) throws IOException {
128
                gen.writeNumber(value);
129
            }
130
131
            @Override
132
            public void itsFloat(Float value) throws IOException {
133
                gen.writeNumber(value);
134
            }
135
136
            @Override
137
            public void itsDouble(Double value) throws IOException {
138
                gen.writeNumber(value);
139
            }
140
141
            @Override
142
            public void itsBigDecimal(BigDecimal value) throws IOException {
143
                gen.writeNumber(value);
144
            }
145
146
            @Override
147
            public void itsString(String value) throws IOException {
148
                gen.writeString(value);
149
            }
150
151
            @Override
152
            public void itsStringParseable(Object value) throws IOException {
153
                gen.writeString(value.toString());
154
            }
155
156
            @Override
157
            public void itsBoolean(Boolean value) throws IOException {
158
                gen.writeBoolean(value);
159
            }
160
161
            @Override
162
            public void itsDate(Date value) throws IOException {
163
                fillDateValue(gen, value);
164
            }
165
166
            @Override
167
            public void itsSerializableObject(Object value) throws IOException {
168
                if (parentFieldData != null && parentFieldData.getKlass() == value.getClass()) {
169
                    fillWith(false, gen, parentFieldData, value, parentFieldData.getGroups());
170
                } else
171
                    fillWith(false, gen, parentFieldData, value, group);
172
            }
173
174
            @Override
175
            public void itsIterable(Iterable<?> value) throws IOException {
176
                gen.writeStartArray();
177
                for (Object arrValue : value) {
178
                    String[] parentGroups = provider.getGroupsByFieldName(parentFieldData.getKlass(), parentFieldData.getFieldName());
179
                    es.webbeta.serializer.ParentFieldData fieldData =
180
                            new es.webbeta.serializer.ParentFieldData(parentFieldData.getKlass(), parentFieldData.getFieldName(), parentGroups);
181
182
                    fillRawValue(gen, fieldData, arrValue, group);
183
                }
184
                gen.writeEndArray();
185
            }
186
187
            @Override
188
            public void itsMap(Map<?, ?> value) throws IOException {
189
                gen.writeStartObject();
190
                for (Map.Entry<?, ?> entry : value.entrySet()) {
191
                    String[] parentGroups = provider.getGroupsByFieldName(parentFieldData.getKlass(), parentFieldData.getFieldName());
192
                    es.webbeta.serializer.ParentFieldData fieldData =
193
                            new es.webbeta.serializer.ParentFieldData(parentFieldData.getKlass(), parentFieldData.getFieldName(), parentGroups);
194
195
                    gen.writeFieldName(entry.getKey().toString());
196
                    fillRawValue(gen, fieldData, entry.getValue(), group);
197
                }
198
                gen.writeEndObject();
199
            }
200
201
        });
202
    }
203
204
    private void fillWith(Boolean asArray, JsonGenerator gen, final ParentFieldData parentData, final Object ob, final String[] group) throws IOException {
205
        Class<?> klass = ob.getClass();
206
        String[] fields = provider.getPropertiesByGroup(klass, parentData, group);
207
        if (asArray)
208
            gen.writeStartArray();
209
        else
210
            gen.writeStartObject();
211
212
        if (typeChecker.isSerializableObject(ob)) {
213
            for (String fieldName : fields) {
214
                FieldAccessor accessor = buildFieldAccessor(ob, fieldName);
215
216
                if (accessor.get() == null) {
217
                    if (accessor.exists() && configurationManager.getIncludeNullValues()) {
218
                        gen.writeFieldName(getSerializedName(klass, fieldName));
219
                        gen.writeNull();
220
                    }
221
                    continue;
222
                }
223
224
                if (!typeChecker.isUnserializableObject(accessor.get())) {
225
                    es.webbeta.serializer.ParentFieldData fieldData =
226
                            new es.webbeta.serializer.ParentFieldData(klass, fieldName, group);
227
228
                    gen.writeFieldName(getSerializedName(klass, fieldName));
229
                    fillRawValue(gen, fieldData, accessor.get(), group);
230
                }
231
            }
232
        } else if (typeChecker.isIterable(ob)) {
233
            for (Object arrValue : (Iterable<?>) ob) {
234
                es.webbeta.serializer.ParentFieldData fieldData =
235
                        new es.webbeta.serializer.ParentFieldData(arrValue.getClass(), null, group);
236
237
                fillRawValue(gen, fieldData, arrValue, group);
238
            }
239
        }
240
241
        if (asArray)
242
            gen.writeEndArray();
243
        else
244
            gen.writeEndObject();
245
    }
246
247
    /**
248
     * It serializes an object without specifing serialization groups
249
     *
250
     * @param ob Object to serialize
251
     * @return JSON format string representing the object
252
     */
253
    public <T> String serialize(T ob) {
254
        return serialize(ob, new String[0]);
255
    }
256
257
    /**
258
     * It serializes an object specifing serialization groups
259
     *
260
     * @param ob    Object to serialize
261
     * @param group Serialization group or groups
262
     * @return JSON format string representing the object
263
     */
264
    public <T> String serialize(T ob, String... group) {
265
        if (ob == null) return null;
266
267
        if (!initializeGenerator())
268
            return null;
269
270
        try {
271
            fillWith(typeChecker.isIterable(ob), generator, null, ob, group);
272
273
            generator.close();
274
275
            return writer.toString();
276
        } catch (IOException e) {
277
            return null;
278
        }
279
    }
280
281
}
282