反序列化 属性 'created' 时出现问题(预期类型:[简单类型,class java.time.LocalDate]

Problem deserializing property 'created' (expected type: [simple type, class java.time.LocalDate]

我使用集成 class,其中测试失败。下面提供了class,

public class EllaServiceIntegrationTest {

    private static final String ELLA_JSON_RESPONSE_FRAUD = "{\n" + "    \"score\": 707,\n" + "    \"reason\": \"DOMAIN_DOES_NOT_EXIST\",\n"
                                                           + "    \"riskBand\": 4,\n" + "    \"email\": {\n"
                                                           + "        \"emailAddress\": \"fraudster@fraud.com\",\n"
                                                           + "        \"exists\": 4,\n"
                                                           + "        \"firstVerificationDate\": \"2019-05-31T19:08:20.7713155Z\",\n"
                                                           + "        \"firstVerificationDays\": 0,\n" + "        \"totalHits\": 31,\n"
                                                           + "        \"uniqueHits\": 1,\n" + "        \"score\": {\n"
                                                           + "            \"reason\": \"DOMAIN_DOES_NOT_EXIST\",\n"
                                                           + "            \"riskLevel\": 6,\n" + "            \"relevantInfoId\": 10900\n"
                                                           + "        }\n" + "    },\n" + "    \"domain\": {},\n" + "    \"phone\": {},\n"
                                                           + "    \"shipAddress\": {\n" + "        \"addressCheck\": 4,\n"
                                                           + "        \"score\": {\n"
                                                           + "            \"reason\": \"SHIPADDRESS_NOT_COMPLETE\",\n"
                                                           + "            \"riskLevel\": 6,\n" + "            \"relevantInfoId\": 40950\n"
                                                           + "        }\n" + "    },\n" + "    \"billingAddress\": {\n"
                                                           + "        \"addressCheck\": 4,\n" + "        \"score\": {\n"
                                                           + "            \"reason\": \"BILLADDRESS_NOT_COMPLETE\",\n"
                                                           + "            \"riskLevel\": 6,\n" + "            \"relevantInfoId\": 50950\n"
                                                           + "        }\n" + "    },\n" + "    \"transaction\": {\n"
                                                           + "        \"isPrepaid\": false,\n" + "        \"cardType\": 6,\n"
                                                           + "        \"score\": {\n"
                                                           + "            \"reason\": \"MODERATE_RISK_TRANSACTION\",\n"
                                                           + "            \"riskLevel\": 3,\n" + "            \"relevantInfoId\": 69999\n"
                                                           + "        }\n" + "    },\n" + "    \"device\": {},\n" + "    \"ip\": {},\n"
                                                           + "    \"service\": {\n" + "        \"existingCustomer\": false,\n"
                                                           + "        \"score\": {\n"
                                                           + "            \"reason\": \"MODERATE_RISK_SERVICE_DETAILS\",\n"
                                                           + "            \"riskLevel\": 3,\n" + "            \"relevantInfoId\": 79999\n"
                                                           + "        }\n" + "    },\n"
                                                           + "    \"correlationId\": \"efc8a177-94d2-4a01-bd4f-af3b0e33be26\",\n"
                                                           + "    \"version\": \"1.0\",\n"
                                                           + "    \"created\": \"2019-05-31T19:08:20.7712944Z\",\n"
                                                           + "    \"status\": \"SUCCESSFUL\"\n" + "}";

    private static final String ELLA_JSON_RESPONSE_NON_FRAUD =
            "{\"status\":\"SUCCESSFUL\",\"result\":{\"cutoff\":0.5,\"classification\":\"non_fraud\",\"non_fraud_proba\":0.5176171064376831,"
            + "\"fraud_proba\":0.4823829233646393}}";

    private final static String ELLA_ENDPOINT = "/ella-web/api/v1/score";

    private EllaService ellaService;

    @Rule
    public WireMockRule wireMockRule = new WireMockRule( wireMockConfig().dynamicPort() );

    @Before
    @SuppressWarnings( "resource" )
    public void setup() {
        int port = wireMockRule.port();

        System.setProperty( "ella.uri", "http://localhost:" + port + ELLA_ENDPOINT );
        System.setProperty( "ella.internal.customer.filter", String.valueOf( false ) );
        System.setProperty( "ella.external.customer.filter", String.valueOf( false ) );
        System.setProperty( "ella.shop.id.filter", "123456,56789,545334" );

        ApplicationContext context = new AnnotationConfigApplicationContext( EllaConfiguration.class );
        ellaService = context.getBean( EllaService.class );
    }

    @Test
    public void testInvokeEllaCallsEllaWithRatepayHeadersAsyncCall() {

        wireMockRule.stubFor( post( urlEqualTo( ELLA_ENDPOINT ) ).withHeader( ACCEPT, equalTo( APPLICATION_JSON_UTF8_VALUE ) )
                                      .willReturn( okJson( ELLA_JSON_RESPONSE_FRAUD ) ) );

        IrisBo irisBo = EllaTestDataProvider.createValidIrisBoWithRequest();
        ellaService.invokeEllaAsync( irisBo );

        verify( postRequestedFor( urlEqualTo( ELLA_ENDPOINT ) )
                        .withHeader( RatepayHeaders.HEADER_GATEWAY_REQUEST_ID, equalTo( EllaTestConstants.VALID_GATEWAY_ID ) )
                        .withHeader( RatepayHeaders.HEADER_TRANSACTION_ID, equalTo( EllaTestConstants.VALID_TRX_ID ) ) );
    }

}

我得到下面提供的错误堆栈,

com.ratepay.iris.ella.dto.response.EllaGatewayUnsuccessfulResponseException: Problem deserializing property 'created' (expected type: [simple type, class java.time.LocalDate]; actual type: `java.time.OffsetDateTime`), problem: argument type mismatch
 at [Source: (String)"{
    "score": 707,
    "reason": "DOMAIN_DOES_NOT_EXIST",
    "riskBand": 4,
    "email": {
        "emailAddress": "fraudster@fraud.com",
        "exists": 4,
        "firstVerificationDate": "2019-05-31T19:08:20.7713155Z",
        "firstVerificationDays": 0,
        "totalHits": 31,
        "uniqueHits": 1,
        "score": {
            "reason": "DOMAIN_DOES_NOT_EXIST",
            "riskLevel": 6,
            "relevantInfoId": 10900
        }
    },
    "domain": {},
    "phone": {},
    "s"[truncated 1013 chars]; line: 57, column: 16] (through reference chain: com.ratepay.iris.ella.dto.response.EllaResponseDto["created"])

    at com.ratepay.iris.ella.service.EllaService.invokeEllaAsync(EllaService.java:95)
    at 

com.ratepay.iris.ella.service.EllaServiceIntegrationTest.testInvokeEllaCallsEllaWithRatepayHeadersAsyncCall(EllaServiceIntegrationTest.java:108)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:50)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
        at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
        at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
        at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
        at com.github.tomakehurst.wiremock.junit.WireMockRule.evaluate(WireMockRule.java:73)
        at org.junit.rules.RunRules.evaluate(RunRules.java:20)
        at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:290)
        at org.junit.runners.ParentRunner.schedule(ParentRunner.java:71)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
        at org.junit.runners.ParentRunner.access[=15=]0(ParentRunner.java:58)
        at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:268)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
        at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
        at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
        at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
        at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
        at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
    Caused by: java.lang.IllegalArgumentException: argument type mismatch
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:139)
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:288)
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:151)
        at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4013)
        at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3004)
        at com.ratepay.commons.web.util.io.http.connector.RequestExecutor.createResponseWithBody(RequestExecutor.java:309)
        at com.ratepay.commons.web.util.io.http.connector.RequestExecutor.createSucessfulResponse(RequestExecutor.java:298)
        at com.ratepay.commons.web.util.io.http.connector.RequestExecutor.createResponse(RequestExecutor.java:284)
        at com.ratepay.commons.web.util.io.http.connector.RequestExecutor.submit(RequestExecutor.java:123)
        at com.ratepay.commons.web.util.io.http.connector.RequestExecutor.submitRequest(RequestExecutor.java:89)
        at com.ratepay.commons.web.util.io.http.connector.ServiceConnector.doCall(ServiceConnector.java:210)
        at com.ratepay.commons.web.util.io.http.connector.ServiceConnector.call(ServiceConnector.java:125)
        at com.ratepay.iris.ella.service.EllaService.callEllaService(EllaService.java:128)
        at com.ratepay.iris.ella.service.EllaService.invokeEllaAsync(EllaService.java:92)

它显然是由 ELLA_JSON_RESPONSE_FRAUD 中定义的返回响应的 + " \"created\": \"2019-05-31T19:08:20.7712944Z\",\n" 行构成的。

我提供了一个响应 DTO 示例来显示时间值定义,

@JsonInclude( JsonInclude.Include.NON_NULL )
@Getter
@Setter
public class EllaResponseDto extends BaseDto {

    private String trackingId;

    private Integer score;

    private String reason;

    private Integer riskBand;

    private EmailDto email;

    private DomainDto domain;

    private PhoneDto phone;

    private AddressDto shipAddress;

    private AddressDto billingAddress;

    private TransactionDto transaction;

    private DeviceDto device;

    private IpDto ip;

    private ServiceDto service;

    private String correlationId;

    private String version;

    @JsonDeserialize( using = JavaOffsetDateTimeDeserializer.class )
    @JsonSerialize( using = JavaOffsetDateTimeSerializer.class )
    private LocalDate created;

    private EllaStatus status;
}

如果我正确理解问题,它在错误堆栈中表示为 Problem deserializing property 'created' (expected type: [simple type, class java.time.LocalDate]; actual type:java.time.OffsetDateTime), problem: argument type mismatch

为了解决这种情况,我将创建日期定义为 private LocalDate created,带有注释的序列化和反序列化选项。显然,这是行不通的。

我该如何解决这个问题?

@JsonDeserialize( using = JavaOffsetDateTimeDeserializer.class )
@JsonSerialize( using = JavaOffsetDateTimeSerializer.class )
private LocalDate created;

Deserializer 将字符串转换为 Offsetdatetime 但创建的数据类型是 LocalDate,我认为从测试数据“2019-05-31T19:08:20.7712944Z”(包括区域)来看,您应该使用 OffsetDateTime 而不是 LocalDate

我找到了解决问题的方法。我需要从

更改所有 DTO 类 的注释
@JsonDeserialize( using = JavaOffsetDateTimeDeserializer.class )
@JsonSerialize( using = JavaOffsetDateTimeSerializer.class )

@JsonSerialize( using = LocalDateSerializer.class )
@JsonDeserialize( using = LocalDateDeserializer.class )

现在测试通过了。