Jackson无法将JSON字符串反序列化为AWS Textract对象的问题
AWS Java SDK v2 Textract模型反序列化问题解决方案
问题描述
使用AWS Java SDK v2时,将JSON字符串反序列化为Textract的DocumentMetadata这类模型对象时,Jackson直接抛出错误,提示找不到合适的构造器(默认构造器或基于属性/委托的创建器)。由于SDK的模型类是只读的,无法添加Jackson注解;尝试过Gson也未解决,不想手动编写本地映射模型,寻求可行方案。
错误日志:
Cannot construct instance of `software.amazon.awssdk.services.textract.model.DocumentMetadata` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator) at [Source: (StringReader); line: 1, column: 57] (through reference chain: com.amazon.fdmextractionserviceextractfromdocument.data.internal.AnalyseExpenseResponse["DocumentMetadata"]): com.fasterxml.jackson.databind.exc.InvalidDefinitionException com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `software.amazon.awssdk.services.textract.model.DocumentMetadata` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator) at [Source: (StringReader); line: 1, column: 57] (through reference chain: com.amazon.fdmextractionserviceextractfromdocument.data.internal.AnalyseExpenseResponse["DocumentMetadata"]) at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67) at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1764) at com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:400) at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1209) at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1415) at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:363) at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:196) at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:129) at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:325) at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:188) at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:322) at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4593) at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3548) at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3516) at com.amazon.fdmextractionserviceextractfromdocument.data.TextractOutputBuilder.getTextractOutput(TextractOutputBuilder.kt:22) at com.amazon.fdmextractionserviceextractfromdocument.domainlogic.ExtractDataComponent.extractData(ExtractDataComponent.kt:12) at com.amazon.fdmextractionserviceextractfromdocument.service.ExtractDataActivity.extractData(ExtractDataActivity.kt:14) at com.amazon.fdmextractionserviceextractfromdocument.LambdaMain.handleRequest(LambdaMain.kt:23) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.base/java.lang.reflect.Method.invoke(Unknown Source)
可行解决方案
1. 使用AWS SDK自带的Jackson模块(最省心)
AWS SDK v2专门提供了适配自身模型的Jackson模块,直接用它就能解决构造器兼容问题,无需修改任何代码。
操作步骤:
- 添加Maven依赖(版本需与你的AWS SDK保持一致):
<dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>jackson-databind</artifactId> <version>${aws.sdk.version}</version> </dependency>
- 初始化适配SDK模型的ObjectMapper:
import com.fasterxml.jackson.databind.ObjectMapper; import software.amazon.awssdk.core.serialization.json.JsonSdkSerializer; // 用SDK工具创建适配的ObjectMapper ObjectMapper awsObjectMapper = JsonSdkSerializer.builder().build().objectMapper(); // 直接执行反序列化 String jsonContent = "你的JSON字符串"; AnalyseExpenseResponse response = awsObjectMapper.readValue(jsonContent, AnalyseExpenseResponse.class);
该模块会自动识别SDK模型的Builder构造逻辑,完美适配反序列化流程。
2. 使用SDK内置的Json解析器(兼容性最强)
如果不想依赖Jackson,可以直接用SDK自身的解析器,完全贴合模型的序列化逻辑:
import software.amazon.awssdk.core.SdkBytes; import software.amazon.awssdk.services.textract.model.DocumentMetadata; import software.amazon.awssdk.core.serialization.json.JsonSdkParser; // 将JSON字符串转为SDK标准字节格式 SdkBytes jsonBytes = SdkBytes.fromUtf8String(jsonContent); // 创建SDK原生解析器 JsonSdkParser parser = JsonSdkParser.create(); // 直接解析为目标模型对象 DocumentMetadata metadata = parser.parse(jsonBytes, DocumentMetadata.SDK_DESERIALIZER);
这种方式不需要第三方库,完全依赖SDK自身能力,不存在兼容性问题。
3. 给自定义类的SDK字段添加Jackson反序列化器(局部适配)
如果只是你的自定义类(比如AnalyseExpenseResponse)中包含SDK模型字段,可以给该字段单独编写反序列化器:
import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import software.amazon.awssdk.core.SdkBytes; import software.amazon.awssdk.core.serialization.json.JsonSdkParser; import software.amazon.awssdk.services.textract.model.DocumentMetadata; // 自定义反序列化器 public class DocumentMetadataDeserializer extends JsonDeserializer<DocumentMetadata> { @Override public DocumentMetadata deserialize(com.fasterxml.jackson.core.JsonParser p, DeserializationContext ctxt) throws IOException { // 将JSON节点转为字符串 String json = p.readValueAsTree().toString(); // 用SDK解析器处理 JsonSdkParser parser = JsonSdkParser.create(); return parser.parse(SdkBytes.fromUtf8String(json), DocumentMetadata.SDK_DESERIALIZER); } } // 在自定义类中标记字段使用该反序列化器 public class AnalyseExpenseResponse { @JsonDeserialize(using = DocumentMetadataDeserializer.class) private DocumentMetadata documentMetadata; // getter和setter方法 }
这样既无需修改SDK类,也能让Jackson正确解析该字段。
为什么Gson不好用?
Gson默认要求类有公开无参构造器或可直接赋值的字段,但AWS SDK v2的模型均为不可变对象,采用Builder模式创建,没有公开字段和无参构造器,因此直接用Gson无法解析。如果非要用Gson,需要为每个SDK模型编写TypeAdapter,工作量与手动编写本地模型相当,不如上述方案高效。
内容的提问来源于stack exchange,提问作者Sudhanshu Bhoi
相关产品推荐
相关产品推荐

