JSON Parsing Date with DateTimeParseException/JsonbException from ClientBuilder/WebTarget program

2.6k views Asked by At

I having problem parsing a date for JSON, when my program consumes a POST Services that contains a Body, Instead of REST client program Postman works perfectly.

Using Postman with URL http://localhost:8080/api/v1/customers/createPurchaser

enter image description here

With the Header enter image description here

The output from console of my Program client is:

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

The code of my program client (ConsumingServices class) is:

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("[email protected]");
        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);
            }
        }
    }
}

The output:

--- 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
------------------------------------------------------------------------

The Styled Output.

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

The Customer class (the all code is in this question javax.ws.rs.ProcessingException, could not find writer for content-type application/json type, in 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;
    }
}

The pom.xml dependencies of my program client are:

<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>

How can I solve this problem in my client(using ClientBuilder/WebTarget) program, if using a REST client program works fine??

1

There are 1 answers

2
Michael Gantman On

Your problem is most likely is in parsing your Customer class instance to JSON in your client program. Note that in Postman you already provide proper JSON (the one that you expect that your Customer class instance would be parsed to), but in your client program you expect your Http client code to parse your Customer class instance to JSON in this piece of code:

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

However, the date gets parsed to '653038060000' just as your error message tells you. So, I suggest first to test if my assumption is correct, to try to send your JSON text instead of Customer class instance from your client program. If my assumption is correct, this would work. If so, then you need to make sure that whichever way you parse your Customer class instance to JSON is correct. Either do it yourself using some JSON library (I suggest Jackson Json, GitHub Jackson home. Here are Maven artifacts:

            <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>

) or get your Http client Invocation.Builder to parse it correctly. To do so you might want to add in your Customer class the following annotation:

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

You might need to add the same Jackson Maven artifacts to your code. For detailed answer, see this question: Spring Data JPA - ZonedDateTime format for json serialization Also, if you are using Java 8 or above I VERY STRONGLY recommend not to use the outdated Date class (no pun intended) but switch to java.time package and use instead LocalDate class or other available classes such as LocalDateTime or ZonedDateTime or others. Finally, if you like you may try another 3d party Http Client from MgntUtils library. Here is its JavaDoc: HttpClient. The library itself you can find here as Maven Artifacts and here on the Github (including source code and Javadoc). This library does not parse classes to JSON though but can send text as the request body. (Disclaimer: this library is written by me).