1 package org.apache.fulcrum.json.gson;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.lang.reflect.Type;
23 import java.text.DateFormat;
24 import java.text.SimpleDateFormat;
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.Date;
28 import java.util.EnumSet;
29 import java.util.Enumeration;
30 import java.util.HashSet;
31 import java.util.Hashtable;
32 import java.util.Set;
33 import java.util.concurrent.Callable;
34
35 import org.apache.avalon.framework.activity.Initializable;
36 import org.apache.avalon.framework.configuration.Configurable;
37 import org.apache.avalon.framework.configuration.Configuration;
38 import org.apache.avalon.framework.configuration.ConfigurationException;
39 import org.apache.avalon.framework.logger.AbstractLogEnabled;
40 import org.apache.fulcrum.json.JsonService;
41
42 import com.google.gson.ExclusionStrategy;
43 import com.google.gson.FieldAttributes;
44 import com.google.gson.Gson;
45 import com.google.gson.GsonBuilder;
46 import com.google.gson.reflect.TypeToken;
47 import com.jayway.jsonpath.Option;
48 import com.jayway.jsonpath.spi.json.GsonJsonProvider;
49 import com.jayway.jsonpath.spi.json.JsonProvider;
50 import com.jayway.jsonpath.spi.mapper.GsonMappingProvider;
51 import com.jayway.jsonpath.spi.mapper.MappingProvider;
52
53
54
55
56
57
58
59
60
61
62
63 public class GSONBuilderService extends AbstractLogEnabled implements
64 JsonService, Initializable, Configurable {
65
66 private static final String GLOBAL_ADAPTERS = "globalAdapters";
67
68 private static final String DATE_FORMAT = "dateFormat";
69
70 private static final String USEJSONPATH = "useJsonPath";
71
72 private String dateFormat;
73
74 private Hashtable<String, String> adapters = null;
75
76 private boolean useJsonPath = false;
77
78 GsonBuilder gson;
79
80 @Override
81 public String ser(Object src) throws Exception {
82 getLogger().debug("ser" + src);
83 return gson.create().toJson(src);
84 }
85
86 @Override
87 public <T> String ser(Object src, Class<T> type) throws Exception {
88 getLogger().debug("ser::" + src + " with type" + type);
89
90 Type collectionType = new TypeToken<T>() {
91 }.getType();
92 return gson.create().toJson(src, collectionType);
93 }
94
95 @Override
96 public <T> T deSer(String json, Class<T> type) throws Exception {
97
98 getLogger().debug("deser:" + json);
99 return gson.create().fromJson(json, type);
100 }
101
102 @Override
103 public <T> Collection<T> deSerCollection(String json, Object collectionType,
104 Class<T> elementType) throws Exception {
105 getLogger().debug("deser:" + json);
106 getLogger().debug("collectionType:" + collectionType);
107 return gson.create().fromJson(json, (Type)collectionType);
108 }
109
110 @Override
111 public String serializeOnlyFilter(Object src, String... filterAttr)
112 throws Exception {
113 return gson
114 .addSerializationExclusionStrategy(
115 include(null,filterAttr)).create().toJson(src);
116 }
117
118 @Override
119 public String serializeOnlyFilter(Object src, Boolean notused,
120 String... filterAttr) throws Exception {
121 return gson
122 .addSerializationExclusionStrategy(
123 include(null,filterAttr)).create().toJson(src);
124 }
125
126 @Override
127 public <T> String serializeOnlyFilter(Object src, Class<T> filterClass,
128 String... filterAttr) throws Exception {
129 return gson
130 .addSerializationExclusionStrategy(
131 include(filterClass, filterAttr)).create().toJson(src);
132 }
133
134 @Override
135 public <T> String serializeOnlyFilter(Object arg0, Class<T> arg1,
136 Boolean arg2, String... arg3) throws Exception {
137 throw new Exception("Not yet implemented!");
138 }
139
140
141
142
143
144
145 @Override
146 public JsonService addAdapter(String name, Class target, Object adapter)
147 throws Exception {
148 gson.registerTypeAdapter(target, adapter);
149 return this;
150 }
151
152
153
154
155
156
157
158 @Override
159 public JsonService addAdapter(String name, Class target, Class adapter)
160 throws Exception {
161 gson.registerTypeAdapter(target, adapter.getConstructor().newInstance());
162 return null;
163 }
164
165 @Override
166 public <T> String serializeAllExceptFilter(Object src,
167 Class<T> filterClass, String... filterAttr) throws Exception {
168 return gson
169 .addSerializationExclusionStrategy(
170 exclude(filterClass, filterAttr)).create().toJson(src);
171 }
172
173 @Override
174 public <T> String serializeAllExceptFilter(Object src, Class<T> filterClass,
175 Boolean clearCache, String... filterAttr) throws Exception {
176 throw new Exception("Not yet implemented!");
177 }
178
179 @Override
180 public String serializeAllExceptFilter(Object src, String... filterAttr)
181 throws Exception {
182 return gson
183 .addSerializationExclusionStrategy(
184 exclude(null, filterAttr)).create().toJson(src);
185 }
186
187 @Override
188 public String serializeAllExceptFilter(Object src, Boolean notused,
189 String... filterAttr) throws Exception {
190 return gson
191 .addSerializationExclusionStrategy(
192 exclude(null, filterAttr)).create().toJson(src);
193 }
194
195 @Override
196 public String ser(Object src, Boolean refreshCache) throws Exception {
197 throw new Exception("Not implemented!");
198 }
199
200 @Override
201 public <T> String ser(Object src, Class<T> type, Boolean refreshCache)
202 throws Exception {
203 throw new Exception("Not implemented!");
204 }
205
206 public JsonService registerTypeAdapter(Object serdeser, Type type) {
207 gson.registerTypeAdapter(type, serdeser);
208 return this;
209 }
210
211
212
213
214
215
216
217
218 public void setDateFormat(final String dfStr) {
219 gson.setDateFormat(dfStr);
220 }
221
222
223
224
225 @Override
226 public void setDateFormat(final DateFormat df) {
227 DateTypeAdapterr.html#DateTypeAdapter">DateTypeAdapter dateTypeAdapter = new DateTypeAdapter();
228 dateTypeAdapter.setCustomDateFormat(df);
229 gson.registerTypeAdapter(Date.class,dateTypeAdapter);
230 }
231
232 public void getJsonService() throws InstantiationException {
233
234
235
236
237 }
238
239
240
241
242 @Override
243 public void configure(Configuration conf) throws ConfigurationException {
244
245 getLogger().debug("conf.getName()" + conf.getName());
246 final Configuration configuredDateFormat = conf.getChild(DATE_FORMAT,
247 false);
248 if (configuredDateFormat != null) {
249 this.dateFormat = configuredDateFormat.getValue();
250 }
251 final Configuration configuredAdapters = conf.getChild(GLOBAL_ADAPTERS,
252 true);
253 if (configuredAdapters != null) {
254 Configuration[] nameVal = configuredAdapters.getChildren();
255 for (int i = 0; i < nameVal.length; i++) {
256 String key = nameVal[i].getName();
257 getLogger().debug("configured key: " + key);
258 if (key.equals("adapter")) {
259 String forClass = nameVal[i].getAttribute("forClass");
260 this.adapters = new Hashtable<String, String>();
261 this.adapters.put(forClass, nameVal[i].getValue());
262 }
263 }
264 }
265
266 final Configuration configuredjsonPath = conf.getChild(
267 USEJSONPATH, false);
268 if (configuredjsonPath != null) {
269 this.useJsonPath = configuredjsonPath.getValueAsBoolean();
270 }
271 }
272
273
274
275
276 @Override
277 public void initialize() throws Exception {
278 gson = new GsonBuilder();
279 getLogger().debug("initialized: gson:" + gson);
280 if (dateFormat != null) {
281 getLogger().info("setting date format to: " + dateFormat);
282 setDateFormat(new SimpleDateFormat(dateFormat));
283
284 }
285
286 if (adapters != null) {
287 Enumeration<String> enumKey = adapters.keys();
288 while (enumKey.hasMoreElements()) {
289 String forClass = enumKey.nextElement();
290 String avClass = adapters.get(forClass);
291 if (avClass != null) {
292 try {
293 getLogger().debug(
294 "initializing: adapters " + avClass
295 + " forClass:" + forClass);
296 Class adapterForClass = Class.forName(forClass);
297 Class adapterClass = Class.forName(avClass);
298 addAdapter("Test Adapter", adapterForClass,
299 adapterClass);
300
301 } catch (Exception e) {
302 throw new InstantiationException(
303 "JsonMapperService: Error instantiating one of the adapters: "
304 + avClass + " for " + forClass);
305 }
306 }
307 }
308 }
309
310 if (useJsonPath) {
311
312 com.jayway.jsonpath.Configuration.setDefaults(new com.jayway.jsonpath.Configuration.Defaults() {
313
314 private Callable<Gson> gsonFuture = new Callable<Gson>() {
315 @Override
316 public Gson call() {
317 return GSONBuilderService.this.gson.create();
318 }
319 };
320
321 private final JsonProvider jsonProvider = new GsonJsonProvider(GSONBuilderService.this.gson.create());
322 private final MappingProvider mappingProvider = new GsonMappingProvider(gsonFuture);
323
324 @Override
325 public JsonProvider jsonProvider() {
326 return jsonProvider;
327 }
328
329 @Override
330 public MappingProvider mappingProvider() {
331 return mappingProvider;
332 }
333
334 @Override
335 public Set<Option> options() {
336 return EnumSet.noneOf(Option.class);
337 }
338 });
339 }
340 }
341
342
343
344
345
346
347
348
349
350
351
352 private ExclusionStrategy exclude(Class clazz, String... filterAttrs) {
353 return new ExclusionStrategy() {
354
355 public Class<?> excludedThisClass;
356 public HashSet<String> excludedAttributes;
357
358 private ExclusionStrategy init(Class<?> excludedThisClass,
359 String... filterAttrs) {
360 this.excludedThisClass = excludedThisClass;
361 if (filterAttrs != null) {
362 this.excludedAttributes = new HashSet<String>(
363 filterAttrs.length);
364 Collections.addAll(this.excludedAttributes, filterAttrs);
365 } else
366 this.excludedAttributes = new HashSet<String>();
367
368 return this;
369 }
370
371 @Override
372 public boolean shouldSkipClass(Class<?> clazz) {
373 return (excludedThisClass != null) ? excludedThisClass
374 .equals(clazz) : false;
375 }
376
377 @Override
378 public boolean shouldSkipField(FieldAttributes paramFieldAttributes) {
379
380
381
382 return !excludedAttributes.isEmpty() ? this.excludedAttributes
383 .contains(paramFieldAttributes.getName()) : false;
384 }
385 }.init(clazz, filterAttrs);
386 }
387
388
389
390
391
392
393 private ExclusionStrategy include(Class clazz, String... filterAttrs) {
394 return new ExclusionStrategy() {
395
396 private Class<?> includeThisClass;
397 private HashSet<String> includedAttributes;
398
399 private ExclusionStrategy init(Class<?> includeThisClass,
400 String... filterAttrs) {
401 this.includeThisClass = includeThisClass;
402 if (filterAttrs != null) {
403 this.includedAttributes = new HashSet<String>(
404 filterAttrs.length);
405 getLogger().debug(" ... adding includedAttributes:" + filterAttrs.length);
406 Collections.addAll(this.includedAttributes, filterAttrs);
407 for (String includedAttribute : includedAttributes) {
408 getLogger().debug("includedAttribute:" +includedAttribute);
409 }
410 } else
411 this.includedAttributes = new HashSet<String>();
412
413 return this;
414 }
415
416
417
418
419 @Override
420 public boolean shouldSkipClass(Class<?> clazz) {
421 getLogger().debug(includeThisClass+ ": comparing include class:" + clazz);
422 return includeThisClass != null ? !includeThisClass
423 .equals(clazz) : false;
424 }
425
426
427
428
429 @Override
430 public boolean shouldSkipField(FieldAttributes paramFieldAttributes) {
431 return !includedAttributes.isEmpty() ? !this.includedAttributes
432 .contains(paramFieldAttributes.getName()) : true;
433
434 }
435 }.init(clazz, filterAttrs);
436 }
437
438 }