【问题标题】:Jackson Deserialize Abstract ClassesJackson 反序列化抽象类
【发布时间】:2017-11-06 13:36:48
【问题描述】:

我正在尝试使用 JSON ObjectMapper 反序列化对象。尝试反序列化时看到以下错误

com.fasterxml.jackson.databind.JsonMappingException: 无法构造 com.phoenix.types.OrderItem 的实例: 抽象类型要么需要映射到具体类型,要么有自定义 解串器,或在 [Source: java.io.StringReader@4bb33f74;行:112,列:7](通过 参考链: com.phoenix.types.GenerateRequest["order"]->com.phoenix.types.Order["orderItems"]->Object[][0]) 在 com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:261) 在 com.fasterxml.jackson.databind.DeserializationContext.instantiationException(DeserializationContext.java:1456) 在 com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1012) 在 com.fasterxml.jackson.databind.deser.AbstractDeserializer.deserialize(AbstractDeserializer.java:149) 在 com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:196) 在 com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:20) 在 com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:499) 在 com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:101) 在 com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:276) 在 com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:140) 在 com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:499) 在 com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:101) 在 com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:276) 在 com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:140) 在 com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3789) 在 com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2833)

我遇到了这个post 用于执行多态反序列化。这基本上提供了解决上面列出的错误的解决方案。我用于反序列化的类(在本例中为 OrderItem 等)是 jar 文件的一部分。但是,有没有办法在尝试反序列化而不是向类本身添加注释时将 JsonDeserialize 定义为 objectmapper 的一部分,因为我无权访问它。

【问题讨论】:

    标签: java spring spring-boot jackson


    【解决方案1】:

    是的,您可以为抽象类编写自己的Custom Deserializer。这个反序列化器必须确定 JSON 代表的具体类,并实例化它的一个实例。

    可能有一种更惯用的方式来做这件事,但这里有一个简单粗暴的例子:

    public class Test {
        public static void main(String... args) throws IOException {
            final ObjectMapper mapper = new ObjectMapper();
            final SimpleModule module = new SimpleModule();
            module.addDeserializer(Animal.class, new AnimalDeserializer());
            mapper.registerModule(module);
    
            final String json = "{\"aGoodBoy\": true}";
            final Animal animal = mapper.readValue(json, Animal.class);
            System.out.println(animal.talk());
        }
    
        public static abstract class Animal {
            public abstract String talk();
        }
    
        public static class Fish extends Animal {
            @Override
            public String talk() {
                return "blub blub I'm a dumb fish";
            }
        }
    
        public static class Dog extends Animal {
            public boolean aGoodBoy;
    
            @Override
            public String talk() {
                return "I am a " + (aGoodBoy ? "good" : "bad") + " dog";
            }
        }
    
        public static class AnimalDeserializer extends StdDeserializer<Animal> {
            protected AnimalDeserializer() {
                this(null);
            }
    
            protected AnimalDeserializer(final Class<?> vc) {
                super(vc);
            }
    
            @Override
            public Animal deserialize(final JsonParser parser, final DeserializationContext context)
            throws IOException, JsonProcessingException {
                final JsonNode node = parser.getCodec().readTree(parser);
                final ObjectMapper mapper = (ObjectMapper)parser.getCodec();
                if (node.has("aGoodBoy")) {
                    return mapper.treeToValue(node, Dog.class);
                } else {
                    return mapper.treeToValue(node, Fish.class);
                }
            }
        }
    }
    

    【讨论】:

    • 谢谢安德鲁。是否有使用自定义反序列化器为抽象类指定具体类的示例?
    • 更新了代码示例。我确信有一个更好的方法来获取底层ObjectMapper,而不是强制转换 ObjectCodec,但是我很难找到它。您也可以手动构建具体实例,但我有点想避免做这项工作。
    • 这节省了我的时间。
    【解决方案2】:

    【讨论】:

      【解决方案3】:

      MyClass.java

      class MyClass<T extends Serializable> implements Serializable{
      
          @JsonProperty(value = "allowedValues", required = false)
          private List<T> allowedValues;
      }
      

      在我的情况下,类型是列表。因此,我遇到了这个异常

      将 json 反序列化为 MyClass.java 时出错:com.fasterxml.jackson.databind.exc.InvalidDefinitionException:无法构造 java.io.Serializable 的实例(不存在像默认构造一样的创建者):要么需要抽象类型映射到具体类型,具有自定义反序列化器,或包含其他类型信息 在 [Source: (String)"{"allowedValues":["a","b","c"]} (通过引用链:com.babu.model.MyClass->["allowedValues"]->java. util.ArrayList[0])

      我该如何解决这个问题?

      【讨论】:

        【解决方案4】:

        Jackson 尝试创建抽象类的实例。

        在你的抽象类中为这个字段写@JsonIgnore注解 并为此字段创建吸气剂。然后在这个getter上再写一个注解 @JsonProperty("{{nameOfYourField}}")

        @JsonIgnore
        @JoinColumn(name = "column_name")
        private OrderItem orderItem;
        
        @JsonProperty("orderItem")
        public OrderItem getOrderItem () {
            return orderItem;
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-05-22
          • 2018-03-06
          • 2010-10-12
          • 1970-01-01
          • 2012-11-18
          • 1970-01-01
          • 2019-06-10
          • 1970-01-01
          相关资源
          最近更新 更多