杰克逊,如何使用原始类型将 json 转换为 Java class?
Jackson, how to transform json to Java class using raw type?
我正在开发一个库,以便能够以更流畅的方式为个人项目查询 public api。我在 Jackson 将 API 答案转换为我的 java 对象时遇到了一些困难。
这是我的问题:
我使用 jdk 11 HttpClient 和 BodyHandlers.ofString() 调用此 API。到目前为止,没有什么很复杂的。但是当我想将 json 转换为 java 对象时,答案的格式给我带来了困难。
这是 Json 中的答案:
{
"data": {
"iso": "2021-02-04T20:35:21Z",
"epoch": 1612470921
}
}
但“数据”类型也可以出现在不同字段的其他答案中。例如:
{
"data": {
"base": "BTC",
"currency": "USD",
"amount": "37721.43"
}
}
所以我决定创建一个像这样的通用数据类型:
public class DataDto<T> {
T data;
@JsonCreator
public DataDto(@JsonProperty(value = "data") T data) {
this.data = data;
}
}
所以,让我们以第一个答案为例。
我还有一个名为 Time 的对象:
public class TimeDto {
private LocalDateTime iso;
private long epoch;
@JsonCreator
public TimeDto(
@JsonProperty(value = "iso") LocalDateTime iso, @JsonProperty(value = "epoch") long epoch){
this.iso = iso;
this.epoch = epoch;
}
}
还有我的函数,我想将答案转换为我的 java 对象:
public static Time getTime(final MyClient client) {
var request =
HttpRequest.newBuilder()
.GET()
.uri(
URI.create(
client.getProperties().getApiUrl() + client.getProperties().getTimePath()))
.header(ACCEPT, ACCEPT_VALUE)
.build();
try {
var response = client.getClient().send(request, HttpResponse.BodyHandlers.ofString());
var dataDtoType = client.getObjectMapper().getTypeFactory().constructType(DataDto.class);
var timeDtoType =
client
.getObjectMapper()
.getTypeFactory()
.constructParametricType(TimeDto.class, dataDtoType);
var toto = client.getJsonDeserializer().readValue(response.body(), timeDtoType);
return null;
} catch (Exception e) {
log.error("An error occured while getting time", e);
throw new MyException("An error occured while getting time", e);
}
}
如您所见,我尝试创建一个特定的 Jackson JavaType 以便能够以通用方式转换数据...但就我而言,当我测试此代码时,此异常附加:
java.lang.IllegalArgumentException: Cannot create TypeBindings for class com.github.badpop.mylib.client.dto.TimeDto with 1 type parameter: class expects 0
at com.fasterxml.jackson.databind.type.TypeBindings.create(TypeBindings.java:126)
at com.fasterxml.jackson.databind.type.TypeBindings.create(TypeBindings.java:96)
at com.fasterxml.jackson.databind.type.TypeFactory.constructParametricType(TypeFactory.java:1109)
at com.github.badpop.mylib.client.PublicResourcesService.getTime(PublicResourcesService.java:42)
at com.github.badpop.mylib.client.MyClient.getTime(MyClient.java:70)
at com.github.badpop.mylib.Main.main(Main.java:20)
如果您有什么想法可以帮助我解决我的问题,在此先感谢您!
最简单的是使用 TypeReference
,例如
String json = "{\r\n" +
" \"data\": {\r\n" +
" \"iso\": \"2021-02-04T20:35:21Z\",\r\n" +
" \"epoch\": 1612470921\r\n" +
" }\r\n" +
"}";
ObjectMapper mapper = new ObjectMapper()
.registerModule(new JavaTimeModule());
DataDto<TimeDto> data = mapper.readValue(json, new TypeReference<DataDto<TimeDto>>() {});
System.out.println("iso: " + data.getData().getIso());
System.out.println("epoch: " + data.getData().getEpoch());
您甚至可以“跳过”DataDto
部分:
TimeDto time = mapper.readValue(json, new TypeReference<DataDto<TimeDto>>() {}).getData();
System.out.println("iso: " + time.getIso());
System.out.println("epoch: " + time.getEpoch());
输出
iso: 2021-02-04T20:35:21Z
epoch: 1612470921
DTO
class DataDto<T> {
private final T data;
@JsonCreator
public DataDto(@JsonProperty(value = "data") T data) {
this.data = data;
}
public T getData() {
return this.data;
}
}
class TimeDto {
private final Instant iso;
private final long epoch;
@JsonCreator
public TimeDto(@JsonProperty(value = "iso") Instant iso,
@JsonProperty(value = "epoch") long epoch){
this.iso = iso;
this.epoch = epoch;
}
public Instant getIso() {
return this.iso;
}
public long getEpoch() {
return this.epoch;
}
}
我正在开发一个库,以便能够以更流畅的方式为个人项目查询 public api。我在 Jackson 将 API 答案转换为我的 java 对象时遇到了一些困难。
这是我的问题:
我使用 jdk 11 HttpClient 和 BodyHandlers.ofString() 调用此 API。到目前为止,没有什么很复杂的。但是当我想将 json 转换为 java 对象时,答案的格式给我带来了困难。
这是 Json 中的答案:
{
"data": {
"iso": "2021-02-04T20:35:21Z",
"epoch": 1612470921
}
}
但“数据”类型也可以出现在不同字段的其他答案中。例如:
{
"data": {
"base": "BTC",
"currency": "USD",
"amount": "37721.43"
}
}
所以我决定创建一个像这样的通用数据类型:
public class DataDto<T> {
T data;
@JsonCreator
public DataDto(@JsonProperty(value = "data") T data) {
this.data = data;
}
}
所以,让我们以第一个答案为例。 我还有一个名为 Time 的对象:
public class TimeDto {
private LocalDateTime iso;
private long epoch;
@JsonCreator
public TimeDto(
@JsonProperty(value = "iso") LocalDateTime iso, @JsonProperty(value = "epoch") long epoch){
this.iso = iso;
this.epoch = epoch;
}
}
还有我的函数,我想将答案转换为我的 java 对象:
public static Time getTime(final MyClient client) {
var request =
HttpRequest.newBuilder()
.GET()
.uri(
URI.create(
client.getProperties().getApiUrl() + client.getProperties().getTimePath()))
.header(ACCEPT, ACCEPT_VALUE)
.build();
try {
var response = client.getClient().send(request, HttpResponse.BodyHandlers.ofString());
var dataDtoType = client.getObjectMapper().getTypeFactory().constructType(DataDto.class);
var timeDtoType =
client
.getObjectMapper()
.getTypeFactory()
.constructParametricType(TimeDto.class, dataDtoType);
var toto = client.getJsonDeserializer().readValue(response.body(), timeDtoType);
return null;
} catch (Exception e) {
log.error("An error occured while getting time", e);
throw new MyException("An error occured while getting time", e);
}
}
如您所见,我尝试创建一个特定的 Jackson JavaType 以便能够以通用方式转换数据...但就我而言,当我测试此代码时,此异常附加:
java.lang.IllegalArgumentException: Cannot create TypeBindings for class com.github.badpop.mylib.client.dto.TimeDto with 1 type parameter: class expects 0
at com.fasterxml.jackson.databind.type.TypeBindings.create(TypeBindings.java:126)
at com.fasterxml.jackson.databind.type.TypeBindings.create(TypeBindings.java:96)
at com.fasterxml.jackson.databind.type.TypeFactory.constructParametricType(TypeFactory.java:1109)
at com.github.badpop.mylib.client.PublicResourcesService.getTime(PublicResourcesService.java:42)
at com.github.badpop.mylib.client.MyClient.getTime(MyClient.java:70)
at com.github.badpop.mylib.Main.main(Main.java:20)
如果您有什么想法可以帮助我解决我的问题,在此先感谢您!
最简单的是使用 TypeReference
,例如
String json = "{\r\n" +
" \"data\": {\r\n" +
" \"iso\": \"2021-02-04T20:35:21Z\",\r\n" +
" \"epoch\": 1612470921\r\n" +
" }\r\n" +
"}";
ObjectMapper mapper = new ObjectMapper()
.registerModule(new JavaTimeModule());
DataDto<TimeDto> data = mapper.readValue(json, new TypeReference<DataDto<TimeDto>>() {});
System.out.println("iso: " + data.getData().getIso());
System.out.println("epoch: " + data.getData().getEpoch());
您甚至可以“跳过”DataDto
部分:
TimeDto time = mapper.readValue(json, new TypeReference<DataDto<TimeDto>>() {}).getData();
System.out.println("iso: " + time.getIso());
System.out.println("epoch: " + time.getEpoch());
输出
iso: 2021-02-04T20:35:21Z
epoch: 1612470921
DTO
class DataDto<T> {
private final T data;
@JsonCreator
public DataDto(@JsonProperty(value = "data") T data) {
this.data = data;
}
public T getData() {
return this.data;
}
}
class TimeDto {
private final Instant iso;
private final long epoch;
@JsonCreator
public TimeDto(@JsonProperty(value = "iso") Instant iso,
@JsonProperty(value = "epoch") long epoch){
this.iso = iso;
this.epoch = epoch;
}
public Instant getIso() {
return this.iso;
}
public long getEpoch() {
return this.epoch;
}
}