jackson mixin在序列化和反序列化时被忽略

ncecgwcz  于 2021-06-27  发布在  Java
关注(0)|答案(2)|浏览(511)

当我只有一个不能更改的接口时,我需要能够从json对象创建javapojo。我希望mixins能帮我实现这一点。我创造了一个混音,希望能工作,但不能让Jackson使用它。
看来jackson忽略了我为接口和实现定义的mixin。如果没有将mixin添加到objectmapper中,测试失败是我所期望的。
下面是显示问题的最简单示例。这些类都在各自的包中。真正的用例要复杂得多,包括接口列表。我用的是Jackson2.10.3。
对我做错了什么有什么建议吗?
提摩太
什么不起作用
接口读取器测试失败,invaliddefinitionexception:无法构造model.level4的示例(与默认构造一样,不存在任何创建者):抽象类型需要Map到具体类型、具有自定义反序列化程序或包含其他类型信息
其次,mixin为name字段定义了一个新标签(nametest),它应该反映在writevalueasstring的输出中。它输出带有标签(名称)原始值的字段。
接口

  1. public interface Level4 {
  2. public Long getId();
  3. public void setId(Long id);
  4. public String getName();
  5. public void setName(String name);
  6. }

实施

  1. public class Level4Impl implements Level4 {
  2. private Long id;
  3. private String name;
  4. @Override
  5. public Long getId() {
  6. return id;
  7. }
  8. @Override
  9. public void setId(Long id) {
  10. this.id = id;
  11. }
  12. @Override
  13. public String getName() {
  14. return name;
  15. }
  16. @Override
  17. public void setName(String name) {
  18. this.name = name;
  19. }
  20. }

混合

  1. public abstract class Level4Mixin {
  2. public Level4Mixin(
  3. @JsonProperty("id") Long id,
  4. @JsonProperty("nameTest") String name) { }
  5. }

单元测试

  1. class Level4MixinTest {
  2. private ObjectMapper mapper;
  3. @BeforeEach
  4. void setUp() throws Exception {
  5. mapper = new ObjectMapper();
  6. mapper.addMixIn(Level4.class, Level4Mixin.class);
  7. mapper.addMixIn(Level4Impl.class, Level4Mixin.class);
  8. }
  9. @Test
  10. void test_InterfaceWrite() throws JsonProcessingException {
  11. Level4 lvl4 = new Level4Impl();
  12. lvl4.setId(1L);
  13. lvl4.setName("test");
  14. String json = mapper.writeValueAsString(lvl4);
  15. assertNotNull(json);
  16. assertTrue(json.contains("nameTest"));
  17. }
  18. @Test
  19. void test_InterfaceRead() throws JsonProcessingException {
  20. String json = "{\"id\":1,\"nameTest\":\"test\"}";
  21. assertDoesNotThrow(() -> {
  22. Level4 parsed = mapper.readValue(json, Level4.class);
  23. assertNotNull(parsed);
  24. });
  25. }
  26. @Test
  27. void test_ImplWrite() throws JsonProcessingException {
  28. Level4Impl lvl4 = new Level4Impl();
  29. lvl4.setId(1L);
  30. lvl4.setName("test");
  31. String json = mapper.writeValueAsString(lvl4);
  32. assertNotNull(json);
  33. assertTrue(json.contains("nameTest"));
  34. }
  35. @Test
  36. void test_ImplRead() {
  37. String json = "{\"id\":1,\"nameTest\":\"test\"}";
  38. assertDoesNotThrow(() -> {
  39. Level4Impl parsed = mapper.readValue(json, Level4Impl.class);
  40. assertNotNull(parsed);
  41. });
  42. }
  43. }
xqkwcwgp

xqkwcwgp1#

要在序列化对象时向该对象添加属性,可以使用@jsonappend。例如:

  1. @JsonAppend(attrs = {@JsonAppend.Attr(value = "nameTest")})
  2. public class Level4Mixin {}

以及测试:

  1. @BeforeEach
  2. void setUp() throws Exception {
  3. mapper = new ObjectMapper()
  4. .addMixIn(Level4Impl.class, Level4Mixin.class);
  5. }
  6. @Test
  7. void test_ImplWrite() throws JsonProcessingException {
  8. Level4Impl lvl4 = new Level4Impl();
  9. lvl4.setId(1L);
  10. lvl4.setName("test");
  11. String json = mapper.writerFor(Level4Impl.class)
  12. .withAttribute("nameTest", "myValue")
  13. .writeValueAsString(lvl4);
  14. assertNotNull(json);
  15. assertTrue(json.contains("nameTest"));
  16. assertTrue(json.contains("myValue"));
  17. }

同样适用于 test_InterfaceWrite .
将json反序列化为对象的测试不清楚:

  1. @Test
  2. void test_ImplRead() {
  3. String json = "{\"id\":1,\"nameTest\":\"test\"}";
  4. assertDoesNotThrow(() -> {
  5. Level4Impl parsed = mapper.readValue(json, Level4Impl.class);
  6. assertNotNull(parsed);
  7. });
  8. }

班级 Level4Impl 不具有属性 nameTest 所以反序列化失败了。如果不想抛出异常,可以配置 ObjectMapper 在未知属性上不失败。例如:

  1. @Test
  2. void test_ImplRead() {
  3. String json = "{\"id\":1,\"nameTest\":\"test\"}";
  4. assertDoesNotThrow(() -> {
  5. Level4Impl parsed = new ObjectMapper()
  6. .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
  7. .readValue(json, Level4Impl.class);
  8. assertNotNull(parsed);
  9. });
  10. }
展开查看全部
vyu0f0g1

vyu0f0g12#

首先,您必须让jackson知道它应该示例化接口的哪个子类。你可以通过添加 @JsonTypeInfo 和/或 @JsonSubTypes 你在课堂上的混音注解。对于单个子类,以下内容就足够了:

  1. @JsonTypeInfo(use = Id.NAME, defaultImpl = Level4Impl.class)
  2. public abstract class Level4Mixin {
  3. }

对于多个子类,它将更加复杂,并且需要json负载中标识具体类型的额外字段。有关详细信息,请参见jackson多态反序列化。另外值得一提的是,添加类型信息将导致type id字段被写入json。仅供参考。
添加新标签就像为所需属性添加一对getter和setter一样简单。显然是原创的 name 在这种情况下,字段也将写入json。为了改变这种情况,您可能需要将@jsonignore放在getter的subclass或mix-in中。在后一种情况下,所有子类的名称都将被忽略。
最后一点:在这种情况下,你应该注册你的混音与超级类型只。
以下是对满足测试要求的类所做的更改:
级别4IMPL

  1. public class Level4Impl implements Level4 {
  2. private Long id;
  3. private String name;
  4. @Override
  5. public Long getId() {
  6. return id;
  7. }
  8. @Override
  9. public void setId(Long id) {
  10. this.id = id;
  11. }
  12. @Override
  13. public String getName() {
  14. return name;
  15. }
  16. @Override
  17. public void setName(String name) {
  18. this.name = name;
  19. }
  20. public String getNameTest() {
  21. return name;
  22. }
  23. public void setNameTest(String name) {
  24. this.name = name;
  25. }
  26. }

混合

  1. @JsonTypeInfo(use = Id.NAME, defaultImpl = Level4Impl.class)
  2. public interface Level4Mixin {
  3. @JsonIgnore
  4. String getName();
  5. }

级别4混合更改

  1. @BeforeEach
  2. void setUp() throws Exception {
  3. mapper = new ObjectMapper();
  4. mapper.addMixIn(Level4.class, Level4Mixin.class);
  5. // remove
  6. //mapper.addMixIn(Level4Impl.class, Level4Mixin.class);
  7. }
展开查看全部

相关问题