1 package org.apache.fulcrum.json.jackson;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 import java.io.IOException;
22 import java.text.DateFormat;
23 import java.text.SimpleDateFormat;
24 import java.util.Arrays;
25 import java.util.Collection;
26 import java.util.HashMap;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Map.Entry;
30
31 import org.apache.avalon.framework.activity.Initializable;
32 import org.apache.avalon.framework.configuration.Configurable;
33 import org.apache.avalon.framework.configuration.Configuration;
34 import org.apache.avalon.framework.configuration.ConfigurationException;
35 import org.apache.avalon.framework.logger.AbstractLogEnabled;
36 import org.apache.avalon.framework.logger.LogEnabled;
37 import org.apache.commons.lang3.StringUtils;
38 import org.apache.fulcrum.json.JsonService;
39 import org.apache.fulcrum.json.jackson.filters.CustomModuleWrapper;
40 import org.apache.fulcrum.json.jackson.jsonpath.DefaultJsonPathWrapper;
41
42 import com.fasterxml.jackson.core.JsonGenerator;
43 import com.fasterxml.jackson.core.JsonParser;
44 import com.fasterxml.jackson.core.JsonParser.Feature;
45 import com.fasterxml.jackson.core.JsonProcessingException;
46 import com.fasterxml.jackson.core.SerializableString;
47 import com.fasterxml.jackson.core.io.CharacterEscapes;
48 import com.fasterxml.jackson.core.type.TypeReference;
49 import com.fasterxml.jackson.databind.AnnotationIntrospector;
50 import com.fasterxml.jackson.databind.DeserializationFeature;
51 import com.fasterxml.jackson.databind.JsonDeserializer;
52 import com.fasterxml.jackson.databind.JsonSerializer;
53 import com.fasterxml.jackson.databind.MapperFeature;
54 import com.fasterxml.jackson.databind.Module;
55 import com.fasterxml.jackson.databind.ObjectMapper;
56 import com.fasterxml.jackson.databind.ObjectMapper.DefaultTyping;
57 import com.fasterxml.jackson.databind.ObjectReader;
58 import com.fasterxml.jackson.databind.SerializationFeature;
59 import com.fasterxml.jackson.databind.SerializerProvider;
60 import com.fasterxml.jackson.databind.cfg.ConfigFeature;
61 import com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair;
62 import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;
63 import com.fasterxml.jackson.databind.module.SimpleModule;
64 import com.fasterxml.jackson.databind.ser.FilterProvider;
65 import com.fasterxml.jackson.databind.ser.PropertyFilter;
66 import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
67 import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91 public class Jackson2MapperService extends AbstractLogEnabled implements JsonService, Initializable, Configurable {
92
93 private static final String DEFAULT_TYPING = "defaultTyping";
94 private static final String CACHE_FILTERS = "cacheFilters";
95 private static final String DATE_FORMAT = "dateFormat";
96 private static final String ESCAPE_CHARS = "escapeCharsGlobal";
97 private static final String ESCAPE_CHAR_CLASS = "escapeCharsClass";
98 private static final String USE_JSON_PATH = "useJsonPath";
99 ObjectMapper mapper;
100 AnnotationIntrospector primary;
101 AnnotationIntrospector secondary;
102
103 private static final String ANNOTATIONINSPECTOR = "annotationInspectors";
104
105 private Map<String, String> annotationInspectors = null;
106 private Map<String, Boolean> features = null;
107 private Map<String, String> featureTypes = null;
108
109 private String dateFormat;
110
111
112
113
114
115 public static final String DEFAULTDATEFORMAT = "MM/dd/yyyy";
116
117
118 private boolean cacheFilters = true;
119
120 String[] defaultTypeDefs = null;
121 private CacheService cacheService;
122 private boolean escapeCharsGlobal = false;
123
124 private boolean useJsonPath = false;
125 private String escapeCharsClass = null;
126
127 @Override
128 public String ser(Object src) throws Exception {
129 return ser(src, false);
130 }
131
132 @Override
133 public <T> String ser(Object src, Class<T> type) throws Exception {
134 return ser(src, type, false);
135 }
136
137 public String ser(Object src, FilterProvider filter) throws Exception {
138 return ser(src, filter, false);
139 }
140
141
142
143
144
145
146
147
148
149 public String ser(Object src, FilterProvider filter, Boolean cleanCache) throws Exception {
150 String serResult = null;
151 if (src == null) {
152 getLogger().info("no serializable object.");
153 return serResult;
154 }
155 if (filter == null) {
156 getLogger().debug("ser class::" + src.getClass() + " without filter.");
157 return ser(src);
158 } else {
159 getLogger().debug("add filter for cache filter Class " + src.getClass().getName());
160 setCustomIntrospectorWithExternalFilterId(src.getClass(), null);
161 if (isCacheFilters()) {
162 cacheService.getFilters().put(src.getClass().getName(), filter);
163 }
164 }
165 getLogger().debug("ser class::" + src.getClass() + " with filter " + filter);
166 mapper.setFilterProvider(filter);
167 String res = mapper.writer(filter).writeValueAsString(src);
168 if (cleanCache) {
169 cacheService.cleanSerializerCache(mapper);
170 }
171 return res;
172 }
173
174 @Override
175 public <T> T deSer(String json, Class<T> type) throws Exception {
176 ObjectReader reader = null;
177 if (type != null)
178 reader = mapper.readerFor(type);
179 else
180 reader = mapper.reader();
181
182 return reader.readValue(json);
183 }
184
185
186
187
188
189
190
191
192 public <T> T deSer(Object src, Class<T> type) {
193 return mapper.convertValue(src, type);
194 }
195
196
197
198
199
200
201
202
203
204
205
206
207
208 @Override
209 public JsonService addAdapter(String name, Class target, Object module)
210 throws Exception {
211 if (module instanceof CustomModuleWrapper) {
212 CustomModuleWrapper./../org/apache/fulcrum/json/jackson/filters/CustomModuleWrapper.html#CustomModuleWrapper">CustomModuleWrapper cmw = (CustomModuleWrapper) module;
213 Module cm = new CustomModule(name, target, cmw.getSer(),
214 cmw.getDeSer());
215 getLogger().debug("registering custom module " + cm + " for: " + target);
216 mapper.registerModule(cm);
217 } else if (module instanceof Module) {
218 getLogger().debug(
219 "registering module " + module );
220 mapper.registerModule((Module) module);
221 } else {
222 throw new ClassCastException("expecting module type " + Module.class);
223 }
224 return this;
225 }
226
227 public Class<?> showMixinForClass(Class target) {
228 Class<?> mixin = mapper.findMixInClassFor( target );
229 getLogger().debug("find mixin for target " + target + " -> mixin: " + mixin);
230 return mixin;
231 }
232
233 public <T> List<T> deSerList(String json, Class<? extends List> targetList, Class<T> elementType) throws Exception {
234 return mapper.readValue(json, mapper.getTypeFactory().constructParametricType(targetList, elementType));
235 }
236
237 public <T, U> Map<T, U> deSerMap(String json, Class<? extends Map> mapClass, Class<T> keyClass, Class<U> valueClass)
238 throws Exception {
239 return mapper.readValue(json, mapper.getTypeFactory().constructMapType(mapClass, keyClass, valueClass));
240 }
241
242 public <T> Collection<T> deSerCollectionWithTypeReference(String json, TypeReference<T> collectionType)
243 throws Exception {
244 return (Collection<T>) mapper.readValue(json, collectionType);
245 }
246
247 public <T> Collection<T> deSerCollectionWithType(String json, Class<? extends Collection> collectionClass,
248 Class<T> type) throws Exception {
249 return mapper.readValue(json, mapper.getTypeFactory().constructCollectionType(collectionClass, type));
250 }
251
252 @Override
253 public <T> Collection<T> deSerCollection(String json, Object collectionType, Class<T> elementType)
254 throws Exception {
255 if (collectionType instanceof TypeReference) {
256 return deSerCollectionWithTypeReference(json, (TypeReference<T>) collectionType);
257 } else {
258 return mapper.readValue(json, mapper.getTypeFactory()
259 .constructCollectionType(((Collection<T>) collectionType).getClass(), elementType));
260 }
261 }
262
263
264
265
266
267
268
269
270
271 public <T> String serCollectionWithTypeReference(Collection<T> src, TypeReference collectionType,
272 Boolean cleanCache) throws JsonProcessingException {
273 String res = mapper.writerFor(collectionType).writeValueAsString(src);
274 if (cleanCache) {
275 cacheService.cleanSerializerCache(mapper);
276 }
277 return res;
278 }
279
280
281
282
283
284
285
286
287
288 @Override
289 public JsonService addAdapter(String name, Class target, Class mixin) throws Exception {
290 getLogger().debug(
291 "registering unversioned simple mixin module named " + name + " of type " + mixin + " for: " + target);
292 mapper.addMixIn(target, mixin);
293 return this;
294 }
295
296
297
298
299
300
301
302
303
304
305
306
307 @SuppressWarnings("rawtypes")
308 public String withMixinModule(Object src, String name, Class target, Class mixin) throws JsonProcessingException {
309 Module mx = new MixinModule(name, target, mixin);
310 getLogger().debug("registering module " + mx + ", mixin: " + mixin);
311 return mapper.registerModule(mx).writer().writeValueAsString(src);
312 }
313
314
315
316
317
318
319
320
321
322
323
324 @SuppressWarnings("rawtypes")
325 public String withSetMixins(Object src, Class target, Class mixin) throws JsonProcessingException {
326 return setMixins(target, mixin).writer().writeValueAsString(src);
327 }
328
329
330
331
332
333
334 @SuppressWarnings("rawtypes")
335 public ObjectMapper setMixins(Class target, Class mixin) {
336 Map<Class<?>, Class<?>> sourceMixins = null;
337 if (target != null) {
338 sourceMixins = new HashMap<>(1);
339 sourceMixins.put(target, mixin);
340 }
341 getLogger().debug("complete reset mixins for target " + target + ", mixin: " + mixin);
342 return mapper.setMixIns(sourceMixins);
343 }
344
345 @Override
346 public String serializeAllExceptFilter(Object src, String... filterAttr) throws Exception {
347 return serializeAllExceptFilter(src, src.getClass(), true, filterAttr);
348 }
349
350 @Override
351 public synchronized String serializeAllExceptFilter(Object src, Boolean cache, String... filterAttr)
352 throws Exception {
353 return serializeAllExceptFilter(src, src.getClass(), cache, filterAttr);
354 }
355
356 public synchronized <T> String serializeAllExceptFilter(Object src, Class<T>[] filterClasses, String... filterAttr)
357 throws Exception {
358 return serializeAllExceptFilter(src, filterClasses, true, filterAttr);
359 }
360
361 @Override
362 public synchronized <T> String serializeAllExceptFilter(Object src, Class<T> filterClass, String... filterAttr)
363 throws Exception {
364 return serializeAllExceptFilter(src, filterClass, true, filterAttr);
365 }
366
367 @Override
368 public <T> String serializeAllExceptFilter(Object src, Class<T> filterClass, Boolean cleanFilter,
369 String... filterAttr) throws Exception {
370 return serializeAllExceptFilter(src, new Class[] { filterClass }, cleanFilter, filterAttr);
371 }
372
373
374
375
376
377
378
379
380
381
382
383
384 public synchronized <T> String serializeAllExceptFilter(Object src, Class<T>[] filterClasses, Boolean clean,
385 String... filterAttr) throws Exception {
386 PropertyFilter pf = null;
387 if (filterAttr != null)
388 pf = SimpleBeanPropertyFilter.serializeAllExcept(filterAttr);
389 else if (filterClasses == null) {
390 return ser(src, clean);
391
392
393
394 }
395 return filter(src, new Class<?>[] { filterClasses[0] }, filterClasses, pf, clean);
396 }
397
398 @Override
399 public String serializeOnlyFilter(Object src, String... filterAttrs) throws Exception {
400 return serializeOnlyFilter(src, src.getClass(), true, filterAttrs);
401 }
402
403 @Override
404 public synchronized String serializeOnlyFilter(Object src, Boolean cache, String... filterAttr) throws Exception {
405 return serializeOnlyFilter(src, src.getClass(), cache, filterAttr);
406 }
407
408 @Override
409 public synchronized <T> String serializeOnlyFilter(Object src, Class<T> filterClass, String... filterAttr)
410 throws Exception {
411 return serializeOnlyFilter(src, filterClass, true, filterAttr);
412 }
413
414 @Override
415 public synchronized <T> String serializeOnlyFilter(Object src, Class<T> filterClass, Boolean refresh,
416 String... filterAttr) throws Exception {
417 return serializeOnlyFilter(src, new Class[] { filterClass }, refresh, filterAttr);
418 }
419
420 public synchronized <T> String serializeOnlyFilter(Object src, Class<T>[] filterClasses, Boolean refresh,
421 String... filterAttr) throws Exception {
422 PropertyFilter pf = null;
423 if (filterAttr != null && filterAttr.length > 0 && !"".equals(filterAttr[0])) {
424 pf = SimpleBeanPropertyFilter.filterOutAllExcept(filterAttr);
425 getLogger().debug("setting filteroutAllexcept filter for size of filterAttr: " + filterAttr.length);
426 } else {
427 getLogger().warn("no filter attributes set!");
428 pf = SimpleBeanPropertyFilter.filterOutAllExcept("dummy");
429 }
430 if (filterClasses == null)
431 throw new AssertionError("You have to provide some class to apply the filtering!");
432 return filter(src, filterClasses, null, pf, refresh);
433 }
434
435 @Override
436 public String ser(Object src, Boolean cleanCache) throws Exception {
437 if (isCacheFilters() && cacheService.getFilters().containsKey(src.getClass().getName())) {
438 getLogger().warn("Found registered filter - using instead of default view filter for class:"
439 + src.getClass().getName());
440 SimpleFilterProvider filter = (SimpleFilterProvider) cacheService.getFilters()
441 .get(src.getClass().getName());
442 return ser(src, filter, cleanCache);
443 }
444 String res = mapper.writerWithView(Object.class).writeValueAsString(src);
445 if (cleanCache != null && cleanCache) {
446 cacheService.cleanSerializerCache(mapper);
447 }
448 return res;
449 }
450
451 @Override
452 public <T> String ser(Object src, Class<T> type, Boolean cleanCache) throws Exception {
453 getLogger().info("serializing object:" + src + " for type " + type);
454 if (isCacheFilters() && src != null && cacheService.getFilters().containsKey(src.getClass().getName())) {
455 getLogger().warn("Found registered filter - could not use custom view and custom filter for class:"
456 + src.getClass().getName());
457
458
459
460
461 SimpleFilterProvider filter = (SimpleFilterProvider) cacheService.getFilters()
462 .get(src.getClass().getName());
463 return ser(src, filter);
464 }
465
466 String res = (type != null) ? mapper.writerWithView(type).writeValueAsString(src)
467 : mapper.writeValueAsString(src);
468 if (cleanCache) {
469 cacheService.cleanSerializerCache(mapper);
470 }
471 return res;
472 }
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491 private <T> String filter(Object src, Class<?>[] filterClasses, Class<T>[] excludeClasses, PropertyFilter pf,
492 Boolean clean) throws Exception {
493 FilterProvider filter = null;
494 if (filterClasses.length > 0) {
495 filter = retrieveFilter(pf, filterClasses[0], excludeClasses);
496 }
497 getLogger().info("filtering with filter " + filter);
498 String serialized = ser(src, filter, clean);
499 if (!isCacheFilters() || clean) {
500 if (filterClasses.length > 0) {
501 boolean exclude = (excludeClasses != null) ? true : false;
502 cacheService.removeFilter(filterClasses[0], exclude);
503 }
504 }
505 return serialized;
506 }
507
508 private <T> SimpleFilterProvider retrieveFilter(PropertyFilter pf, Class<?> filterClass,
509 Class<T>[] excludeClasses) {
510 SimpleFilterProvider filter = null;
511 if (pf != null) {
512 filter = new SimpleFilterProvider();
513 filter.setDefaultFilter(pf);
514 }
515 if (isCacheFilters()) {
516 if (!cacheService.getFilters().containsKey(filterClass.getName())) {
517 getLogger().debug("add filter for cache filter Class " + filterClass.getName());
518 setCustomIntrospectorWithExternalFilterId(filterClass, excludeClasses);
519 if (pf != null) {
520 cacheService.getFilters().put(filterClass.getName(), filter);
521 }
522 } else {
523 filter = (SimpleFilterProvider) cacheService.getFilters().get(filterClass.getName());
524
525
526 }
527 }
528 getLogger().debug("set filter:" + filter);
529 return filter;
530 }
531
532
533
534
535
536
537
538
539
540
541
542 private <T> void setCustomIntrospectorWithExternalFilterId(Class<?> filterClass,
543 Class<T>[] externalFilterClassIds) {
544 if (primary instanceof SimpleNameIntrospector) {
545
546 ((SimpleNameIntrospector) primary).setFilteredClasses(filterClass);
547 if (externalFilterClassIds != null) {
548 ((SimpleNameIntrospector) primary).setIsExludeType(true);
549 for (Class<T> filterClazz : externalFilterClassIds) {
550 getLogger().debug("added class for filters " + filterClazz);
551 }
552 ((SimpleNameIntrospector) primary).setExternalFilterExcludeClasses(externalFilterClassIds);
553 }
554 }
555 }
556
557 public Jackson2MapperService registerModule(Module module) {
558 mapper.registerModule(module);
559 return this;
560 }
561
562 public <T> void addSimpleModule(SimpleModule module, Class<T> type, JsonSerializer<T> ser) {
563 module.addSerializer(type, ser);
564 }
565
566 public <T> void addSimpleModule(SimpleModule module, Class<T> type, JsonDeserializer<T> deSer) {
567 module.addDeserializer(type, deSer);
568 }
569
570
571
572
573 @Override
574 public void setDateFormat(final DateFormat df) {
575 mapper.setDateFormat(df);
576 }
577
578
579
580
581 @Override
582 public void configure(Configuration conf) throws ConfigurationException {
583 getLogger().debug("conf.getName()" + conf.getName());
584 this.annotationInspectors = new HashMap<>();
585
586 final Configuration configuredAnnotationInspectors = conf.getChild(ANNOTATIONINSPECTOR, false);
587
588 if (configuredAnnotationInspectors != null) {
589 Configuration[] nameVal = configuredAnnotationInspectors.getChildren();
590 Arrays.stream( nameVal).forEach(c->
591 {
592 String key = c.getName();
593 getLogger().debug("configured key: " + key);
594 if (key.equals("features")) {
595 this.features = new HashMap<>();
596 this.featureTypes = new HashMap<>();
597 Arrays.stream( c.getChildren() ).forEach( lf -> {
598 boolean featureValue = lf.getAttributeAsBoolean("value", false);
599 String featureType = null;
600 String feature = null;
601 try {
602 featureType = lf.getAttribute("type");
603 feature = lf.getValue();
604 getLogger().debug("configuredAnnotationInspectors " + feature + ":" + featureValue);
605 this.features.put(feature, featureValue);
606 this.featureTypes.put(feature, featureType);
607 } catch (ConfigurationException e) {
608 throw new RuntimeException(e);
609 }
610 });
611 } else {
612 String val;
613 try {
614 val = c.getValue();
615 getLogger().debug("configuredAnnotationInspectors " + key + ":" + val);
616 this.annotationInspectors.put(key, val);
617 } catch (ConfigurationException e) {
618 throw new RuntimeException(e);
619 }
620
621 }
622 });
623 }
624 final Configuration configuredDateFormat = conf.getChild(DATE_FORMAT, true);
625 this.dateFormat = configuredDateFormat.getValue(DEFAULTDATEFORMAT);
626
627 final Configuration configuredKeepFilter = conf.getChild(CACHE_FILTERS, false);
628 if (configuredKeepFilter != null) {
629 setCacheFilters( configuredKeepFilter.getValueAsBoolean());
630 }
631 final Configuration configuredEscapeChars = conf.getChild(ESCAPE_CHARS, false);
632 if (configuredEscapeChars != null) {
633 this.escapeCharsGlobal = configuredEscapeChars.getValueAsBoolean();
634 }
635 final Configuration configuredEscapeCharClass = conf.getChild(ESCAPE_CHAR_CLASS, false);
636 if (configuredEscapeCharClass != null) {
637 this.escapeCharsClass = configuredEscapeCharClass.getValue();
638 }
639
640 final Configuration configuredDefaultType = conf.getChild(DEFAULT_TYPING, false);
641 if (configuredDefaultType != null) {
642 defaultTypeDefs = new String[] { configuredDefaultType.getAttribute("type"),
643 configuredDefaultType.getAttribute("key") };
644 }
645 final Configuration configuredjsonPath = conf.getChild(USE_JSON_PATH, false);
646 if (configuredjsonPath != null) {
647 this.useJsonPath = configuredjsonPath.getValueAsBoolean();
648 }
649 }
650
651 @Override
652 public void initialize() throws Exception {
653 mapper = new ObjectMapper(null, null, null);
654
655 initAnnotationInspectors();
656
657 initFeatures();
658
659 initDefaultTyping();
660
661 getLogger().info("setting date format to:" + dateFormat);
662 getLogger().info("cacheFilters is:" + isCacheFilters());
663 if (!isCacheFilters()) {
664 mapper.configure(SerializationFeature.FLUSH_AFTER_WRITE_VALUE, true);
665 }
666
667 mapper.setDateFormat(new SimpleDateFormat(dateFormat));
668
669 if (escapeCharsGlobal) {
670 mapper.getFactory().setCharacterEscapes(characterEscapes);
671 }
672 if (escapeCharsClass != null) {
673 try {
674 characterEscapes = (CharacterEscapes) Class.forName(escapeCharsClass).getConstructor().newInstance();
675 } catch (Exception e) {
676 throw new InstantiationException(
677 "JsonMapperService: Error instantiating " + escapeCharsClass + " for " + ESCAPE_CHAR_CLASS);
678 }
679 }
680
681 getLogger().debug("initialized mapper:" + mapper);
682
683 mapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() {
684 @Override
685 public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
686 jgen.writeString("");
687
688 }
689 });
690 cacheService = new CacheService(primary);
691 if (cacheService instanceof LogEnabled) {
692 cacheService.enableLogging(getLogger().getChildLogger(cacheService.getClass().getSimpleName()));
693 getLogger().info("setting cacheService logger: " + cacheService.getClass().getSimpleName());
694 }
695
696 if (useJsonPath) {
697
698 DefaultJsonPathWrapper djpw = null;
699 try {
700 djpw = new DefaultJsonPathWrapper(this.mapper);
701 getLogger().debug("******** initialized new jsonPath defaults: " + djpw.getJsonPathDefault());
702 } catch (Exception e) {
703 throw new AssertionError(
704 "JsonMapperService: Error instantiating " + djpw + " using useJsonPath=" + useJsonPath);
705 }
706
707 }
708 }
709
710 private void initDefaultTyping() {
711 if (defaultTypeDefs != null && defaultTypeDefs.length == 2) {
712 DefaultTyping defaultTyping = DefaultTyping.valueOf(defaultTypeDefs[0]);
713 mapper.enableDefaultTypingAsProperty(defaultTyping, defaultTypeDefs[1]);
714 getLogger().info("default typing is " + defaultTypeDefs[0] + " with key:" + defaultTypeDefs[1]);
715 }
716 }
717
718 private void initFeatures() throws Exception {
719 if (features != null && !features.isEmpty()) {
720 features.entrySet().stream().forEach( entry -> {
721 String featureKey = entry.getKey();
722 Boolean featureValue = entry.getValue();
723 String featureType = featureTypes.get(featureKey);
724 Class<?> configFeature = null;
725 try {
726 getLogger().debug("initializing featureType: " + featureType);
727 configFeature = loadClass(featureType);
728 } catch (ClassNotFoundException e) {
729 throw new AssertionError("JsonMapperService: Error instantiating " + featureType + " for " + featureKey, e);
730 }
731 ConfigFeature feature = null;
732 if (!StringUtils.isEmpty(featureKey) && featureValue != null) {
733 try
734 {
735 if (configFeature.equals(SerializationFeature.class)) {
736 feature = SerializationFeature.valueOf(featureKey);
737 mapper.configure((SerializationFeature) feature, featureValue);
738 assert mapper.getSerializationConfig()
739 .isEnabled((SerializationFeature) feature) == featureValue;
740 getLogger().info("initialized serconfig mapper feature: " + feature + " with "
741 + mapper.getSerializationConfig().isEnabled((SerializationFeature) feature));
742 } else if (configFeature.equals(DeserializationFeature.class)) {
743 feature = DeserializationFeature.valueOf(featureKey);
744 mapper.configure((DeserializationFeature) feature, featureValue);
745 assert mapper.getDeserializationConfig()
746 .isEnabled((DeserializationFeature) feature) == featureValue;
747 getLogger().info("initialized deserconfig mapper feature: " + feature + " with "
748 + mapper.getDeserializationConfig().isEnabled((DeserializationFeature) feature));
749 } else if (configFeature.equals(MapperFeature.class)) {
750 feature = MapperFeature.valueOf(featureKey);
751 mapper.configure((MapperFeature) feature, featureValue);
752 assert mapper.getDeserializationConfig().isEnabled((MapperFeature) feature) == featureValue;
753 assert mapper.getSerializationConfig().isEnabled((MapperFeature) feature) == featureValue;
754 getLogger().info("initialized serconfig mapper feature: " + feature + " with "
755 + mapper.getDeserializationConfig().isEnabled((MapperFeature) feature));
756 getLogger().info("initialized deserconfig mapper feature: " + feature + " with "
757 + mapper.getSerializationConfig().isEnabled((MapperFeature) feature));
758 } else if (configFeature.equals(JsonParser.class)) {
759 Feature parserFeature = JsonParser.Feature.valueOf(featureKey);
760 getLogger().info("initializing parser feature: " + parserFeature + " with " + featureValue);
761 mapper.configure(parserFeature, featureValue);
762 } else if (configFeature.equals(JsonGenerator.class)) {
763 com.fasterxml.jackson.core.JsonGenerator.Feature genFeature = JsonGenerator.Feature
764 .valueOf(featureKey);
765 getLogger().info("initializing parser feature: " + genFeature + " with " + featureValue);
766 mapper.configure(genFeature, featureValue);
767 }
768 } catch (Exception e) {
769 throw new RuntimeException("JsonMapperService: Error instantiating feature " + featureKey + " with "
770 + featureValue , e);
771 }
772
773 }
774 });
775 }
776 }
777
778 private void initAnnotationInspectors() throws Exception {
779 for (Entry<String, String> entry : annotationInspectors.entrySet()) {
780 String key = entry.getKey();
781 String avClass = entry.getValue();
782 if (key.equals("primary") && !StringUtils.isEmpty(avClass)) {
783 try {
784 primary = (AnnotationIntrospector) Class.forName(avClass).getConstructor().newInstance();
785 } catch (Exception e) {
786 throw new InstantiationException("JsonMapperService: Error instantiating " + avClass + " for " + key);
787 }
788 } else if (key.equals("secondary") && avClass != null) {
789 try {
790 secondary = (AnnotationIntrospector) Class.forName(avClass).getConstructor().newInstance();
791 } catch (Exception e) {
792 throw new InstantiationException("JsonMapperService: Error instantiating " + avClass + " for " + key);
793 }
794 }
795 }
796 if (primary == null) {
797 primary = new JacksonAnnotationIntrospector();
798 getLogger().info("using default introspector:" + primary.getClass().getName());
799 mapper.setAnnotationIntrospector(primary);
800 } else if (primary != null && secondary != null) {
801 AnnotationIntrospector pair = new AnnotationIntrospectorPair(primary, secondary);
802 mapper.setAnnotationIntrospector(pair);
803 } else {
804 mapper.setAnnotationIntrospector(primary);
805 }
806
807 if (primary instanceof LogEnabled) {
808 ((LogEnabled) primary).enableLogging(getLogger().getChildLogger(primary.getClass().getSimpleName()));
809 getLogger().info("setting primary introspector logger: " + primary.getClass().getSimpleName());
810 }
811 if (secondary instanceof LogEnabled) {
812 ((LogEnabled) secondary).enableLogging(getLogger().getChildLogger(secondary.getClass().getSimpleName()));
813 getLogger().info("setting secondary introspector logger: " + secondary.getClass().getSimpleName());
814 }
815 }
816
817
818
819
820
821
822
823
824 @SuppressWarnings("unchecked")
825 protected <T> Class<T> loadClass(String className) throws ClassNotFoundException {
826 ClassLoader loader = this.getClass().getClassLoader();
827 try {
828 Class<T> clazz;
829
830 if (loader != null) {
831 clazz = (Class<T>) loader.loadClass(className);
832 } else {
833 clazz = (Class<T>) Class.forName(className);
834 }
835
836 return clazz;
837 } catch (ClassNotFoundException x) {
838
839 throw x;
840 }
841 }
842
843 public ObjectMapper getMapper() {
844 return mapper;
845 }
846
847 public void setMapper(ObjectMapper mapper) {
848 this.mapper = mapper;
849 }
850
851 public boolean isCacheFilters() {
852 return cacheFilters;
853 }
854
855 public void setCacheFilters(boolean cacheFilters) {
856 this.cacheFilters = cacheFilters;
857 if (!cacheFilters)
858 mapper.configure(SerializationFeature.FLUSH_AFTER_WRITE_VALUE, true);
859 }
860
861 static CharacterEscapes characterEscapes = new CharacterEscapes() {
862 private static final long serialVersionUID = 1L;
863 private final int[] asciiEscapes;
864 {
865 int[] esc = standardAsciiEscapesForJSON();
866
867 esc['<'] = CharacterEscapes.ESCAPE_STANDARD;
868 esc['>'] = CharacterEscapes.ESCAPE_STANDARD;
869 esc['&'] = CharacterEscapes.ESCAPE_STANDARD;
870 esc['\''] = CharacterEscapes.ESCAPE_STANDARD;
871
872 asciiEscapes = esc;
873 }
874
875 @Override
876 public int[] getEscapeCodesForAscii() {
877 return asciiEscapes;
878 }
879
880 @Override
881 public SerializableString getEscapeSequence(final int ch) {
882
883
884
885 return null;
886
887 }
888 };
889 }