(De-)在运行时以自定义方式序列化Bean [英] (De-)Serialize Bean in a custom way at runtime

查看:334
本文介绍了(De-)在运行时以自定义方式序列化Bean的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

让我们假设我有以下POJO:

Let's imagine I have the following POJO:

class Pojo {
    String s;
    Object o;
    Map<String, String> m;
}

在运行时,我想要除一个属性之外的所有属性的默认序列化/反序列化。通常,我想在序列化时用数据库中的ID替换字段,类似于这个其他问题

And at runtime, I want default serialization / deserialization for all properties except one. Typically, I want to replace a field by its ID in a database when serializing, similarly to this other question.

例如,我想用从外部映射获取的字符串替换 o (例如: object1 < =>123和 object2 < =>456):

For example, I want to replace o by a string obtained from an external mapping (for example: object1 <=> "123" and object2 <=> "456"):


  • 序列化:读取 o 并替换(如果 o object1 ,序列化为字符串123)

  • 反序列化:读取123,查询一些表得到原始值 o 返回(即 object1 ),重新创建 Pojo 对象 o = object1

  • serialization: read o and replace (so if o is object1, serialize as string "123")
  • deserialization: read "123", query some table to get the original value of o back (i.e. object1), recreate a Pojo object with o = object1.

我理解模块会是一种方法,但我不知道如何使用它们同时保持自动BeanSerializer / Deserializer的属性不需要更改。

I understand that Modules would be one way to do that but I'm not sure how to use them while keeping the automatic BeanSerializer/Deserializer for the properties that don't need to be changed.

有人可以给出一个例子(甚至做作)或另一种方法吗?

Can someone give an example (even contrived) or an alternative approach?

注意:


  • 我无法使用注释或Mixins,因为在编译时未知更改(即任何属性都可能以不可确定的方式更改。)

  • 这个其他问题指向使用CustomSerializerFactory,它似乎可以完成这项工作。不幸的是,官方网站指出它不再是推荐的方法而应该使用模块代替。

  • I can't use annotations or Mixins as the changes are unknown at compile time (i.e. any properties might be changed in a way that is not determinable).
  • This other question points to using a CustomSerializerFactory, which seems to do the job. Unfortunately, the official site indicates that it is not the recommended approach any more and that modules should be used instead.

修改

为了更清楚一点,我可以使用Mixins执行以下操作:

To be a little clearer, I can do the following with Mixins for example:

ObjectMapper mapper = new ObjectMapper(MongoBsonFactory.createFactory());
mapper.addMixInAnnotations(Pojo.class, PojoMixIn.class);

ObjectReader reader = mapper.reader(Pojo.class);
DBEncoder dbEncoder = DefaultDBEncoder.FACTORY.create();
OutputBuffer buffer = new BasicOutputBuffer();
dbEncoder.writeObject(buffer, o);

使用以下Mixin:

abstract class PojoMixIn {
    @JsonIgnore Object o;
}

然后将所需的字符串添加到JSON内容中。但是我需要在编译时知道需要替换的是 o 字段,我不这样做。

And then add the required string to the JSON content. But I would need to know at compile time that it is the o field that needs to be replaced, which I don't.

推荐答案

我认为 @JsonSerialize @JsonDeserialize 是什么你需要。这些注释使您可以控制特定字段的序列化/反序列化。 这个问题显示了将它们组合成一个注释的优雅方式。

I think @JsonSerialize and @JsonDeserialize is what you need. These annotations give you control on the serialization/deserialization of particular fields. This question shows elegant way to combine them into one annotation.

UPD。对于这个复杂的场景,您可以查看 BeanSerializerModifier / BeanDeserializerModifier 类。我们的想法是使用您的特定字段的自定义逻辑修改常规 BeanSerializer / BeanDeserializer ,并让基本实现执行其他操作。稍后会发布一个例子。

UPD. For this complex scenario you could take a look at BeanSerializerModifier/BeanDeserializerModifier classes. The idea is to modify general BeanSerializer/BeanDeserializer with your custom logic for particular fields and let basic implementation to do other stuff. Will post an example some time later.

UPD2。正如我所见,其中一种方法可能是使用 changeProperties 方法并指定您自己的序列化程序。

UPD2. As I see, one of the way could be to use changeProperties method and assign your own serializer.

UPD3。更新了自定义序列化程序的工作示例。反序列化可以类似的方式完成。

UPD3. Updated with working example of custom serializer. Deserialization could be done in similar way.

UPD4。更新了完整自定义序列化/反序列化的示例。 (我使用过 jakson-mapper-asl-1.9.8

UPD4. Updated example with full custom serialization/deserialization. (I have used jakson-mapper-asl-1.9.8)

  public class TestBeanSerializationModifiers {

    static final String PropertyName = "customProperty";
    static final String CustomValue = "customValue";
    static final String BaseValue = "baseValue";

    // Custom serialization

    static class CustomSerializer extends JsonSerializer<Object> {
        @Override
        public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
            String customValue = CustomValue; // someService.getCustomValue(value);
            jgen.writeString(customValue);
        }
    }

    static class MyBeanSerializerModifier extends BeanSerializerModifier {
        @Override
        public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BasicBeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) {
            for (int i = 0; i < beanProperties.size(); i++) {
                BeanPropertyWriter beanPropertyWriter = beanProperties.get(i);
                if (PropertyName.equals(beanPropertyWriter.getName())) {
                    beanProperties.set(i, beanPropertyWriter.withSerializer(new CustomSerializer()));
                }
            }
            return beanProperties;
        }
    }

    // Custom deserialization

    static class CustomDeserializer extends JsonDeserializer<Object> {
        @Override
        public Object deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
            // serialized value, 'customValue'
            String serializedValue = jp.getText();
            String baseValue = BaseValue; // someService.restoreOldValue(serializedValue);
            return baseValue;
        }
    }

    static class MyBeanDeserializerModifier extends BeanDeserializerModifier {
        @Override
        public BeanDeserializerBuilder updateBuilder(DeserializationConfig config, BasicBeanDescription beanDesc, BeanDeserializerBuilder builder) {
            Iterator<SettableBeanProperty> beanPropertyIterator = builder.getProperties();
            while (beanPropertyIterator.hasNext()) {
                SettableBeanProperty settableBeanProperty = beanPropertyIterator.next();
                if (PropertyName.equals(settableBeanProperty.getName())) {
                    SettableBeanProperty newSettableBeanProperty = settableBeanProperty.withValueDeserializer(new CustomDeserializer());
                    builder.addOrReplaceProperty(newSettableBeanProperty, true);
                    break;
                }
            }
            return builder;
        }
    }

    static class Model {

        private String customProperty = BaseValue;
        private String[] someArray = new String[]{"one", "two"};

        public String getCustomProperty() {
            return customProperty;
        }

        public void setCustomProperty(String customProperty) {
            this.customProperty = customProperty;
        }

        public String[] getSomeArray() {
            return someArray;
        }

        public void setSomeArray(String[] someArray) {
            this.someArray = someArray;
        }
    }

    public static void main(String[] args) {
        SerializerFactory serializerFactory = BeanSerializerFactory
                .instance
                .withSerializerModifier(new MyBeanSerializerModifier());

        DeserializerFactory deserializerFactory = BeanDeserializerFactory
                .instance
                .withDeserializerModifier(new MyBeanDeserializerModifier());

        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setSerializerFactory(serializerFactory);
        objectMapper.setDeserializerProvider(new StdDeserializerProvider(deserializerFactory));

        try {
            final String fileName = "test-serialization.json";
            // Store, "customValue" -> json
            objectMapper.writeValue(new File(fileName), new Model());
            // Restore, "baseValue" -> model
            Model model = objectMapper.readValue(new File(fileName), Model.class);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

这篇关于(De-)在运行时以自定义方式序列化Bean的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆