2017-01-21 25 views
0

我想序列化一个“持有人”类,其中有一个值,其类型是从泛型派生。即“类HasValue”里面有一个“私人A值”。@JsonTypeInfo不包含“@class”ID到json时,包装类也有@JsonTypeInfo

此外,我已经和接口“Inf”和一个实现该接口的具体类“InfCls”。界面用@JsonTypeInfo标记,并被告知创建一个“@class”字段。

如果持有者类没有@JsonTypeInfo就可以了。但是当我补充说它打破了。

注意:虽然在此实例中我不需要@JsonTypeInfo(因为持有者始终是一个具体类),所以在需要时会出现同样的问题,所以我选择这个作为更简单的示例。下面

SCWE:

import static org.junit.Assert.assertEquals; 

import java.util.Objects; 

import org.junit.Test; 

import com.fasterxml.jackson.annotation.JsonAutoDetect; 
import com.fasterxml.jackson.annotation.JsonCreator; 
import com.fasterxml.jackson.annotation.JsonProperty; 
import com.fasterxml.jackson.annotation.JsonTypeInfo; 
import com.fasterxml.jackson.annotation.JsonTypeInfo.As; 
import com.fasterxml.jackson.databind.JavaType; 
import com.fasterxml.jackson.databind.ObjectMapper; 

public class SerializationIssues { 

    // No @JsonTypeInfo on HasValue 
    @Test 
    public void json_HasValue_Inf_javaType() throws Exception { 
     HasValue<Inf> object = new HasValue<>(new InfCls(1)); 

     ObjectMapper objectMapper = new ObjectMapper(); 
     JavaType javaType = objectMapper.getDeserializationConfig().getTypeFactory().constructParametricType(HasValue.class, Inf.class); 
     String serialized = objectMapper.writerFor(javaType).writeValueAsString(object); 
     HasValue<?> deserialized = objectMapper.readValue(serialized, javaType); 

     assertEquals(object, deserialized); 
    } 

    // @JsonTypeInfo on HasValueId 
    @Test 
    public void json_HasValueId_Inf_javaType() throws Exception { 
     HasValueId<Inf> object = new HasValueId<>(new InfCls(1)); 

     ObjectMapper objectMapper = new ObjectMapper(); 
     JavaType javaType = objectMapper.getDeserializationConfig().getTypeFactory().constructParametricType(HasValueId.class, Inf.class); 
     String serialized = objectMapper.writerFor(javaType).writeValueAsString(object); 
     HasValueId<?> deserialized = objectMapper.readValue(serialized, javaType); 

     assertEquals(object, deserialized); 
    } 

    // ===== An interface and impl to test @JsonTypeInfo ===== 
    @JsonTypeInfo(use = JsonTypeInfo.Id.MINIMAL_CLASS, include = As.PROPERTY, property = "@class") 
    public static interface Inf { 
    } 

    @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, isGetterVisibility = JsonAutoDetect.Visibility.NONE, getterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE) 
    public static class InfCls implements Inf { 
     private int val; 

     @JsonCreator 
     public InfCls(@JsonProperty("val") int val) { 
      this.val = val; 
     } 

     @Override 
     public String toString() { 
      return "InfCls [val=" + val + "]"; 
     } 

     @Override 
     public int hashCode() { 
      return 31 * 1 + val; 
     } 

     @Override 
     public boolean equals(Object obj) { 
      if (this == obj) 
       return true; 
      if (obj == null) 
       return false; 
      if (getClass() != obj.getClass()) 
       return false; 
      InfCls other = (InfCls) obj; 
      if (val != other.val) 
       return false; 
      return true; 
     } 
    } 

    // ===== A class that has a value ===== 
    @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, isGetterVisibility = JsonAutoDetect.Visibility.NONE, getterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE) 
    public static class HasValue<A> { 
     private final A val; 

     @JsonCreator 
     public HasValue(@JsonProperty("val") A val) { 
      this.val = Objects.requireNonNull(val); 
     } 

     public A get() { 
      return val; 
     } 

     @Override 
     public String toString() { 
      return "HasValue [val=" + val + "]"; 
     } 

     @Override 
     public int hashCode() { 
      return 31 * 1 + ((val == null) ? 0 : val.hashCode()); 
     } 

     @Override 
     public boolean equals(Object obj) { 
      if (this == obj) 
       return true; 
      if (obj == null) 
       return false; 
      if (getClass() != obj.getClass()) 
       return false; 
      HasValue<?> other = (HasValue<?>) obj; 
      if (val == null) { 
       if (other.val != null) 
        return false; 
      } else if (!val.equals(other.val)) 
       return false; 
      return true; 
     } 
    } 

    @JsonTypeInfo(use = JsonTypeInfo.Id.MINIMAL_CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class") 
    @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, isGetterVisibility = JsonAutoDetect.Visibility.NONE, getterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE) 
    public static class HasValueId<A> { 
     private final A val; 

     @JsonCreator 
     public HasValueId(@JsonProperty("val") A val) { 
      this.val = Objects.requireNonNull(val); 
     } 

     public A get() { 
      return val; 
     } 

     @Override 
     public String toString() { 
      return "HasValue [val=" + val + "]"; 
     } 

     @Override 
     public int hashCode() { 
      return 31 * 1 + ((val == null) ? 0 : val.hashCode()); 
     } 

     @Override 
     public boolean equals(Object obj) { 
      if (this == obj) 
       return true; 
      if (obj == null) 
       return false; 
      if (getClass() != obj.getClass()) 
       return false; 
      HasValueId<?> other = (HasValueId<?>) obj; 
      if (val == null) { 
       if (other.val != null) 
        return false; 
      } else if (!val.equals(other.val)) 
       return false; 
      return true; 
     } 
    } 

} 

回答

0

你与正在只要遇到@JsonTypeInfo注解推出的方式自举串行器,你只要它正在消失的类型信息。

有几种方法可以解决这个问题。你可以在类中提供明确的类型信息来源:

public static class HasValueId<A extends Inf> { 
    private final A val; 

这将使杰克逊通过内省确定字段类型,找到你的第二个注解。

或者你可以用@JsonTypeInfo注释通用领域:

public static class HasValueId<A> { 
    @JsonTypeInfo(use = JsonTypeInfo.Id.MINIMAL_CLASS, include = As.PROPERTY, property = "@class") 
    private final A val; 

...这将消除对接口上的注释的需要。

完成此操作后,您将不再需要键入作者;普通老objectMapper.writeValueAsString(object);将工作。

+0

这确实解决了我的问题。感谢您的快速回复。 关于何时序列化器被“推出”有什么一般规则? –

+0

对不起,模糊的术语,但我不知道官方语言是什么。如果你看看'ObjectWriter.Prefetch.forRootType',你会发现有问题的代码。一旦找到一个多态类型,它就会“解开”序列化程序,大概是为了让动态类型优先于静态。 – teppic