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 | 40 | 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 | 23 | private Hashtable<String, String> adapters = null; |
75 | |
|
76 | 23 | private boolean useJsonPath = false; |
77 | |
|
78 | |
GsonBuilder gson; |
79 | |
|
80 | |
@Override |
81 | |
public String ser(Object src) throws Exception { |
82 | 17 | getLogger().debug("ser" + src); |
83 | 17 | return gson.create().toJson(src); |
84 | |
} |
85 | |
|
86 | |
@Override |
87 | |
public <T> String ser(Object src, Class<T> type) throws Exception { |
88 | 0 | getLogger().debug("ser::" + src + " with type" + type); |
89 | |
|
90 | 0 | Type collectionType = new TypeToken<T>() { |
91 | |
}.getType(); |
92 | 0 | return gson.create().toJson(src, collectionType); |
93 | |
} |
94 | |
|
95 | |
@Override |
96 | |
public <T> T deSer(String json, Class<T> type) throws Exception { |
97 | |
|
98 | 2 | getLogger().debug("deser:" + json); |
99 | 2 | 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 | 1 | getLogger().debug("deser:" + json); |
106 | 1 | getLogger().debug("collectionType:" + collectionType); |
107 | 1 | return gson.create().fromJson(json, (Type)collectionType); |
108 | |
} |
109 | |
|
110 | |
@Override |
111 | |
public <T> String serializeOnlyFilter(Object src, String... filterAttr) |
112 | |
throws Exception { |
113 | 1 | return gson |
114 | |
.addSerializationExclusionStrategy( |
115 | |
include(null,filterAttr)).create().toJson(src); |
116 | |
} |
117 | |
|
118 | |
@Override |
119 | |
public <T> String serializeOnlyFilter(Object src, Boolean notused, |
120 | |
String... filterAttr) throws Exception { |
121 | 0 | 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 | 1 | 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 | 0 | 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 | 2 | gson.registerTypeAdapter(target, adapter); |
149 | 2 | 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 | 3 | gson.registerTypeAdapter(target, adapter.getConstructor().newInstance()); |
162 | 3 | return null; |
163 | |
} |
164 | |
|
165 | |
@Override |
166 | |
public <T> String serializeAllExceptFilter(Object src, |
167 | |
Class<T> filterClass, String... filterAttr) throws Exception { |
168 | 3 | 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 | 0 | throw new Exception("Not yet implemented!"); |
177 | |
} |
178 | |
|
179 | |
@Override |
180 | |
public <T> String serializeAllExceptFilter(Object src, String... filterAttr) |
181 | |
throws Exception { |
182 | 2 | return gson |
183 | |
.addSerializationExclusionStrategy( |
184 | |
exclude(null, filterAttr)).create().toJson(src); |
185 | |
} |
186 | |
|
187 | |
@Override |
188 | |
public <T> String serializeAllExceptFilter(Object src, Boolean notused, |
189 | |
String... filterAttr) throws Exception { |
190 | 0 | 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 | 0 | 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 | 0 | throw new Exception("Not implemented!"); |
204 | |
} |
205 | |
|
206 | |
public JsonService registerTypeAdapter(Object serdeser, Type type) { |
207 | 0 | gson.registerTypeAdapter(type, serdeser); |
208 | 0 | return this; |
209 | |
} |
210 | |
|
211 | |
|
212 | |
|
213 | |
|
214 | |
|
215 | |
|
216 | |
|
217 | |
|
218 | |
public void setDateFormat(final String dfStr) { |
219 | 0 | gson.setDateFormat(dfStr); |
220 | 0 | } |
221 | |
|
222 | |
@Override |
223 | |
public void setDateFormat(final DateFormat df) { |
224 | 26 | DateTypeAdapter dateTypeAdapter = new DateTypeAdapter(); |
225 | 26 | dateTypeAdapter.setCustomDateFormat(df); |
226 | 26 | gson.registerTypeAdapter(Date.class,dateTypeAdapter); |
227 | 26 | } |
228 | |
|
229 | |
public void getJsonService() throws InstantiationException { |
230 | |
|
231 | |
|
232 | |
|
233 | |
|
234 | 0 | } |
235 | |
|
236 | |
@Override |
237 | |
public void configure(Configuration conf) throws ConfigurationException { |
238 | |
|
239 | 23 | getLogger().debug("conf.getName()" + conf.getName()); |
240 | 23 | final Configuration configuredDateFormat = conf.getChild(DATE_FORMAT, |
241 | |
false); |
242 | 23 | if (configuredDateFormat != null) { |
243 | 23 | this.dateFormat = configuredDateFormat.getValue(); |
244 | |
} |
245 | 23 | final Configuration configuredAdapters = conf.getChild(GLOBAL_ADAPTERS, |
246 | |
true); |
247 | 23 | if (configuredAdapters != null) { |
248 | 23 | Configuration[] nameVal = configuredAdapters.getChildren(); |
249 | 23 | for (int i = 0; i < nameVal.length; i++) { |
250 | 0 | String key = nameVal[i].getName(); |
251 | 0 | getLogger().debug("configured key: " + key); |
252 | 0 | if (key.equals("adapter")) { |
253 | 0 | String forClass = nameVal[i].getAttribute("forClass"); |
254 | 0 | this.adapters = new Hashtable<String, String>(); |
255 | 0 | this.adapters.put(forClass, nameVal[i].getValue()); |
256 | |
} |
257 | |
} |
258 | |
} |
259 | |
|
260 | 23 | final Configuration configuredjsonPath = conf.getChild( |
261 | |
USEJSONPATH, false); |
262 | 23 | if (configuredjsonPath != null) { |
263 | 23 | this.useJsonPath = configuredjsonPath.getValueAsBoolean(); |
264 | |
} |
265 | 23 | } |
266 | |
|
267 | |
@Override |
268 | |
public void initialize() throws Exception { |
269 | 24 | gson = new GsonBuilder(); |
270 | 24 | getLogger().debug("initialized: gson:" + gson); |
271 | 24 | if (dateFormat != null) { |
272 | 24 | getLogger().info("setting date format to: " + dateFormat); |
273 | 24 | setDateFormat(new SimpleDateFormat(dateFormat)); |
274 | |
|
275 | |
} |
276 | |
|
277 | 24 | if (adapters != null) { |
278 | 0 | Enumeration<String> enumKey = adapters.keys(); |
279 | 0 | while (enumKey.hasMoreElements()) { |
280 | 0 | String forClass = enumKey.nextElement(); |
281 | 0 | String avClass = adapters.get(forClass); |
282 | 0 | if (avClass != null) { |
283 | |
try { |
284 | 0 | getLogger().debug( |
285 | |
"initializing: adapters " + avClass |
286 | |
+ " forClass:" + forClass); |
287 | 0 | Class adapterForClass = Class.forName(forClass); |
288 | 0 | Class adapterClass = Class.forName(avClass); |
289 | 0 | addAdapter("Test Adapter", adapterForClass, |
290 | |
adapterClass); |
291 | |
|
292 | 0 | } catch (Exception e) { |
293 | 0 | throw new Exception( |
294 | |
"JsonMapperService: Error instantiating " |
295 | |
+ avClass + " for " + forClass); |
296 | 0 | } |
297 | |
} |
298 | 0 | } |
299 | |
} |
300 | |
|
301 | 24 | if (useJsonPath) { |
302 | |
|
303 | 24 | com.jayway.jsonpath.Configuration.setDefaults(new com.jayway.jsonpath.Configuration.Defaults() { |
304 | |
|
305 | 24 | private Callable<Gson> gsonFuture = new Callable<Gson>() { |
306 | |
@Override |
307 | |
public Gson call() { |
308 | 4 | return GSONBuilderService.this.gson.create(); |
309 | |
} |
310 | |
}; |
311 | |
|
312 | 24 | private final JsonProvider jsonProvider = new GsonJsonProvider(GSONBuilderService.this.gson.create()); |
313 | 24 | private final MappingProvider mappingProvider = new GsonMappingProvider(gsonFuture); |
314 | |
|
315 | |
@Override |
316 | |
public JsonProvider jsonProvider() { |
317 | 5 | return jsonProvider; |
318 | |
} |
319 | |
|
320 | |
@Override |
321 | |
public MappingProvider mappingProvider() { |
322 | 5 | return mappingProvider; |
323 | |
} |
324 | |
|
325 | |
@Override |
326 | |
public Set<Option> options() { |
327 | 5 | return EnumSet.noneOf(Option.class); |
328 | |
} |
329 | |
}); |
330 | |
} |
331 | 24 | } |
332 | |
|
333 | |
|
334 | |
|
335 | |
|
336 | |
|
337 | |
|
338 | |
|
339 | |
|
340 | |
|
341 | |
|
342 | |
|
343 | |
private ExclusionStrategy exclude(Class clazz, String... filterAttrs) { |
344 | 10 | return new ExclusionStrategy() { |
345 | |
|
346 | |
public Class<?> excludedThisClass; |
347 | |
public HashSet<String> excludedAttributes; |
348 | |
|
349 | |
private ExclusionStrategy init(Class<?> excludedThisClass, |
350 | |
String... filterAttrs) { |
351 | 5 | this.excludedThisClass = excludedThisClass; |
352 | 5 | if (filterAttrs != null) { |
353 | 3 | this.excludedAttributes = new HashSet<String>( |
354 | |
filterAttrs.length); |
355 | 3 | Collections.addAll(this.excludedAttributes, filterAttrs); |
356 | |
} else |
357 | 2 | this.excludedAttributes = new HashSet<String>(); |
358 | |
|
359 | 5 | return this; |
360 | |
} |
361 | |
|
362 | |
@Override |
363 | |
public boolean shouldSkipClass(Class<?> clazz) { |
364 | 30 | return (excludedThisClass != null) ? excludedThisClass |
365 | |
.equals(clazz) : false; |
366 | |
} |
367 | |
|
368 | |
@Override |
369 | |
public boolean shouldSkipField(FieldAttributes paramFieldAttributes) { |
370 | |
|
371 | |
|
372 | |
|
373 | 10 | return !excludedAttributes.isEmpty() ? this.excludedAttributes |
374 | |
.contains(paramFieldAttributes.getName()) : false; |
375 | |
} |
376 | |
}.init(clazz, filterAttrs); |
377 | |
} |
378 | |
|
379 | |
private ExclusionStrategy include(Class clazz, String... filterAttrs) { |
380 | 4 | return new ExclusionStrategy() { |
381 | |
|
382 | |
private Class<?> includeThisClass; |
383 | |
private HashSet<String> includedAttributes; |
384 | |
|
385 | |
private ExclusionStrategy init(Class<?> includeThisClass, |
386 | |
String... filterAttrs) { |
387 | 2 | this.includeThisClass = includeThisClass; |
388 | 2 | if (filterAttrs != null) { |
389 | 2 | this.includedAttributes = new HashSet<String>( |
390 | |
filterAttrs.length); |
391 | 2 | getLogger().debug(" ... adding includedAttributes:" + filterAttrs.length); |
392 | 2 | Collections.addAll(this.includedAttributes, filterAttrs); |
393 | 2 | for (String includedAttribute : includedAttributes) { |
394 | 2 | getLogger().debug("includedAttribute:" +includedAttribute); |
395 | 2 | } |
396 | |
} else |
397 | 0 | this.includedAttributes = new HashSet<String>(); |
398 | |
|
399 | 2 | return this; |
400 | |
} |
401 | |
|
402 | |
|
403 | |
|
404 | |
|
405 | |
@Override |
406 | |
public boolean shouldSkipClass(Class<?> clazz) { |
407 | 13 | getLogger().debug(includeThisClass+ ": comparing include class:" + clazz); |
408 | 13 | return includeThisClass != null ? !includeThisClass |
409 | |
.equals(clazz) : false; |
410 | |
} |
411 | |
|
412 | |
|
413 | |
|
414 | |
|
415 | |
@Override |
416 | |
public boolean shouldSkipField(FieldAttributes paramFieldAttributes) { |
417 | 6 | return !includedAttributes.isEmpty() ? !this.includedAttributes |
418 | |
.contains(paramFieldAttributes.getName()) : true; |
419 | |
|
420 | |
} |
421 | |
}.init(clazz, filterAttrs); |
422 | |
} |
423 | |
|
424 | |
} |