对于如果属性在抽象类中这个利用@JsonTypeInfo 和 @JsonSubTypes 很容易实现,如果这个属性与将要反序列化在同一层级,那个应该怎么做,将下面举个例子,基于spring-boot环境
-
public interface Item{ } public class Person{ private Integer age; private Item item; } // age<7 public ChildItem implement Item { private String read; private String sleep; } // 7< age < 50 public AdultItem implement Item { private String work; private String playGame; } // age > 50 public OldItem implement Item { private String walk; private String talk; }
-
上面定义Person对象,里面有item,具体实现类是通过age来决定jackson具体实例化那个类
-
此时使用@JsonTypeInfo 和 @JsonSubTypes不好处理,它针对是json中都相同属性,根据属性值判断,可惜这里属性都不相同?
解决方案
1、完全手动实现反序列化
-
如果实体不是很复杂这个还是可以接受,如果bean字段特别多,那么不好操作了
-
也就实现StdDeserializer的deserialize方法
-
示例代码(spring boot)下
-
@JsonComponent public class ItemDeserializer extends StdDeserializer<Item> { protected ItemDeserializer() { super(Item.class); } @Override public Item deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { ObjectMapper mapper = (ObjectMapper) p.getCodec(); JsonNode itemNode = mapper.readTree(p); JsonNode read = itemNode.get("read"); if (read != null && !read.asText().isEmpty()) { ChildItem childItem = new ChildItem(); childItem.setRead(read.asText()); childItem.setSleep(itemNode.get("sleep").asText()); return childItem; } JsonNode work = itemNode.get("work"); if (work != null && !work.asText().isEmpty()) { AdultItem adultItem = new AdultItem(); adultItem.setWork(work.asText()); adultItem.setPlayGame(itemNode.get("playGame").asText()); return adultItem; } JsonNode work = itemNode.get("walk"); if (walk != null && !walk.asText().isEmpty()) { OldItem oldItem = new OldItem(); oldItem.setWalk(walk.asText()); oldItem.setTalk(itemNode.get("talk").asText()); return oldItem; } return null; } }
-
直接根据json字段判断需要实例化那个对象
-
@JsonComponent,将该反序列注册到Jackson中
2、半手动实现反序列化
-
思路就是补上相同字段,让它标准化
-
重新序列化操作( 适合字段多的bean)
-
@JsonComponent public class PersonDeserializer extends StdDeserializer<Person> { protected PersonDeserializer() { super(Person.class); } @Override public Person deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { ObjectMapper mapper = (ObjectMapper) p.getCodec(); JsonNode tree = mapper.readTree(p); JsonNode itemNode = tree.get("item"); int age = itemNode.get("age").asInt(); if (age<7) { ((ObjectNode) itemNode).put("type", "child"); }else if(age < 50){ ((ObjectNode) itemNode).put("type", "adult"); }else{ ((ObjectNode) itemNode).put("type", "old"); } return new ObjectMapper().readValue(tree.toString(), Person.class); } } // 配置 @JsonTypeInfo注解 public class Person{ private Integer age; @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type") @JsonSubTypes({ @JsonSubTypes.Type(value = ChildItem.class, name = "child"), @JsonSubTypes.Type(value = AdultItem.class, name = "adult"), @JsonSubTypes.Type(value = OldItem.class, name = "old"), }) private Item item; }
-
return new ObjectMapper().readValue(tree.toString(), Person.class); 这个一定要注意需要new ObjectMapper() , 如果使用原来的mapper会抛出No content to map due to end-of-input异常