jackson:基于BeanSerializer实现自定义的Java bean序列化器

作者 : admin 本文共9165个字,预计阅读时间需要23分钟 发布时间: 2024-06-10 共2人阅读

之前写过一篇博客《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

上面方法中返回类型JacksonBeanSerializerBuilderBeanSerializerBuilder的子类,
实现代码如下:
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.deser.BeanDeserializerBase;
import com.fasterxml.jackson.databind.ser.BeanSerializer;
import com.fasterxml.jackson.databind.ser.DefaultSerializerProvider;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.google.common.base.Supplier;
import gu.sql2java.filter.Filterable;
import gu.sql2java.filter.IFilter;
@SuppressWarnings("serial")
public abstract class JacksonExampleSerializer extends BeanSerializer implements Filterable {
public JacksonExampleSerializer(Class<?> beanClass) {
this(	createBeanSerializer(beanClass));
}
private JacksonExampleSerializer(JacksonBeanSerializerBuilder builder) {
super(builder.getBeanDescription().getType(),
builder,builder.buildProperties(),builder.getFilteredProperties());
}
@Override
public void injectFilter(Supplier<? extends IFilter> fieldFilterSupplier,
Supplier<? extends IFilter> valueFilterSupplier) {
// DO SOMETHING
}
@Override
protected void serializeFieldsFiltered(Object bean, JsonGenerator gen, SerializerProvider provider)
throws IOException, JsonGenerationException {
// TODO 自动生成的方法存根
super.serializeFieldsFiltered(bean, gen, provider);
}
/**
* 创建{@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);
}
}
}
本站无任何商业行为
个人在线分享 » jackson:基于BeanSerializer实现自定义的Java bean序列化器
E-->