java - 来自 ClientBuilder/WebTarget 程序的带有 DateTimeParseException/JsonbException 的 JSON 解析日期
问题描述
JSON
当我的程序使用POST
包含Body
, 而不是REST
客户端程序的服务时,我在解析日期时遇到问题Postman
。
使用带有 URL http://localhost:8080/api/v1/customers/createPurchaser 的 Postman
我的程序客户端控制台的输出是:
java.time.format.DateTimeParseException:无法在索引 0 处解析文本“653038060000”
我的程序客户端(ConsumingServices
类)的代码是:
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 'dateOfBirth' 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 '1599180453470' 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
类Customer
(所有代码都在这个问题javax.ws.rs.ProcessingException 中,在 Payara Server 5 中找不到内容类型应用程序/json 类型的编写器)
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 客户端程序可以正常工作??
解决方案
您的问题很可能是在Customer
您的客户端程序中将您的类实例解析为 JSON。请注意,在 Postman 中,您已经提供了正确的 JSON(您希望将Customer
类实例解析为的 JSON),但在您的客户端程序中,您希望您的 Http 客户端代码Customer
在这段代码中将您的类实例解析为 JSON:
Response response = invocationBuilder
.header("Authorization", "1234")
.post(Entity.entity(customer, MediaType.APPLICATION_JSON));
但是,正如您的错误消息告诉您的那样,日期被解析为“653038060000”。因此,我建议首先测试我的假设是否正确,尝试Customer
从您的客户端程序发送您的 JSON 文本而不是类实例。如果我的假设是正确的,这将起作用。如果是这样,那么您需要确保将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 format for json serialization
另外,如果您使用的是 Java 8 或更高版本,我非常强烈建议不要使用过时的Date
类(没有双关语),而是切换到java.time
package 并改用LocalDate类或其他可用的类,例如LocalDateTime
or ZonedDateTime
or others。最后,如果您愿意,可以尝试 MgntUtils 库中的另一个 3d 方 Http 客户端。这是它的 JavaDoc:HttpClient。您可以在此处作为Maven Artifacts找到该库本身,也可以在Github上找到该库本身(包括源代码和Javadoc)。该库不会将类解析为 JSON,但可以将文本作为请求正文发送。(免责声明:这个库是我写的)。
推荐阅读
- microsoft-dynamics - 将 Dynamics 365 联系人与 GAL 同步
- python - ValueError:x 和 y 必须具有相同的第一维,但具有形状 (32,) 和 (30,)
- r - RStudio 经常尝试自动完成的代码片段库是什么?
- laravel - 在 Jenkins 管道中运行“docker-compose run --rm composer update”不起作用
- sql - SQL 表阻止我添加外键
- excel - 检索其下方行的另一个单元格的单元格值的公式
- python - Windows 上的 Python 扩展模块 - 控制依赖项的 DLL 路径
- python - 需要帮助以找到更好的方法来为热图创建数组
- php - 使用选择表单对 WordPress 评论进行排序
- mysql - 如何格式化typeorm mysql查询