Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.apache.fulcrum.json.jackson.Jackson2MapperService Maven / Gradle / Ivy
package org.apache.fulcrum.json.jackson;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Hashtable;
import org.apache.avalon.framework.activity.Initializable;
import org.apache.avalon.framework.configuration.Configurable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.logger.AbstractLogEnabled;
import org.apache.avalon.framework.logger.LogEnabled;
import org.apache.fulcrum.json.JsonService;
import org.apache.fulcrum.json.jackson.filters.CustomModuleWrapper;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonParser.Feature;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.AnnotationIntrospector;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectMapper.DefaultTyping;
import com.fasterxml.jackson.databind.ObjectReader;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.cfg.ConfigFeature;
import com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair;
import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.FilterProvider;
import com.fasterxml.jackson.databind.ser.PropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
/**
*
*
* By default multiple serialization of the same object in a single thread is
* not supported (e.g filter + mixin or default + filter for the same bean /
* object).
*
* By default a filter is defined by its {@link Class#getName()}.
*
* Note: If using {@link SimpleNameIntrospector}, filter caches are set by class id. Caching is enabled by default, if not (a) by setting {@link #cacheFilters} to false
.
* By setting (b) the Boolean parameter clean {@link #serializeAllExceptFilter(Object, Class, Boolean, String...)} or {@link #serializeOnlyFilter(Object, Class, Boolean, String...)}
* you could clean the filter. If caching is disabled each filter will be unregistered and the cache cleaned.
*
* @author Georg Kallidis
* @version $Id: Jackson2MapperService.java 1685062 2015-06-12 10:57:08Z gk $
*
*/
public class Jackson2MapperService extends AbstractLogEnabled implements
JsonService, Initializable, Configurable {
private static final String DEFAULT_TYPING = "defaultTyping";
private static final String CACHE_FILTERS = "cacheFilters";
private static final String DATE_FORMAT = "dateFormat";
ObjectMapper mapper;
AnnotationIntrospector primary; // support default
AnnotationIntrospector secondary;
public String ANNOTATIONINSPECTOR = "annotationInspectors";
private Hashtable annotationInspectors = null;
private Hashtable features = null;
private Hashtable featureTypes = null;
private String dateFormat;
/**
* Default dateformat is MM/dd/yyyy
, could be overwritten in {@link #setDateFormat(DateFormat)}.
*/
public final String DEFAULTDATEFORMAT = "MM/dd/yyyy";
final boolean defaultType = false;
public boolean cacheFilters = true; // true -> this is by default true in jackson, if not using
// multiple serialization in one thread
String[] defaultTypeDefs = null;
private CacheService cacheService;
@Override
public String ser(Object src) throws Exception {
return ser(src, false);
}
@Override
public String ser(Object src, Class type) throws Exception {
return ser(src, type, false);
}
public String ser(Object src, FilterProvider filter) throws Exception {
return ser(src, filter, false);
}
public String ser(Object src, FilterProvider filter, Boolean cleanCache) throws Exception {
String serResult= null;
if (src == null) {
getLogger().info("no serializable object.");
return serResult;
}
if (filter == null) {
getLogger().debug("ser class::" + src.getClass() + " without filter.");
return ser(src);
}
getLogger().debug("ser class::" + src.getClass() + " with filter " + filter);
mapper.setFilters(filter);
String res = mapper.writer(filter).writeValueAsString(src);
if (cleanCache) {
cacheService.cleanSerializerCache(mapper);
}
return res;
}
@Override
public T deSer(String json, Class type) throws Exception {
ObjectReader reader = null;
if (type != null)
reader = mapper.reader(type);
else
reader = mapper.reader();
return reader.readValue(json);
}
public Collection deSerCollectionWithType(String json, Class extends Collection> collectionClass, Class type)
throws Exception {
return mapper.readValue(json, mapper.getTypeFactory()
.constructCollectionType(collectionClass, type));
}
public String serCollectionWithTypeReference(Collection src, TypeReference collectionType, Boolean cleanCache)
throws Exception {
String res = mapper.writerWithType(collectionType).writeValueAsString(src);
if (cleanCache) {
cacheService.cleanSerializerCache(mapper);
}
return res;
}
@Override
public Collection deSerCollection(String json,
Object collectionType, Class elementType) throws Exception {
if (collectionType instanceof TypeReference) {
return mapper.readValue(json, (TypeReference)collectionType);
} else {
return mapper.readValue(json, mapper.getTypeFactory()
.constructCollectionType(((Collection)collectionType).getClass(), elementType));
}
}
public Collection deSerCollectionWithTypeReference(String json,
TypeReference collectionType ) throws Exception {
return mapper.readValue(json, collectionType);
}
public void getJsonService() throws InstantiationException {
}
/**
* @param name name of the module
* @param target target class
* @param mixin provide mixin as class.
* Deregistering module could be only done by setting this parameter to null.
*
* @see #addAdapter(String, Class, Object)
*/
@Override
public JsonService addAdapter(String name, Class target, Class mixin)
throws Exception {
Module mx = new MixinModule(name, target, mixin);
getLogger().debug("registering unversioned simple mixin module named " + name + " of type " + mixin + " for: " + target);
mapper.registerModule(mx);
return this;
}
/**
* Add a named module
*
* @param name Name of the module
*
* @param target Target class
*
* @param module
* Either an Jackson Module @link {@link Module} or an custom
* wrapper @link CustomModuleWrapper.
*
* @see JsonService#addAdapter(String, Class, Object)
*/
@Override
public JsonService addAdapter(String name, Class target, Object module)
throws Exception {
if (module instanceof CustomModuleWrapper) {
CustomModuleWrapper cmw = (CustomModuleWrapper) module;
Module cm = new CustomModule(name, target, cmw.getSer(),
cmw.getDeSer());
getLogger().debug("registering custom module " + cm + " for: " + target);
mapper.registerModule(cm);
} else if (module instanceof Module) {
getLogger().debug(
"registering module " + module + " for: " + target);
mapper.registerModule((Module) module);
} else {
throw new Exception("expecting module type" + Module.class);
}
return this;
}
@SuppressWarnings("rawtypes")
public String withMixinModule(Object src, String name, Class target,
Class mixin) throws JsonProcessingException {
Module mx = new MixinModule(name, target, mixin);
getLogger().debug("registering module " + mx + " for: " + mixin);
return mapper.registerModule(mx).writer().writeValueAsString(src);
}
@Override
public String serializeAllExceptFilter(Object src, String... filterAttr)
throws Exception {
return serializeAllExceptFilter(src, src.getClass(), true, filterAttr);
}
public synchronized String serializeAllExceptFilter(Object src, Boolean cache, String... filterAttr) throws Exception {
return serializeAllExceptFilter(src, src.getClass(), cache, filterAttr);
}
public synchronized String serializeAllExceptFilter(Object src,
Class[] filterClasses, String... filterAttr) throws Exception {
return serializeAllExceptFilter(src, filterClasses, true, filterAttr);
}
@Override
public synchronized String serializeAllExceptFilter(Object src,
Class filterClass, String... filterAttr) throws Exception {
return serializeAllExceptFilter(src, filterClass, true, filterAttr);
}
@Override
public String serializeAllExceptFilter(Object src,
Class filterClass, Boolean cleanFilter, String... filterAttr)
throws Exception {
return serializeAllExceptFilter(src, new Class[] {filterClass}, cleanFilter, filterAttr);
}
public synchronized String serializeAllExceptFilter(Object src,
Class[] filterClasses, Boolean clean, String... filterAttr) throws Exception {
PropertyFilter pf = null;
if (filterAttr != null)
pf = SimpleBeanPropertyFilter.serializeAllExcept(filterAttr);
else if (filterClasses == null) //no filter
return ser(src, clean);
return filter(src, new Class>[] { src.getClass() }, filterClasses, pf, clean);
}
@Override
public String serializeOnlyFilter(Object src, String... filterAttrs)
throws Exception {
return serializeOnlyFilter(src, src.getClass(), true, filterAttrs);
}
public synchronized String serializeOnlyFilter(Object src,
Boolean cache, String... filterAttr) throws Exception {
return serializeOnlyFilter(src, src.getClass(), cache, filterAttr);
}
@Override
public synchronized String serializeOnlyFilter(Object src,
Class filterClass, String... filterAttr) throws Exception {
return serializeOnlyFilter(src, filterClass, true, filterAttr);
}
@Override
public synchronized String serializeOnlyFilter(Object src,
Class filterClass, Boolean refresh, String... filterAttr) throws Exception {
return serializeOnlyFilter(src, new Class[]{ filterClass }, refresh, filterAttr);
}
public synchronized String serializeOnlyFilter(Object src,
Class[] filterClasses, Boolean refresh, String... filterAttr) throws Exception {
PropertyFilter pf = null;
if (filterAttr != null && filterAttr.length > 0 && filterAttr[0] != "") {
pf = SimpleBeanPropertyFilter.filterOutAllExcept(filterAttr);
getLogger().debug("setting filteroutAllexcept filter for size of filterAttr: " + filterAttr.length);
} else {
getLogger().warn("no filter attributes set!");
pf = SimpleBeanPropertyFilter.filterOutAllExcept("dummy");
}
if (filterClasses == null) throw new Exception("You have to provide some class to apply the filtering!");
return filter(src, filterClasses, null, pf, refresh);
}
@Override
public String ser(Object src, Boolean cleanCache) throws Exception {
if (cacheService.getFilters().containsKey(src.getClass().getName())) {
getLogger().warn(
"Found registered filter - using instead of default view filter for class:"
+ src.getClass().getName());
// throw new
// Exception("Found registered filter - could not use custom view and custom filter for class:"+
// src.getClass().getName());
SimpleFilterProvider filter = (SimpleFilterProvider) cacheService.getFilters().get(src.getClass()
.getName());
return ser(src, filter, cleanCache);//mapper.writerWithView(src.getClass()).writeValueAsString(src);
}
String res = mapper.writerWithView(Object.class).writeValueAsString(src);
if (cleanCache != null && cleanCache) {
cacheService.cleanSerializerCache(mapper);
}
return res;
}
@Override
public String ser(Object src, Class type, Boolean cleanCache)
throws Exception {
getLogger().info("serializing object:" + src + " for type "+ type);
if (src != null && cacheService.getFilters().containsKey(src.getClass().getName())) {
getLogger()
.warn("Found registered filter - could not use custom view and custom filter for class:"
+ src.getClass().getName());
// throw new
// Exception("Found registered filter - could not use custom view and custom filter for class:"+
// src.getClass().getName());
SimpleFilterProvider filter = (SimpleFilterProvider) cacheService.getFilters().get(src.getClass()
.getName());
return ser(src, filter);
}
String res = (type != null)? mapper.writerWithView(type).writeValueAsString(src): mapper.writeValueAsString(src);
if (cleanCache) {
cacheService.cleanSerializerCache(mapper);
}
return res;
}
/**
*
* @param src The source Object to be filtered.
* @param filterClass This Class array contains at least one element. If no class is provided it is the class type of the source object.
* The filterClass is to become the key of the filter object cache.
* @param excludeClasses The classes to be excluded, optionally used onlz for methods like {@link #serializeAllExceptFilter(Object, Class[], String...)}.
* @param pf Expecting a property filter from e.g @link {@link SimpleBeanPropertyFilter}.
* @param clean if true
does not reuse the filter object (no cashing).
* @return The serialized Object as String
* @throws Exception
*/
private String filter(Object src, Class>[] filterClasses, Class[] excludeClasses,
PropertyFilter pf, Boolean clean) throws Exception {
FilterProvider filter = null;
if (filterClasses.length >0) {
filter = retrieveFilter(pf, filterClasses[0], excludeClasses);
}
getLogger().info("filtering with filter "+ filter);
String serialized = ser(src, filter, clean);
if (!cacheFilters || clean) {
if (filterClasses.length >0) {
boolean exclude = (excludeClasses !=null)? true:false;
cacheService.removeFilter(filterClasses[0],exclude);
}
}
return serialized;
}
private SimpleFilterProvider retrieveFilter(PropertyFilter pf, Class> filterClass,
Class[] excludeClasses ) {
SimpleFilterProvider filter = null;
if (pf != null) {
filter = new SimpleFilterProvider();
filter.setDefaultFilter(pf);
}
if (!cacheService.getFilters().containsKey(filterClass.getName())) {
getLogger().debug("add filter for cache filter Class " + filterClass.getName());
setCustomIntrospectorWithExternalFilterId(filterClass, excludeClasses); // filter class
if (pf != null) {
cacheService.getFilters().put(filterClass.getName(), (FilterProvider) filter);
}
} else {
filter = (SimpleFilterProvider)cacheService.getFilters().get(filterClass
.getName());
//setCustomIntrospectorWithExternalFilterId(filterClass); // filter
// class
}
getLogger().debug("set filter:"+ filter);
return filter;
}
/**
* @param filterClass Adding filterClass into {@link SimpleNameIntrospector#setFilteredClass(Class)} enables the filtering process.
* @param externalFilterIds Adding externalFilterIs to {@link SimpleNameIntrospector#setExternalFilterExcludeClasses(Class...)} excludes these classes.
*/
private void setCustomIntrospectorWithExternalFilterId(Class> filterClass,
Class[] externalFilterClassIds) {
if (primary instanceof SimpleNameIntrospector) {
// first one is required that we get to the PropertyFilter
((SimpleNameIntrospector) primary).setFilteredClasses(filterClass);
if (externalFilterClassIds != null) {
((SimpleNameIntrospector) primary).setIsExludeType(true);
for (Class filterClazz : externalFilterClassIds) {
getLogger().debug("added class for filters "
+ filterClazz);
}
((SimpleNameIntrospector) primary).setExternalFilterExcludeClasses(externalFilterClassIds);
getLogger().debug("added exclude class(es) for filters " + externalFilterClassIds);
}
}
}
public Jackson2MapperService registerModule(Module module) {
mapper.registerModule(module);
return this;
}
public void addSimpleModule(SimpleModule module, Class type,
JsonSerializer ser) {
module.addSerializer(type, ser);
}
public void addSimpleModule(SimpleModule module, Class type,
JsonDeserializer deSer) {
module.addDeserializer(type, deSer);
}
/**
* Default Dateformat: {@link #DEFAULTDATEFORMAT}
*/
@Override
public void setDateFormat(final DateFormat df) {
mapper.setDateFormat(df);
}
/**
* Avalon component lifecycle method
*/
@Override
public void configure(Configuration conf) throws ConfigurationException {
getLogger().debug("conf.getName()" + conf.getName());
this.annotationInspectors = new Hashtable();
final Configuration configuredAnnotationInspectors = conf.getChild(
ANNOTATIONINSPECTOR, false);
if (configuredAnnotationInspectors != null) {
Configuration[] nameVal = configuredAnnotationInspectors
.getChildren();
for (int i = 0; i < nameVal.length; i++) {
String key = nameVal[i].getName();
getLogger().debug("configured key: " + key);
if (key.equals("features")) {
this.features = new Hashtable();
this.featureTypes = new Hashtable();
Configuration[] features = nameVal[i].getChildren();
for (int j = 0; j < features.length; j++) {
boolean featureValue = features[j]
.getAttributeAsBoolean("value", false);
String featureType = features[j].getAttribute("type");
String feature = features[j].getValue();
getLogger().debug(
"configuredAnnotationInspectors " + feature
+ ":" + featureValue);
this.features.put(feature, featureValue);
this.featureTypes.put(feature, featureType);
}
} else {
String val = nameVal[i].getValue();
getLogger()
.debug("configuredAnnotationInspectors " + key
+ ":" + val);
this.annotationInspectors.put(key, val);
}
}
}
final Configuration configuredDateFormat = conf.getChild(DATE_FORMAT,
true);
this.dateFormat = configuredDateFormat.getValue(DEFAULTDATEFORMAT);
final Configuration configuredKeepFilter = conf.getChild(CACHE_FILTERS,
false);
if (configuredKeepFilter != null) {
this.cacheFilters = configuredKeepFilter.getValueAsBoolean();
}
final Configuration configuredDefaultType = conf.getChild(
DEFAULT_TYPING, false);
if (configuredDefaultType != null) {
defaultTypeDefs = new String[] {
configuredDefaultType.getAttribute("type"),
configuredDefaultType.getAttribute("key") };
}
}
@Override
public void initialize() throws Exception {
mapper = new ObjectMapper(null, null, null);// add configurable JsonFactory,.. later?
Enumeration enumKey = annotationInspectors.keys();
while (enumKey.hasMoreElements()) {
String key = enumKey.nextElement();
String avClass = annotationInspectors.get(key);
if (key.equals("primary") && avClass != null) {
try {
primary = (AnnotationIntrospector) Class.forName(avClass).getConstructor()
.newInstance();
} catch (Exception e) {
throw new Exception(
"JsonMapperService: Error instantiating " + avClass
+ " for " + key);
}
} else if (key.equals("secondary") && avClass != null) {
try {
secondary = (AnnotationIntrospector) Class.forName(avClass).getConstructor()
.newInstance();
} catch (Exception e) {
throw new Exception(
"JsonMapperService: Error instantiating " + avClass
+ " for " + key);
}
}
}
if (primary == null) {
primary = new JacksonAnnotationIntrospector(); // support default
getLogger().info(
"using default introspector:"
+ primary.getClass().getName());
mapper.setAnnotationIntrospector(primary);
} else if (primary != null && secondary != null){
AnnotationIntrospector pair = new AnnotationIntrospectorPair(
primary, secondary);
mapper.setAnnotationIntrospector(pair);
} else {
mapper.setAnnotationIntrospector(primary);
}
if (primary instanceof LogEnabled)
{
((LogEnabled)primary).enableLogging(getLogger().getChildLogger(primary.getClass().getSimpleName()));
getLogger().info(
"setting primary introspector logger: "
+ primary.getClass().getSimpleName());
}
if (secondary instanceof LogEnabled)
{
((LogEnabled)secondary).enableLogging(getLogger().getChildLogger(secondary.getClass().getSimpleName()));
getLogger().info(
"setting secondary introspector logger: "
+ secondary.getClass().getSimpleName());
}
if (features != null) {
Enumeration enumFeatureKey = features.keys();
while (enumFeatureKey.hasMoreElements()) {
String featureKey = enumFeatureKey.nextElement();// e.g.
// FAIL_ON_EMPTY_BEANS
Boolean featureValue = features.get(featureKey); // e.g.false
String featureType = featureTypes.get(featureKey);
Class> configFeature = null;
try {
getLogger().debug(
"initializing featureType: " + featureType);
configFeature = Class.forName(featureType);
} catch (Exception e) {
throw new Exception(
"JsonMapperService: Error instantiating "
+ featureType + " for " + featureKey,e);
}
ConfigFeature feature = null;
if (featureKey != null && featureValue != null) {
try {
if (configFeature.equals(SerializationFeature.class)) {
feature = SerializationFeature.valueOf(featureKey);
mapper.configure((SerializationFeature) feature,
featureValue);
assert mapper.getSerializationConfig().isEnabled(
(SerializationFeature) feature) == featureValue;
getLogger()
.info("initialized serconfig mapper feature: "
+ feature
+ " with "
+ mapper.getSerializationConfig()
.isEnabled(
(SerializationFeature) feature));
} else if (configFeature
.equals(DeserializationFeature.class)) {
feature = DeserializationFeature
.valueOf(featureKey);
mapper.configure((DeserializationFeature) feature,
featureValue);
assert mapper.getDeserializationConfig().isEnabled(
(DeserializationFeature) feature) == featureValue;
getLogger()
.info("initialized deserconfig mapper feature: "
+ feature
+ " with "
+ mapper.getDeserializationConfig()
.isEnabled(
(DeserializationFeature) feature));
} else if (configFeature.equals(MapperFeature.class)) {
feature = MapperFeature.valueOf(featureKey);
mapper.configure((MapperFeature) feature,
featureValue);
assert mapper.getDeserializationConfig().isEnabled(
(MapperFeature) feature) == featureValue;
assert mapper.getSerializationConfig().isEnabled(
(MapperFeature) feature) == featureValue;
getLogger()
.info("initialized serconfig mapper feature: "
+ feature
+ " with "
+ mapper.getDeserializationConfig()
.isEnabled(
(MapperFeature) feature));
getLogger()
.info("initialized deserconfig mapper feature: "
+ feature
+ " with "
+ mapper.getSerializationConfig()
.isEnabled(
(MapperFeature) feature));
} else if (configFeature.equals(JsonParser.class)) {
Feature parserFeature = JsonParser.Feature.valueOf(featureKey);
getLogger()
.info("initializing parser feature: "
+ parserFeature
+ " with "
+ featureValue);
mapper.configure(parserFeature,
featureValue);
} else if (configFeature.equals(JsonGenerator.class)) {
com.fasterxml.jackson.core.JsonGenerator.Feature genFeature = JsonGenerator.Feature.valueOf(featureKey);
getLogger()
.info("initializing parser feature: "
+ genFeature
+ " with "
+ featureValue);
mapper.configure(genFeature,
featureValue);
}
} catch (Exception e) {
throw new Exception(
"JsonMapperService: Error instantiating feature "
+ featureKey + " with " + featureValue,
e);
}
}
}
}
if (defaultTypeDefs != null && defaultTypeDefs.length == 2) {
DefaultTyping defaultTyping = DefaultTyping
.valueOf(defaultTypeDefs[0]);
mapper.enableDefaultTypingAsProperty(defaultTyping,
defaultTypeDefs[1]);
getLogger().info(
"default typing is " + defaultTypeDefs[0] + " with key:"
+ defaultTypeDefs[1]);
}
getLogger().info("setting date format to:" + dateFormat);
getLogger().info("cacheFilters is:" + cacheFilters);
if (!cacheFilters) {
mapper.configure(SerializationFeature.FLUSH_AFTER_WRITE_VALUE, true);
}
mapper.setDateFormat(new SimpleDateFormat(dateFormat));
getLogger().debug("initialized mapper:" + mapper);
mapper.getSerializerProvider().setNullValueSerializer(
new JsonSerializer() {
@Override
public void serialize(Object value, JsonGenerator jgen,
SerializerProvider provider) throws IOException,
JsonProcessingException {
jgen.writeString("");
}
});
cacheService = new CacheService(primary);
if (cacheService instanceof LogEnabled)
{
((LogEnabled)cacheService).enableLogging(getLogger().getChildLogger(cacheService.getClass().getSimpleName()));
getLogger().info(
"setting cacheService logger: "
+ cacheService.getClass().getSimpleName());
}
}
public ObjectMapper getMapper() {
return mapper;
}
public void setMapper(ObjectMapper mapper) {
this.mapper = mapper;
}
public boolean isCacheFilters() {
return cacheFilters;
}
public void setCacheFilters(boolean cacheFilters) {
this.cacheFilters = cacheFilters;
if (!cacheFilters)
mapper.configure(SerializationFeature.FLUSH_AFTER_WRITE_VALUE, true);
}
}