parser - objectmapper java




JSON Jackson-使用自定義序列化器序列化多態類時的異常 (2)

您需要額外重寫您的CustomPetSerializer因為IPet是多態的。 這也是serialize不被調用的原因。 當調用serializeWithType時,詳細解釋這個相關的SO問題 。 例如,你的serializeWithType實現可能看起來像這樣:

@Override
public void serializeWithType(IPet value, JsonGenerator gen, 
        SerializerProvider provider, TypeSerializer typeSer) 
        throws IOException, JsonProcessingException {

  typeSer.writeTypePrefixForObject(value, gen);
  serialize(value, gen, provider); // call your customized serialize method
  typeSer.writeTypeSuffixForObject(value, gen);
}

這將為您的Human實例打印{"pet":{"type":"dog":{"age":"7"}}}

我目前正在將一些代碼從Jackson 1.x遷移到Jackson 2.5 json mapper,並且在1.x中出現了一個很長的問題。

這是設置(見下面的代碼):

  • 接口IPet
  • 類狗執行IPet
  • IPet使用@JsonTypeInfo和@JsonSubTypes進行註釋
  • 類Human具有類型IPet的屬性,用@JsonSerialize註解(使用= CustomPetSerializer.class)

問題:如果我序列化狗的一個實例,它按預期工作(類型信息也被添加到Jackson的JSON字符串)。 但是,當我序列化人類的一個實例拋出異常說:

com.fasterxml.jackson.databind.JsonMappingException:類型id處理沒有為com.pet.Dog類型實現(通過引用鏈:com.Human [“pet”])

CustomPetSerializer類的serialize(...)方法不被調用(使用斷點測試)。

代碼:

IPet實現:

@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.PROPERTY, property="type")
@JsonSubTypes({
     @JsonSubTypes.Type(value=Dog.class,    name="dog")
    //,@JsonSubTypes.Type(value=Cat.class,  name="cat")
    //more subtypes here...
})
public interface IPet
{
    public Long getId();
    public String getPetMakes();
}

狗執行:

public class Dog implements IPet
{
    @Override
    public String getPetMakes()
    {
        return "Wuff!";
    }

    @Override
    public Long getId()
    {
        return 777L;
    }
}

擁有狗的人:

public class Human
{
    private IPet pet = new Dog();

    @JsonSerialize(using=CustomPetSerializer.class)
    public IPet getPet()
    {
        return pet;
    }
}

CustomPetSerializer實現:

public class CustomPetSerializer extends JsonSerializer<IPet>
{
    @Override
    public void serialize(IPet value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException
    {
        if(value != null && value.getId() != null)
        {
            Map<String,Object> style = new HashMap<String,Object>();
            style.put("age", "7");
            gen.writeObject(style);
        }
    }
}

JUnit測試方法:

@Test
public void testPet() throws JsonProcessingException
{
    ObjectMapper mapper = new ObjectMapper();

    Human human = new Human();

    //works as expcected
    String json = mapper.writeValueAsString(human.getPet());
    Assert.assertNotNull(json);
    Assert.assertTrue(json.equals("{\"type\":\"dog\",\"id\":777,\"petMakes\":\"Wuff!\"}"));

    //throws exception: Type id handling not implemented for type com.pet.Dog (through reference chain: com.Human["pet"])
    json = mapper.writeValueAsString(human);    //exception is thrown here
    Assert.assertNotNull(json);
    Assert.assertTrue(json.contains("\"age\":\"7\""));
}

由於傑克遜2.9 writeTypePrefixForObject()writeTypeSuffixForObject()已被棄用(我不清楚為什麼)。 現在看來,按照新的方法:

@Override
public void serializeWithType(IPet value, JsonGenerator gen, 
        SerializerProvider provider, TypeSerializer typeSer) 
        throws IOException, JsonProcessingException {

  WritableTypeId typeId = typeSerializer.typeId(value, START_OBJECT);
  typeSer.writeTypePrefix(gen, typeId);
  serialize(value, gen, provider); // call your customized serialize method
  typeSer.writeTypeSuffix(gen, typeId);
}

所以現在有一個額外的行,所以不知道為什麼這是一個前進的步驟,也許是更有效地重用typeId對象。

來源:傑克遜的ObjectNode類目前在主。 不是最好的來源,但看不到任何升級文件解釋做什麼。





jackson