【问题标题】:Jackson mixin selection and inheritanceJackson mixin的选择与继承
【发布时间】:2023-04-11 04:06:01
【问题描述】:

我对 Jackson 的 mixin 和继承有疑问。我有两个目标班级,一个父母和一个孩子。对于这两个目标类,我定义了两个相互没有继承关系的 MixIn 类(接口)。我还使用一个扩展另一个 MixIn 接口进行了测试,但结果没有区别。当 Jackson 序列化父类时,它使用正确定义的 mixin 进行序列化配置,并且一切正常。然而,当 Jackson 序列化子类时,它将使用父类 mixin 定义来序列化存在于父类和子类中的属性。然后它使用子类 mixin 定义来序列化在子类中定义但不在父类中定义的属性。现在这可能与比较基类或在 Jackson 中实现接口有关。

现在的问题是,当序列化子类的对象时,有什么方法可以指示 Jackson 仅使用子类的 mixin 定义?是的,我想为两个单独的用例保留两个 mixin 定义,所以仅仅删除父类 mixin 映射并不能解决我的问题。

下面的示例代码以及预期和实际输出的 JSON。

环境: 杰克逊版本 2.1.4 Tomcat 版本 7.0.34.0

它们实现的目标类和接口:

public interface TestI {

  public String getName();  
}


public interface TestExtendI extends TestI {

   public Integer getAge(); 
}


public class Test implements TestI {

  String name;

  public Test(String name) {
    this.name = name;
  }

  @Override
  public String getName() {
    return name;
  }  
}

public class TestExtend extends Test implements TestExtendI {

  private Integer age;

  public TestExtend(String name) {
    super(name);
  }

  public TestExtend(String name, Integer age) {
    super(name);
    this.age = age;
  }

  @Override
  public Integer getAge() {
    return age;
  }
}

混合定义

public interface TestMixIn {

  @JsonProperty("base-name")
  public String getName();
}


public interface TestExtendMixIn {

  @JsonProperty("ext-name")
  public String getName();

  @JsonProperty("ext-age")
  public Integer getAge();
}

如果两个 mixin 都添加到映射器中,则输出 JSON 为:

{
  "base-name": "5", // from parent class mixin definition
  "ext-age": 50     // from child class mixin defition
}

使用 TestI.class 的 mixin 注释一切都按预期工作,输出 JSON 是(这是我想要实现的):

{
  "ext-name": "5",  // from child class mixin defition
  "ext-age": 50     // from child class mixin defition
}

对象映射器配置

@Provider
@Produces(MediaType.APPLICATION_JSON)
public class JacksonObjectMapper implements ContextResolver<ObjectMapper> {

  private ObjectMapper mapper;

  public JacksonObjectMapper() {
    mapper = new ObjectMapper();
    mapper.addMixInAnnotations(TestI.class, TestMixIn.class);
    mapper.addMixInAnnotations(TestExtendI.class, TestExtendMixIn.class);    
  }  

  public ObjectMapper getContext(Class<?> type) { 
    return this.mapper; 
  }
}

用于处理请求/响应的 REST api

@Path("api/test/{id}")
public class TestRestApi {
  @GET
  @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
  public TestI getTest(@PathParam("id") String id) {

    TestI ret = new TestExtend(id, 50);    
    return ret;
  }
}

解决方案

正如 pgelinas 在第一个响应中所描述的,解决此问题的方法是在子接口中再次定义应由“子”混入处理的方法。对于上面的示例代码,这意味着对 TestExtendI 接口的更改:

public interface TestExtendI extends TestI {

  public Integer getAge();

  // override the method from the parent interface here
  @Override
  public String getName();
}

这将解决问题,并且不会在解决方案中添加太多样板代码。而且它不会改变接口契约,因为子接口已经扩展了父接口。

【问题讨论】:

    标签: jackson


    【解决方案1】:

    这是一个棘手的问题;您的具体问题的答案是否定的,您不能告诉子类不要使用应用于父类的 Mixin。

    但是,这里解决您的问题的一个简单方法是在 TestExtendI 接口中重新声明 getName() 方法。我相信 MixIn 注释解析不遵循通常的父子覆盖(就像普通注释的情况一样),而是更喜欢应用于声明方法的类的 MixIn。这可能是 Jackson 的错误或设计选择,您可以随时在 github 上填写问题。

    【讨论】:

      猜你喜欢
      • 2014-12-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-04
      • 1970-01-01
      • 1970-01-01
      • 2013-08-12
      • 2010-10-19
      相关资源
      最近更新 更多