【问题标题】:Jackson JSON Modify Object Before SerializationJackson JSON 在序列化之前修改对象
【发布时间】:2014-10-20 02:53:08
【问题描述】:

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

这就是我所拥有的:

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);

    }

}

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

provider.findTypedValueSerializer(Person.class, true, null).serialize(safePerson, jgen, provider);

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

我也尝试过使用@JsonFilter,但它非常重,并且使我的加载时间增加了六倍。

帮助!谢谢!

【问题讨论】:

  • 为什么要这样做,您想在将 Person 对象中的某些内容发送回客户端之前隐藏它吗?
  • 是的,我有一个服务可以清除 Person 对象并返回它的清除克隆。问题是,这取决于您登录的原因,决定了删除了多少数据。
  • 还有一些情况,我在序列化一个数组,数组中有两个不同的人,我需要从每个人中删除不同的东西。
  • Jackson 视图和视图旨在解决此类问题。 wiki.fasterxml.com/JacksonJsonViews
  • 很棒的发现!但从我所见,这意味着我必须注释这个类的每个字段(并且有 40 多个),然后必须管理每个字段。这对我想做的事情来说有点混乱。

标签: java json serialization jackson


【解决方案1】:

天哪,经过几个小时的挖掘这个库,尝试编写我自己的工厂,以及其他一千件事,我终于得到了这个愚蠢的东西来做我想做的事:

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);

    }

}

【讨论】:

【解决方案2】:

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

@JsonSerialize(converter = OurConverter.class)

和转换器

public class OurConverter extends StdConverter&lt;IN, OUT&gt;

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

【讨论】:

    【解决方案3】:

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

    如果 POJO 类上不存在 @JsonSerializer,则创建默认序列化程序的点是 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);
        }
    
    }
    

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

    最终逻辑可能会被推送到自定义 DefaultJsonSerializerAware 祖先。

    2017 年 9 月 28 日更新:

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

    这个问题的解决方案对我来说似乎是正确的并且非常简单重用所有序列化逻辑,而不仅仅是constructBeanSerializer方法。这个逻辑从提供者的serializeValue 方法开始。唯一不合适的是自定义 JsonSerialize 注释。因此,我们重新定义 BeanSerializationFactory 以假装自省类(并且只有它 - 否则字段类型上的 JsonSerialize 注释将不适用)没有 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);
    }
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-03-19
      • 1970-01-01
      • 1970-01-01
      • 2017-12-10
      • 2014-02-12
      • 1970-01-01
      • 1970-01-01
      • 2023-03-13
      相关资源
      最近更新 更多