在运行时以自定义方式(反)序列化 Bean

2023-12-22

假设我有以下 POJO:

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

在运行时,我希望对除一个属性之外的所有属性进行默认序列化/反序列化。通常,我想在序列化时用数据库中的 ID 替换字段,类似于这另一个问题 https://stackoverflow.com/questions/5325096/deserializing-entities-with-relationships.

例如我想替换o通过从外部映射获得的字符串(例如:object1“123”和object2“456”):

  • 序列化:读取o并替换(所以如果o is object1,序列化为字符串“123”)
  • 反序列化:读取“123”,查询一些表以获取原始值o回来(即object1),重新创建一个Pojo对象与o = object1.

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

有人可以举一个例子(甚至是人为的)或替代方法吗?


Notes:

  • 我无法使用注释或 Mixins,因为更改在编译时是未知的(即任何属性都可能以不可确定的方式更改)。
  • 这另一个问题 https://stackoverflow.com/questions/2981359/jackson-suppressing-serializationwrite-of-properties-dynamically指出使用 CustomSerializerFactory,它似乎可以完成这项工作。不幸的是,官方网站表明这不再是推荐的方法 http://wiki.fasterxml.com/CustomSerializerFactory并且应该使用模块来代替。

Edit

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

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需要替换的字段,但我不需要。


I think @JsonSerialize and @JsonDeserialize就是你所需要的。这些注释使您可以控制特定字段的序列化/反序列化。这个问题 https://stackoverflow.com/questions/12921812/create-a-custom-jackson-annotation展示了将它们组合成一个注释的优雅方式。

UPD.对于这个复杂的场景,你可以看看BeanSerializerModifier/BeanDeserializerModifier类。这个想法是修改一般BeanSerializer/BeanDeserializer使用特定字段的自定义逻辑,并让基本实现来做其他事情。稍后将发布一个示例。

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

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

UPD4.使用完整的自定义序列化/反序列化更新了示例。 (我用过杰克逊映射器-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();
        }
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在运行时以自定义方式(反)序列化 Bean 的相关文章

随机推荐