之前写过一篇博客《jackson:基于BeanDeserializer实现自定义的Java bean 解析器》,介绍了如何继承com.fasterxml.jackson.databind.deser.BeanDeserializer
实现自定义的反序列化器。
如果要实现继承BeanDeserializer实现自定义的Java bean 解析器,与做序列化器一样,如何将一个Class转为BeanSserializer
构造方法需要的类型才是关键。
BeanSerializerBuilder
如下是BeanSserializer
的构造方法:
public BeanSerializer(JavaType type, BeanSerializerBuilder builder,
BeanPropertyWriter[] properties, BeanPropertyWriter[] filteredProperties);
protected BeanSerializer(BeanSerializerBase src);
protected BeanSerializer(BeanSerializerBase src,ObjectIdWriter objectIdWriter);
protected BeanSerializer(BeanSerializerBase src,ObjectIdWriter objectIdWriter,Object filterId);
protected BeanSerializer(BeanSerializerBase src, Set<String> toIgnore, Set<String> toInclude);
protected BeanSerializer(BeanSerializerBase src,BeanPropertyWriter[] properties, BeanPropertyWriter[] filteredProperties)
这么多构造方法,从哪一个开始是个问题,通过反复跟踪代码,在BeanSerializeFactory.constructBeanOrAddOnSerializer(SerializerProvider prov, JavaType type, BeanDescription beanDesc, boolean staticTyping)
方法中找到了从Class创建BeanSerializerBuilder
实例的代码。
上面BeanSserializer
的第一个构造方法虽然要的参数多,但是有了BeanSerializerBuilder
实例,所有的其他参数都可以想办法从BeanSerializerBuilder
实例中获取 。
JacksonBeanSerializerFactory
由此我继承BeanSerializeFactory
创建了一个新的类JacksonBeanSerializerFactory
,只为照抄父类方法constructBeanOrAddOnSerializer
的逻辑,
下面代码中JacksonBeanSerializerFactory.constructBeanSerializerBuilder
方法只为从BeanDescription
实例返回一个BeanSerializerBuilder
实例
JacksonBeanSerializerFactory.java
class JacksonBeanSerializerFactory extends BeanSerializerFactory {
private static final long serialVersionUID = 4346918816045771010L;
static JacksonBeanSerializerFactory instance = new JacksonBeanSerializerFactory();
public JacksonBeanSerializerFactory() {
this(null);
}
public JacksonBeanSerializerFactory(SerializerFactoryConfig config) {
super(config);
}
JacksonBeanSerializerBuilder constructBeanSerializerBuilder(SerializerProvider prov,
BeanDescription beanDesc)
throws JsonMappingException
{
final SerializationConfig config = prov.getConfig();
JacksonBeanSerializerBuilder builder = new JacksonBeanSerializerBuilder(beanDesc);
builder.setConfig(config);
// First: any detectable (auto-detect, annotations) properties to serialize?
List<BeanPropertyWriter> props = findBeanProperties(prov, beanDesc, builder);
if (props == null) {
props = new ArrayList<BeanPropertyWriter>();
} else {
props = removeOverlappingTypeIds(prov, beanDesc, builder, props);
}
// [databind#638]: Allow injection of "virtual" properties:
prov.getAnnotationIntrospector().findAndAddVirtualProperties(config, beanDesc.getClassInfo(), props);
// [JACKSON-440] Need to allow modification bean properties to serialize:
if (_factoryConfig.hasSerializerModifiers()) {
for (BeanSerializerModifier mod : _factoryConfig.serializerModifiers()) {
props = mod.changeProperties(config, beanDesc, props);
}
}
// Any properties to suppress?
props = filterBeanProperties(config, beanDesc, props);
// Need to allow reordering of properties to serialize
if (_factoryConfig.hasSerializerModifiers()) {
for (BeanSerializerModifier mod : _factoryConfig.serializerModifiers()) {
props = mod.orderProperties(config, beanDesc, props);
}
}
/* And if Object Id is needed, some preparation for that as well: better
* do before view handling, mostly for the custom id case which needs
* access to a property
*/
builder.setObjectIdWriter(constructObjectIdHandler(prov, beanDesc, props));
builder.setProperties(props);
builder.setFilterId(findFilterId(config, beanDesc));
AnnotatedMember anyGetter = beanDesc.findAnyGetter();
if (anyGetter != null) {
JavaType type = anyGetter.getType();
// copied from BasicSerializerFactory.buildMapSerializer():
boolean staticTyping = config.isEnabled(MapperFeature.USE_STATIC_TYPING);
JavaType valueType = type.getContentType();
TypeSerializer typeSer = createTypeSerializer(config, valueType);
// last 2 nulls; don't know key, value serializers (yet)
// 23-Feb-2015, tatu: As per [databind#705], need to support custom serializers
JsonSerializer<?> anySer = findSerializerFromAnnotation(prov, anyGetter);
if (anySer == null) {
// TODO: support '@JsonIgnoreProperties' with any setter?
anySer = MapSerializer.construct(/* ignored props*/ (Set<String>) null,
type, staticTyping, typeSer, null, null, /*filterId*/ null);
}
// TODO: can we find full PropertyName?
PropertyName name = PropertyName.construct(anyGetter.getName());
BeanProperty.Std anyProp = new BeanProperty.Std(name, valueType, null,
beanDesc.getClassAnnotations(), anyGetter, PropertyMetadata.STD_OPTIONAL);
builder.setAnyGetter(new AnyGetterWriter(anyProp, anyGetter, anySer));
}
// Next: need to gather view information, if any:
processViews(config, builder);
// Finally: let interested parties mess with the result bit more...
/** 暂时删除 */
// if (_factoryConfig.hasSerializerModifiers()) {
// for (BeanSerializerModifier mod : _factoryConfig.serializerModifiers()) {
// builder = mod.updateBuilder(config, beanDesc, builder);
// }
// }
return builder.builder();
}
}
createBeanSerializer
然后我们就可以实现一个方法从Class创建一个BeanSerializerBuilder
的实例:如下
/**
* 创建{@code beanClass}对应的{@link BeanDeserializerBase}实例用于父类构造方法的参数,
* 将{@code beanClass}的序列化参数注入到当前实例中
* @param beanClass
*/
private static JacksonBeanSerializerBuilder createBeanSerializer(Class<?> beanClass){
try {
JavaType type = TypeFactory.defaultInstance().constructType(beanClass);
ObjectMapper mapper = new ObjectMapper();
BeanDescription desc = mapper.getSerializationConfig().introspect(type);
SerializerProvider provider = ((DefaultSerializerProvider) mapper.getSerializerProvider())
.createInstance(mapper.getSerializationConfig(), JacksonBeanSerializerFactory.instance);
return JacksonBeanSerializerFactory.instance
.constructBeanSerializerBuilder(provider, desc);
} catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
JacksonBeanSerializerBuilder
上面方法中返回类型JacksonBeanSerializerBuilder
是BeanSerializerBuilder
的子类,
实现代码如下:
JacksonBeanSerializerBuilder.java
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
import com.fasterxml.jackson.databind.ser.BeanSerializerBuilder;
/**
* @author guyadong
* @since 3.31.3
*/
class JacksonBeanSerializerBuilder extends BeanSerializerBuilder {
private final static BeanPropertyWriter[] NO_PROPERTIES = new BeanPropertyWriter[0];
JacksonBeanSerializerBuilder(BeanDescription beanDesc) {
super(beanDesc);
}
JacksonBeanSerializerBuilder(BeanSerializerBuilder src) {
super(src);
}
public void setConfig(SerializationConfig config) {
_config = config;
}
JacksonBeanSerializerBuilder builder()
{
if (_anyGetter != null) {
_anyGetter.fixAccess(_config);
}
if (_typeId != null) {
if (_config.isEnabled(MapperFeature.CAN_OVERRIDE_ACCESS_MODIFIERS)) {
_typeId.fixAccess(_config.isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS));
}
}
return this;
}
/**
* @see #build()
*/
BeanPropertyWriter[] buildProperties() {
BeanPropertyWriter[] properties;
// No properties, any getter or object id writer?
// No real serializer; caller gets to handle
if (_properties == null || _properties.isEmpty()) {
if (_anyGetter == null && _objectIdWriter == null) {
return null;
}
properties = NO_PROPERTIES;
} else {
properties = _properties.toArray(new BeanPropertyWriter[_properties.size()]);
if (_config.isEnabled(MapperFeature.CAN_OVERRIDE_ACCESS_MODIFIERS)) {
for (int i = 0, end = properties.length; i < end; ++i) {
properties[i].fixAccess(_config);
}
}
}
return properties;
}
}
示例:JacksonExampleSerializer
有了createBeanSerializer
方法,我们就可以很容易继承BeanSerializer
实现自定义的序列化器了,示例如下:
JacksonExampleSerializer.java
import java.io.IOException;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.BeanSerializer;
import com.fasterxml.jackson.databind.ser.DefaultSerializerProvider;
import com.fasterxml.jackson.databind.type.TypeFactory;
@SuppressWarnings("serial")
public abstract class JacksonExampleSerializer extends BeanSerializer {
public JacksonExampleSerializer(Class<?> beanClass) {
this( createBeanSerializer(beanClass));
}
private JacksonExampleSerializer(JacksonBeanSerializerBuilder builder) {
super(builder.getBeanDescription().getType(),
builder,builder.buildProperties(),builder.getFilteredProperties());
}
@Override
protected void serializeFieldsFiltered(Object bean, JsonGenerator gen, SerializerProvider provider)
throws IOException, JsonGenerationException {
// 根据需要重写实现方法
super.serializeFieldsFiltered(bean, gen, provider);
}
/**
* 创建{@code beanClass}对应的{@link BeanSerializerBuilder}实例用于父类构造方法的参数,
* 将{@code beanClass}的序列化参数注入到当前实例中
* @param beanClass
*/
private static JacksonBeanSerializerBuilder createBeanSerializer(Class<?> beanClass){
try {
JavaType type = TypeFactory.defaultInstance().constructType(beanClass);
ObjectMapper mapper = new ObjectMapper();
BeanDescription desc = mapper.getSerializationConfig().introspect(type);
SerializerProvider provider = ((DefaultSerializerProvider) mapper.getSerializerProvider())
.createInstance(mapper.getSerializationConfig(), JacksonBeanSerializerFactory.instance);
return JacksonBeanSerializerFactory.instance
.constructBeanSerializerBuilder(provider, desc);
} catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
}