在jackson中反序列化嵌套对象

8hhllhi2  于 2021-09-13  发布在  Java
关注(0)|答案(0)|浏览(727)

这应该是直截了当的基于我所看到的文档和例子,但我还没有设法让这个工作。我很抱歉,如果这已经张贴在其他地方,但我还没有找到相同的问题,即使它涉及到与jackson库的嵌套对象反序列化。
主要项目:
jackson解析器正在尝试将嵌套对象Map到linkedhashmap,而不是实际的对象/类类型
使用第三方类,因此不可能有注解
json数据不可修改,因为它是在别处生成的
基本上,我的json是从gcp日志生成的,如下所示(为了可读性而简化):

  1. {
  2. "logName": "projects/my_project_id/logs/stdout",
  3. "severity": "ERROR",
  4. "timestamp": "2021-07-25T01:32:56.371417530Z",
  5. "receiveTimestamp": "2021-07-25T01:33:01.118327598Z",
  6. "jsonPayload": {
  7. "message": "application log message"
  8. },
  9. "resource": {
  10. "type": "gce_instance",
  11. "labels": {
  12. "project_id": "my_project_id",
  13. "instance_id": "my_instance_id",
  14. "zone": "my_zone"
  15. }
  16. },
  17. "operation": {
  18. "first": true,
  19. "id": "<operation_id>",
  20. "producer": "producer_name"
  21. }
  22. }

使用jackson数据绑定库,我试图将其解析并反序列化为java对象。
在我使用gcp时,google为这些日志对象提供了库。即com.google.api.services.logging.v2.model.logentry及其相关对象,如httprequest、logentryoperation等。该对象主要有字符串、整数和Map等简单对象,但也有一些是上述对象(httprequest、logentryoperation等)。
例如

  1. public final class LogEntry extends GenericJson {
  2. private HttpRequest httpRequest;
  3. private String insertId;
  4. private Map<String, Object> jsonPayload;
  5. private Map<String, String> labels;
  6. private String logName;
  7. private MonitoredResourceMetadata metadata;
  8. private LogEntryOperation operation;
  9. ...
  10. }

从我所看到的文档和示例来看,使用readvalue方法并将我要Map到的类传递给它应该非常简单,如下所示:

  1. byte[] data = jsonString.getBytes();
  2. ObjectMapper mapper = new ObjectMapper();
  3. mapper.readValue(new ByteArrayInputStream(data), LogEntry.class);

但是我得到了这个错误:

  1. com.fasterxml.jackson.databind.JsonMappingException: Can not set com.google.api.services.logging.v2.model.LogEntryOperation field com.google.api.services.logging.v2.model.LogEntry.operation to java.util.LinkedHashMap (through reference chain: com.google.api.services.logging.v2.model.LogEntry["operation"])

对于logentry类中的每个嵌套对象都会发生这种情况。为了确认,我克隆了logentry类,并将这些对象(比如logentryoperation)更新为一个Map,并且它能够工作。
现在的问题是,我不想克隆这个类,因为它是库的一部分,而且我也不能更改gcp中的数据。
我还尝试对objectmapper使用config(序列化功能和反序列化功能),但找不到任何有帮助的东西。我假设当您将类作为参数传递时,jackson解析器能够确定嵌套对象。
我是否缺少一个配置或什么?或者使用jackson解析器不可能做到这一点?
谢谢
编辑1:完整的堆栈跟踪:

  1. com.abc.logging.data.parsing.LogEntryParser$LogParseException: Failed to parse class com.google.api.services.logging.v2.model.LogEntry value from json payload
  2. at com.abc.logging.data.parsing.LogEntryParser.parse(LogEntryParser.java:87)
  3. at com.abc.logging.data.parsing.LogEntryParser.parse(LogEntryParser.java:34)
  4. at com.abc.logging.data.parsing.LogEntryParserTest.testMapper(LogEntryParserTest.java:191)
  5. at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  6. at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
  7. at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  8. at java.base/java.lang.reflect.Method.invoke(Method.java:566)
  9. at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
  10. at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
  11. at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
  12. at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
  13. at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
  14. at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
  15. at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
  16. at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
  17. at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
  18. at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
  19. at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
  20. at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
  21. at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
  22. at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
  23. at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:365)
  24. at org.apache.maven.surefire.junit4.JUnit4Provider.executeWithRerun(JUnit4Provider.java:273)
  25. at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:238)
  26. at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:159)
  27. at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:379)
  28. at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:340)
  29. at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:125)
  30. at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:413)
  31. Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not set com.google.api.services.logging.v2.model.LogEntryOperation field com.google.api.services.logging.v2.model.LogEntry.operation to java.util.LinkedHashMap (through reference chain: com.google.api.services.logging.v2.model.LogEntry["operation"])
  32. at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:397)
  33. at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:356)
  34. at com.fasterxml.jackson.databind.deser.std.ContainerDeserializerBase.wrapAndThrow(ContainerDeserializerBase.java:181)
  35. at com.fasterxml.jackson.databind.deser.std.MapDeserializer._readAndBindStringKeyMap(MapDeserializer.java:552)
  36. at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:377)
  37. at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:29)
  38. at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4524)
  39. at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3503)
  40. at com.abc.logging.data.parsing.LogEntryParser.parse(LogEntryParser.java:81)
  41. ... 28 more
  42. Caused by: java.lang.IllegalArgumentException: Can not set com.google.api.services.logging.v2.model.LogEntryOperation field com.google.api.services.logging.v2.model.LogEntry.operation to java.util.LinkedHashMap
  43. at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
  44. at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
  45. at java.base/jdk.internal.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:81)
  46. at java.base/java.lang.reflect.Field.set(Field.java:780)
  47. at com.google.api.client.util.FieldInfo.setFieldValue(FieldInfo.java:275)
  48. at com.google.api.client.util.FieldInfo.setValue(FieldInfo.java:231)
  49. at com.google.api.client.util.GenericData.put(GenericData.java:98)
  50. at com.google.api.client.util.GenericData.put(GenericData.java:43)
  51. at com.fasterxml.jackson.databind.deser.std.MapDeserializer._readAndBindStringKeyMap(MapDeserializer.java:547)
  52. ... 33 more
  53. [ERROR] Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 1.583 s <<< FAILURE! - in com.abc.logging.data.parsing.LogEntryParserTest
  54. [ERROR] testMapper(com.abc.logging.data.parsing.LogEntryParserTest) Time elapsed: 0.904 s <<< FAILURE!
  55. java.lang.AssertionError
  56. at com.abc.logging.data.parsing.LogEntryParserTest.testMapper(LogEntryParserTest.java:212)

编辑2:我尝试将mixin与@jsondeserialize和单独的反序列化类一起用于这些对象,但它似乎没有调用反序列化类。它仍然失败,但有相同的例外。
mixin类:

  1. public abstract class LogEntryOperationMixin {
  2. @JsonDeserialize(using = MyLogEntryOpDeserializer.class)
  3. private LogEntryOperation operation;
  4. }

反序列化类:

  1. public class MyLogEntryOpDeserializer extends JsonDeserializer<LogEntryOperation> {
  2. @Override
  3. public LogEntryOperation deserialize(JsonParser parser, DeserializationContext deserializer) {
  4. LogEntryOperation entryOperation = new LogEntryOperation();
  5. // ... populate with data
  6. return entryOperation;
  7. }
  8. }

我的主要班级:

  1. ObjectMapper mapper = new ObjectMapper();
  2. mapper.addMixIn(LogEntry.class, LogEntryOperationMixin.class);
  3. mapper.readValue(jsonData, LogEntry.class);

暂无答案!

目前还没有任何答案,快来回答吧!

相关问题