Дата анализа JSON с DateTimeParseException / JsonbException из программы ClientBuilder/WebTarget

У меня проблема с синтаксическим анализом даты для JSON, когда моя программа потребляет POST Услуги, содержащие Body, Вместо того REST клиентская программа Postman работает отлично.

Использование Postman с URL http: // localhost:8080 / api / v1 / customers / createPurchaser

С заголовком

Вывод с консоли моего программного клиента:

java.time.format.DateTimeParseException: текст 653038060000 не удалось проанализировать с индексом 0

Код моего программного клиента (ConsumingServices class) это:

import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.Invocation;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

public class ConsumingServices {

    public static void main(String[] args) {
        Customer customer = new Customer();
        customer.setFirstName("John");
        customer.setLastName("Mason");
        customer.setEmail("john.mason@mail.com");
        customer.setDateOfBirth(new Date());
        customer.setStatus(CustomerStatus.ACTIVE);
        
        ClientBuilder clientBuilder = ClientBuilder.newBuilder();
        clientBuilder.connectTimeout(1000, TimeUnit.SECONDS);
        clientBuilder.readTimeout(1000, TimeUnit.SECONDS);
        Client client = clientBuilder.build();

        WebTarget target = client.target("http://localhost:8080/api/v1/customers");

        Invocation.Builder invocationBuilder = target.path("createPurchaser")
                .request(MediaType.APPLICATION_JSON)
                .accept(MediaType.APPLICATION_JSON)
                ;

        Response response = invocationBuilder
                .header("Authorization", "1234")
                .post(Entity.entity(customer, MediaType.APPLICATION_JSON));

        System.out.println("response.getStatus():" + response.getStatus());
        if (response.getStatus() == Response.Status.OK.getStatusCode()) {
            Purchaser purchaser = response.readEntity(Purchaser.class);
            System.out.println("purchaser:".concat(purchaser.toString()));
        } else {
            if (MediaType.TEXT_PLAIN_TYPE.equals(response.getMediaType())) {
                String message = response.readEntity(String.class);
                System.out.println("message:" + message);
            } else if (MediaType.APPLICATION_JSON.equals(response.getMediaType())) {
                ApiError apiError = response.readEntity(ApiError.class);
                System.out.println("apiError:".concat(apiError.toString()));
            } else {
                System.out.println("response.getMediaType():" + response.getMediaType());
                String content = response.readEntity(String.class);
                System.out.println("message:" + content);
            }
        }
    }
}

Выход:

--- exec-maven-plugin:1.5.0:exec (default-cli) @ acme-customers-client ---
response.getStatus():500

response.getMediaType():text/html
message:<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><title>Payara Server  5.2020.3 #badassfish - Error report</title><style type="text/css"><!--H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}A {color : black;}HR {color : #525D76;}--></style> </head><body><h1>HTTP Status 500 - Internal Server Error</h1><hr/><p><b>type</b> Exception report</p><p><b>message</b>Internal Server Error</p><p><b>description</b>The server encountered an internal error that prevented it from fulfilling this request.</p><p><b>exception</b> <pre>javax.servlet.ServletException: javax.ws.rs.ProcessingException: Error deserializing object from entity stream.</pre></p><p><b>root cause</b> <pre>javax.ws.rs.ProcessingException: Error deserializing object from entity stream.</pre></p><p><b>root cause</b> <pre>javax.json.bind.JsonbException: Unable to deserialize property &#39;dateOfBirth&#39; because of: Error parsing class java.util.Date from value: 1599180453470. Check your @JsonbDateFormat has all time units for class java.util.Date type, or consider using org.eclipse.yasson.YassonConfig#ZERO_TIME_PARSE_DEFAULTING.</pre></p><p><b>root cause</b> <pre>javax.json.bind.JsonbException: Error parsing class java.util.Date from value: 1599180453470. Check your @JsonbDateFormat has all time units for class java.util.Date type, or consider using org.eclipse.yasson.YassonConfig#ZERO_TIME_PARSE_DEFAULTING.</pre></p><p><b>root cause</b> <pre>java.time.format.DateTimeParseException: Text &#39;1599180453470&#39; could not be parsed at index 0</pre></p><p><b>note</b> <u>The full stack traces of the exception and its root causes are available in the Payara Server  5.2020.3 #badassfish logs.</u></p><hr/><h3>Payara Server  5.2020.3 #badassfish</h3></body></html>
------------------------------------------------------------------------
BUILD SUCCESS
------------------------------------------------------------------------
Total time:  5.574 s
Finished at: 2020-09-03T19:47:36-05:00
------------------------------------------------------------------------

Стилизованный вывод.

type Exception report

messageInternal Server Error

descriptionThe server encountered an internal error that prevented it from fulfilling this request.

exception

javax.servlet.ServletException: javax.ws.rs.ProcessingException: Error deserializing object from entity stream.
root cause

javax.ws.rs.ProcessingException: Error deserializing object from entity stream.
root cause

javax.json.bind.JsonbException: Unable to deserialize property 'dateOfBirth' because of: Error parsing class java.util.Date from value: 653038060000. Check your @JsonbDateFormat has all time units for class java.util.Date type, or consider using org.eclipse.yasson.YassonConfig#ZERO_TIME_PARSE_DEFAULTING.
root cause

javax.json.bind.JsonbException: Error parsing class java.util.Date from value: 653038060000. Check your @JsonbDateFormat has all time units for class java.util.Date type, or consider using org.eclipse.yasson.YassonConfig#ZERO_TIME_PARSE_DEFAULTING.
root cause

java.time.format.DateTimeParseException: Text '653038060000' could not be parsed at index 0

В Customerclass (весь код находится в этом вопросе javax.ws.rs.ProcessingException, не удалось найти писателя для приложения типа содержимого / типа json в Payara Server 5)

import java.io.Serializable;
import java.util.Date;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Customer extends BaseType implements Serializable {

    private String firstName;
    private String lastName;
    private CustomerStatus status;
    private String email;
    private Date dateOfBirth;

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public CustomerStatus getStatus() {
        return status;
    }

    public void setStatus(CustomerStatus status) {
        this.status = status;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Date getDateOfBirth() {
        return dateOfBirth;
    }

    public void setDateOfBirth(Date dateOfBirth) {
        this.dateOfBirth = dateOfBirth;
    }
}

В pom.xml зависимости моего программного клиента:

<dependencies>
    <dependency>
        <groupId>com.acme</groupId>
        <artifactId>acme-customers-lib</artifactId>
        <version>1.0.0-SNAPSHOT</version>
    </dependency>
    
    <!-- https://mvnrepository.com/artifact/org.glassfish.jersey.core/jersey-client -->
    <dependency>
        <groupId>org.glassfish.jersey.core</groupId>
        <artifactId>jersey-client</artifactId>
        <version>2.31</version>
    </dependency>
    
    <!-- https://mvnrepository.com/artifact/org.glassfish.jersey.inject/jersey-hk2 -->
    <dependency>
        <groupId>org.glassfish.jersey.inject</groupId>
        <artifactId>jersey-hk2</artifactId>
        <version>2.31</version>
    </dependency>
    
    <!-- https://mvnrepository.com/artifact/org.glassfish.jersey.media/jersey-media-json-jackson -->
    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-json-jackson</artifactId>
        <version>2.31</version>
    </dependency>
</dependencies>

Как я могу решить эту проблему в моем клиенте (используя ClientBuilder/WebTarget) программа, при использовании REST клиентская программа работает нормально??

0 ответов

Ваша проблема, скорее всего, в разборе вашего Customerэкземпляр класса в JSON в вашей клиентской программе. Обратите внимание, что в Postman вы уже предоставляете правильный JSON (тот, который вы ожидаете, что ваш Customer class будет анализироваться в), но в вашей клиентской программе вы ожидаете, что код клиента Http будет анализировать ваш Customer экземпляр класса в JSON в этом фрагменте кода:

       Response response = invocationBuilder
            .header("Authorization", "1234")
            .post(Entity.entity(customer, MediaType.APPLICATION_JSON));

Однако дата анализируется на "653038060000", как и указано в сообщении об ошибке. Итак, я предлагаю сначала проверить правильность моего предположения, чтобы попытаться отправить текст JSON вместо Customerэкземпляр класса из вашей клиентской программы. Если мое предположение верно, это сработает. Если это так, то вам нужно убедиться, что каким бы способом вы не анализировали Customerэкземпляр класса в JSON правильный. Либо сделайте это самостоятельно, используя какую-нибудь библиотеку JSON (я предлагаю Jackson Json, GitHub Jackson home. Вот артефакты Maven:

                   <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-jsr310</artifactId>
    </dependency>

) или получите свой Http-клиент Invocation.Builderчтобы правильно его разобрать. Для этого вы можете добавить в свой класс Customer следующую аннотацию:

          @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ")
   private Date dateOfBirth;

Возможно, вам потребуется добавить в код те же артефакты Jackson Maven. Для получения подробного ответа см. Этот вопрос: Spring Data JPA - Формат ZonedDateTime для сериализации json. Кроме того, если вы используете Java 8 или выше, я ОЧЕНЬ НАСТОЯТЕЛЬНО рекомендую не использовать устаревшие Date класс (без каламбура), но переключитесь на java.timepackage и используйте вместо него класс LocalDate или другие доступные классы, такие как LocalDateTime или же ZonedDateTimeили другие. Наконец, если хотите, можете попробовать другой сторонний Http-клиент из библиотеки MgntUtils. Вот его JavaDoc: HttpClient. Саму библиотеку вы можете найти здесь как Maven Artifacts и здесь, в Github (включая исходный код и Javadoc). Эта библиотека не анализирует классы в JSON, но может отправлять текст в качестве тела запроса. (Отказ от ответственности: эта библиотека написана мной).

Другие вопросы по тегам