在JSON请求中使用继承时发生JsonMappingException

时间:2018-07-13 15:12:04

标签: java json rest jackson aws-lambda

我有一个要求,Lambda函数应该具有通用输入。根据输入,它应该执行特定于该类型的逻辑。 基本上会有一个接口,基于输入json,它应该自动将其映射到相应的子类型。

这是我的课程

public class LambdaFunctionHandler implements RequestHandler<DemographicRequest, String> {

    @Override
    public String handleRequest(DemographicRequest input, Context context) {
        context.getLogger().log("Input: " + input);

        if (input instanceof NameRequest) {
            context.getLogger().log("Name request");
            // name specific logic and update in db
        } else if (input instanceof AddressRequest) {
            context.getLogger().log("Address Request");
            //address specific logic and update in db
        }

        // TODO: implement your handler
        return "Hello from Lambda!";
    }

}

public class AddressRequest implements DemographicRequest {

    private String addressLine1;
    private String addressLine2;
    private String street;
    private String city; 
    private String zipCode;
    private String country;

// setter and getters

}

public class NameRequest implements DemographicRequest {

    private String firstname;
    private String lastname;

//setters and getters
}

@JsonTypeInfo(use = Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "type")
@JsonSubTypes({ @Type(value = NameRequest.class), @Type(value = AddressRequest.class) })
public interface DemographicRequest {

}

当我尝试下面的输入请求时,我得到了JsonMappingException。我已经使用@JsonTypeInfo和@JsonSubTypes(不确定是否以正确的方式使用)。但是还是没用。

{
  "firstname": "fist",
  "lastname": "last"
}

Caused by: java.io.UncheckedIOException: com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of com.amazonaws.lambda.demo.model.DemographicRequest, problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information
 at [Source: lambdainternal.util.NativeMemoryAsInputStream@544fe44c; line: 1, column: 1]
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of com.amazonaws.lambda.demo.model.DemographicRequest, problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information
 at [Source: lambdainternal.util.NativeMemoryAsInputStream@544fe44c; line: 1, column: 1]
    at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148)
    at com.fasterxml.jackson.databind.DeserializationContext.instantiationException(DeserializationContext.java:892)
    at com.fasterxml.jackson.databind.deser.AbstractDeserializer.deserialize(AbstractDeserializer.java:139)
    at com.fasterxml.jackson.databind.ObjectReader._bindAndClose(ObjectReader.java:1511)
    at com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:1102)

您能帮我解决/解决这个问题吗?

1 个答案:

答案 0 :(得分:0)

错误

  

抽象类型要么需要映射到具体类型,要么具有自定义反序列化器,要么使用其他类型信息实例化

表示Jackson无法基于接口DemographicRequest解析对象。您必须提供具体的类NameRequestAddressRequest。 如果使用RequestStreamHandler并“手动”执行反序列化,则a唯一可以想到的事情。但是我承认这并不是特别优雅。 例如

public class LambdaFunctionHandler implements RequestStreamHandler {

    @Override
    public void handler(InputStream inputStream, OutputStream outputStream, Context context) throws IOException, IOException {
        context.getLogger().log("Input: " + inputStream);

        final ObjectMapper objectMapper = new ObjectMapper();

        try {
            Object input = objectMapper.readValue(inputStream, NameRequest.class);
            context.getLogger().log("Name request");
            // name specific logic and update in db
        } catch (JsonMappingException e) {
            //
        }
        try {
            Object input = objectMapper.readValue(inputStream, AddressRequest.class);
            context.getLogger().log("Address Request");
            //address specific logic and update in db
        } catch (JsonMappingException e) {
            //
        }

        // TODO: implement your handler
        outputStream.write("Hello from Lambda!".getBytes());
        outputStream.close();
    }

}

更好的方法可能是为每种类型提供单独的处理程序。