Jackson JSON在序列化之前修改对象

Add*_*ons 7 java serialization json jackson

我希望在序列化之前修改对象.我想编写一个自定义序列化程序来解析对象,然后将其传递给默认对象序列化程序.

这就是我所拥有的:

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;

/**
 *
 * @author Me
 */
public class PersonSerializer extends JsonSerializer<Person>{

    @Override
    public void serialize(Person value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {

        //This returns a modified clone of Person value.
        Person safePerson = PrivacyService.getSafePerson(value);

        provider.defaultSerializeValue(safePerson, jgen);

    }

}
Run Code Online (Sandbox Code Playgroud)

但这只是一个无限循环.我也尝试过:

provider.findTypedValueSerializer(Person.class, true, null).serialize(safePerson, jgen, provider);
Run Code Online (Sandbox Code Playgroud)

这可行,但它不解析对象中的任何字段.

我也试过使用a @JsonFilter但它非常重,并且我的加载时间是六倍.

救命!谢谢!

And*_*riy 8

由于Jackson 2.2可能会在JsonSerialize注释中使用转换器:

@JsonSerialize(converter = OurConverter.class)

和转换器

public class OurConverter extends StdConverter<IN, OUT>

如果修改对象,IN和OUT是同一类


Add*_*ons 7

神圣的废话,经过几个小时的挖掘这个图书馆,试图写我自己的工厂,以及其他一千个东西,我最终得到了这个愚蠢的事情做我想要的:

public class PersonSerializer extends JsonSerializer<Person>{

    @Override
    public void serialize(Person value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {

        Person safePerson = PrivacyService.getSafePerson(value);

        //This is the crazy one-liner that will save someone a very long time
        BeanSerializerFactory.instance.createSerializer(provider, SimpleType.construct(Person.class)).serialize(safePerson, jgen, provider);

    }

}
Run Code Online (Sandbox Code Playgroud)

  • 您也可以使用BeanSerilizerModifier.我在这个答案中发布了一个例子:http://stackoverflow.com/a/25513488/3537858 (2认同)

Tom*_*ský 5

虽然我最初对找到@ Nitroware的答案感到高兴,但遗憾的是它在Jackson 2.7.2中不起作用 - 再次在类上BeanSerializerFactory.instance.createSerializer内省JsonSerializer注释Person,这导致无限递归和StackOverflowError.

如果@JsonSerializer在POJO类上不存在,则创建默认序列化程序的点是BeanSerializerFactory.constructBeanSerializer方法.所以我们直接使用这种方法吧.由于该方法是protected,我们通过工厂子类使其可见,并向其提供有关序列化类的信息.此外,我们SimpleType.construct通过其推荐的替代品替换弃用的方法.整个解决方案是:

public class PersonSerializer extends JsonSerializer<PersonSerializer> {

    static class BeanSerializerFactoryWithVisibleConstructingMethod extends BeanSerializerFactory {

        BeanSerializerFactoryWithVisibleConstructingMethod() {
            super(BeanSerializerFactory.instance.getFactoryConfig());
        }

        @Override
        public JsonSerializer<Object> constructBeanSerializer(SerializerProvider prov, BeanDescription beanDesc) throws JsonMappingException {
            return super.constructBeanSerializer(prov, beanDesc);
        }

    }

    private final BeanSerializerFactoryWithVisibleConstructingMethod defaultBeanSerializerFactory = new BeanSerializerFactoryWithVisibleConstructingMethod();

    private final JavaType javaType = TypeFactory.defaultInstance().constructType(Person.class);

    @Override
    public void serialize(Person value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
        Person safePerson = PrivacyService.getSafePerson(value);
        JavaType type = TypeFactory.defaultInstance().constructType(Person.class);
        BeanDescription beanDescription = provider.getConfig().introspect(type);
        JsonSerializer<Object> defaultSerializer = defaultBeanSerializerFactory.constructBeanSerializer(provider, beanDescription);
        defaultSerializer.serialize(safePerson, jgen, provider);
    }

}
Run Code Online (Sandbox Code Playgroud)

BeanSerializerModifier基于解决方案不同的是,您必须在自定义序列化程序之外声明并注册特殊行为,使用此解决方案时,特殊逻辑仍然封装在自定义中PersonSerializer.

最终,逻辑可能被推到自定义DefaultJsonSerializerAware祖先.

更新2017-09-28:

我发现上面提到的推理错误.使用sole BeanSerializerFactory.constructBeanSerializer方法是不够的.如果原始类包含空字段,则它们不在输出中.(原因是constructBeanSerializer方法是从createAndCacheUntypedSerializer方法中间接调用的,后来调用addAndResolveNonTypedSerializer方法,其中NullSerializers被添加到BeanPropertyWriters中).)

解决这个问题对我来说似乎是正确的并且非常简单,就是重用所有序列化逻辑,而不仅仅是constructBeanSerializer方法.这个逻辑从提供者的serializeValue方法开始.唯一不合适的是自定义JsonSerialize注释.所以我们重新定义BeanSerializationFactory假装内省类(并且只有它 - 否则J字序化对字段类型的注释不适用)没有JsonSerialize注释.

@Override
public void serialize(Person value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
    Person safePerson = PrivacyService.getSafePerson(value);
    ObjectMapper objectMapper = (ObjectMapper)jgen.getCodec();
    Class<?> entityClass = value.getClass();
    JavaType javaType = TypeFactory.defaultInstance().constructType(entityClass);
    DefaultSerializerProvider.Impl defaultSerializerProvider = (DefaultSerializerProvider.Impl) objectMapper.getSerializerProviderInstance();
    BeanSerializerFactory factoryIgnoringCustomSerializerOnRootClass = new BeanSerializerFactory(BeanSerializerFactory.instance.getFactoryConfig()) {
        @Override
        protected JsonSerializer<Object> findSerializerFromAnnotation(SerializerProvider prov, Annotated a) throws JsonMappingException {
            JsonSerializer<Object> result = javaType.equals(a.getType()) ? null : super.findSerializerFromAnnotation(prov, a);
            return result;
        }
    };
    DefaultSerializerProvider.Impl updatedSerializerProvider = defaultSerializerProvider.createInstance(defaultSerializerProvider.getConfig(), factoryIgnoringCustomSerializerOnRootClass);
    updatedSerializerProvider.serializeValue(jgen, value);
}
Run Code Online (Sandbox Code Playgroud)

请注意,如果您没有遇到空值问题,以前的解决方案就足够了.