【问题标题】:GenericJackson2JsonRedisSerializer Ignore Class and AttributeGenericJackson2JsonRedisSerializer 忽略类和属性
【发布时间】:2021-04-13 04:15:52
【问题描述】:

我正在尝试将 ClassA 序列化为 JSON,然后将其反序列化并将其映射到 ClassB 仅在类似属性上,忽略大量检查。假设我有

public class First{
   private String attribute1;
   private String attribute2;
   private String attribute3;
}

public class Second{
   private Int attribute1;
   private String attribute2;
   private String attribute4;
}

我期待的是映射Second 的对象

{
   "attribute2": "value2"
}

有可能吗?我需要这样做,因为我在一些微服务之间有一个共享的 redis 缓存键。由于设计的变化,存储在redis中的类可能会有不同的定义,并且检查和更新每个微服务的代码是不可行的。谢谢

【问题讨论】:

    标签: spring-boot caching serialization redis


    【解决方案1】:

    没有直接的方法可以告诉GenericJackson2JsonRedisSerializer 忽略某些字段并将类A 转换为B,您可以实施任何您想要的反序列化策略。

    一个简单的例子是,当你想进行类型转换时注册你的映射和可忽略的字段。

    // Adapted from spring data redis
    public class RqueueRedisSerDes implements RedisSerializer<Object> {
        private ObjectMapper mapper;
    
        @AllArgsConstructor
        @Getter
        class Dataum {
          Class<?> tgtClass;
          String[] ignorableProperties;
        }
    
        private Map<Class<?>, Dataum> classMap = new ConcurrentHashMap<>();
    
        RqueueRedisSerDes() {
          this.mapper = new ObjectMapper();
          this.mapper =
              mapper.registerModule(new SimpleModule().addSerializer(new NullValueSerializer()));
          this.mapper = mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
          this.mapper = mapper.enableDefaultTyping(DefaultTyping.NON_FINAL, As.PROPERTY);
        }
    
        public void addClassMap(Class<?> source, Class<?> tgt, String[] ignorableProperties) {
          classMap.put(source, new Dataum(tgt, ignorableProperties));
        }
    
        @Override
        public byte[] serialize(Object source) throws SerializationException {
          if (source == null) {
            return SerializationUtils.EMPTY_ARRAY;
          }
          try {
            return mapper.writeValueAsBytes(source);
          } catch (JsonProcessingException e) {
            throw new SerializationException("Could not write JSON: " + e.getMessage(), e);
          }
        }
    
        @Override
        public Object deserialize(byte[] source) throws SerializationException {
          if (SerializationUtils.isEmpty(source)) {
            return null;
          }
          try {
            Object object = mapper.readValue(source, Object.class);
            for (Entry<Class<?>, Dataum> entry : classMap.entrySet()) {
              if (ClassUtils.isAssignable(entry.getKey(), object.getClass())) {
                Dataum dataum = entry.getValue();
                Object tgt = dataum.getTgtClass().newInstance();
                BeanUtils.copyProperties(object, tgt, dataum.getIgnorableProperties());
                return tgt;
              }
            }
            return object;
          } catch (Exception ex) {
            throw new SerializationException("Could not read JSON: " + ex.getMessage(), ex);
          }
        }
    
        private static class NullValueSerializer extends StdSerializer<NullValue> {
    
          private static final long serialVersionUID = 211020517180777825L;
          private final String classIdentifier;
    
          NullValueSerializer() {
            super(NullValue.class);
            this.classIdentifier = "@class";
          }
    
          @Override
          public void serialize(
              NullValue value, JsonGenerator jsonGenerator, SerializerProvider provider)
              throws IOException {
            jsonGenerator.writeStartObject();
            jsonGenerator.writeStringField(classIdentifier, NullValue.class.getName());
            jsonGenerator.writeEndObject();
          }
        }
      }
    

    定义一个实现RedisSerializer&lt;Object&gt;的类,在RedisConnectionFactory中使用这个类来序列化/反序列化值。

    class SerializerTest{      
      @Data
      @AllArgsConstructor
      @NoArgsConstructor
      public static class First {
        private String attribute1;
        private String attribute2;
        private String attribute3;
      }
      @Data
      @ToString
      public static class Second {
        private Integer attribute1;
        private String attribute2;
        private String attribute4;
      }
    
      public static void main(String[] args) {
        RqueueRedisSerDes serDes = new RqueueRedisSerDes();
        // ignore attribute1 due to different type
        serDes.addClassMap(First.class, Second.class, new String[]{"attribute1"});
        First first = new First("1", "2", "3");
        byte[] out = serDes.serialize(first);
        Second second = (Second) serDes.deserialize(out);
        System.out.println(second);
      }
    }
    

    我刚刚修改了我的 Repo Rqueue 中的代码

    【讨论】:

    • 谢谢@sonus21,对我很有帮助
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-20
    • 1970-01-01
    • 2016-05-19
    相关资源
    最近更新 更多