如何使用 genson 解析嵌套的 json?
How can I parse nested json using genson?
我正在从 REST API 中获取结果,它是一个 json 对象列表,代表用户,每个用户内部都有嵌套的 json 对象。我的问题是嵌套属性名称与我在代码中获得的 bean 属性不对应。但是它们太不合适了,我真的不想保留 API 嵌套属性名称...
我使用 genson 1.5 和 java 8,我的豆子使用 lombok。
我尝试使用简单的解串器,然后使用转换器但没有成功。
这是我从 API 收到的示例:
[
{
"FirstName": "Jack",
"LastName": "Sparrow",
"Adress": {
"String1": "Toulon",
"String2": "France",
"String3": "83",
}
},
{
"FirstName": "I am",
"LastName": "Groot",
"Adress": {
"String1": "Marseille",
"String2": "France",
"String3": "13",
}
},
]
这是我想要作为新格式的 bean:
@Data
public class User {
private String firstName;
private String lastName;
private String country; //this represents String2 from the API
}
我已经尝试过这些解决方案:
- 只使用推荐的反序列化(错误是因为与我的 bean 相比,没有从 api 获得相同的属性):
private Genson genson = new Genson();
public List<User> getUserList() {
Response response = api.target(url)...get();
List<User> users = genson.deserialize(response.readEntity(String.class), new GenericType<List<User>>(){});
return users;
}
- 使用转换器获取与我的 bean 相同的参数
private Genson genson = new GensonBuilder().withConverters(new UserConverter()).create();
public List<User> getUserList() {
Response response = api.target(url)...get();
List<User> users = this.genson.deserialize(response.readEntity(String.class), new genericType<List<User>>(){});
return users;
}
public class UserConverter implements Converter<User> {
public User deserialize(ObjectReader reader, Context ctx) throws Exception {
User user = new User();
reader.beginObject();
while (reader.hasNext()) {
reader.next();
if ("FirstName".equals(reader.name())) {
user.setFirstName(reader.valueAsString());
} else if ("LastName".equals(reader.name())) {
user.setLastName(reader.valueAsString());
} else if ("Adress".equals(reader.name())) {
reader.beginObject();
while (reader.hasNext()) {
if ("String2".equals(reader.name())) {
user.setCountry(reader.valueAsString());
} else {
reader.skipValue();
}
}
reader.endObject();
} else {
reader.skipValue();
}
}
reader.endObject();
return user;
}
@Override
public void serialize(User object, ObjectWriter writer, Context ctx) throws Exception {
// TODO Auto-generated method stub
}
}
错误是:
com.owlike.genson.JsonBindingException: Could not deserialize to type interface java.util.List
at com.owlike.genson.Genson.deserialize(Genson.java:384)
...
Caused by: com.owlike.genson.stream.JsonStreamException: Illegal character at row 0 and column 660 expected } but read '{' !
at com.owlike.genson.stream.JsonReader.newWrongTokenException(JsonReader.java:942)
...
Genson 在 http://genson.io/Documentation/UserGuide/#custom-serde 给出了一个例子,但他们读取了一个整数列表作为值,这就是为什么我尝试嵌套 while for nested json...
如果有人对如何处理我的问题有想法,非常感谢!
您的问题是 JSON 中的属性名称与您在代码中的名称不同。注意你的 JSON 第一个字母是大写的。
你有几个选择:
- 在您的 JSON 中重命名它们
- 使用 @JsonProperty("newname")
或使用 builder.rename(currentName, newName)
在代码端重命名。
- 实施自定义 PropertyNameResolver that delegates name resolution to ConventionalBeanPropertyNameResolver ,然后将第一个字母更改为大写。
您可以在开始时实现自定义转换器,但如果您需要为每种类型都实现,这将是一项相当大的工作。
我建议实施自定义名称解析器。
@eugen 感谢您的回答,我在每个 bean 参数上方尝试了 @JsonProperty,但不幸的是它没有用。
然后一位同事来了,我们在 UserConverter 中添加:
private GenericType<Map<String, String>> adressMap = new GenericType<Map<String, String>>() {};
并更改了第二个 while 为:
else if ("Adress".equals(reader.name())) {
user.string2Value((ctx.genson.deserialize(adressMap, reader, ctx)).get("String2"));
}
这确实有效。
我正在从 REST API 中获取结果,它是一个 json 对象列表,代表用户,每个用户内部都有嵌套的 json 对象。我的问题是嵌套属性名称与我在代码中获得的 bean 属性不对应。但是它们太不合适了,我真的不想保留 API 嵌套属性名称...
我使用 genson 1.5 和 java 8,我的豆子使用 lombok。 我尝试使用简单的解串器,然后使用转换器但没有成功。
这是我从 API 收到的示例:
[
{
"FirstName": "Jack",
"LastName": "Sparrow",
"Adress": {
"String1": "Toulon",
"String2": "France",
"String3": "83",
}
},
{
"FirstName": "I am",
"LastName": "Groot",
"Adress": {
"String1": "Marseille",
"String2": "France",
"String3": "13",
}
},
]
这是我想要作为新格式的 bean:
@Data
public class User {
private String firstName;
private String lastName;
private String country; //this represents String2 from the API
}
我已经尝试过这些解决方案:
- 只使用推荐的反序列化(错误是因为与我的 bean 相比,没有从 api 获得相同的属性):
private Genson genson = new Genson();
public List<User> getUserList() {
Response response = api.target(url)...get();
List<User> users = genson.deserialize(response.readEntity(String.class), new GenericType<List<User>>(){});
return users;
}
- 使用转换器获取与我的 bean 相同的参数
private Genson genson = new GensonBuilder().withConverters(new UserConverter()).create();
public List<User> getUserList() {
Response response = api.target(url)...get();
List<User> users = this.genson.deserialize(response.readEntity(String.class), new genericType<List<User>>(){});
return users;
}
public class UserConverter implements Converter<User> {
public User deserialize(ObjectReader reader, Context ctx) throws Exception {
User user = new User();
reader.beginObject();
while (reader.hasNext()) {
reader.next();
if ("FirstName".equals(reader.name())) {
user.setFirstName(reader.valueAsString());
} else if ("LastName".equals(reader.name())) {
user.setLastName(reader.valueAsString());
} else if ("Adress".equals(reader.name())) {
reader.beginObject();
while (reader.hasNext()) {
if ("String2".equals(reader.name())) {
user.setCountry(reader.valueAsString());
} else {
reader.skipValue();
}
}
reader.endObject();
} else {
reader.skipValue();
}
}
reader.endObject();
return user;
}
@Override
public void serialize(User object, ObjectWriter writer, Context ctx) throws Exception {
// TODO Auto-generated method stub
}
}
错误是:
com.owlike.genson.JsonBindingException: Could not deserialize to type interface java.util.List
at com.owlike.genson.Genson.deserialize(Genson.java:384)
...
Caused by: com.owlike.genson.stream.JsonStreamException: Illegal character at row 0 and column 660 expected } but read '{' !
at com.owlike.genson.stream.JsonReader.newWrongTokenException(JsonReader.java:942)
...
Genson 在 http://genson.io/Documentation/UserGuide/#custom-serde 给出了一个例子,但他们读取了一个整数列表作为值,这就是为什么我尝试嵌套 while for nested json...
如果有人对如何处理我的问题有想法,非常感谢!
您的问题是 JSON 中的属性名称与您在代码中的名称不同。注意你的 JSON 第一个字母是大写的。
你有几个选择:
- 在您的 JSON 中重命名它们
- 使用 @JsonProperty("newname")
或使用 builder.rename(currentName, newName)
在代码端重命名。
- 实施自定义 PropertyNameResolver that delegates name resolution to ConventionalBeanPropertyNameResolver ,然后将第一个字母更改为大写。
您可以在开始时实现自定义转换器,但如果您需要为每种类型都实现,这将是一项相当大的工作。
我建议实施自定义名称解析器。
@eugen 感谢您的回答,我在每个 bean 参数上方尝试了 @JsonProperty,但不幸的是它没有用。
然后一位同事来了,我们在 UserConverter 中添加:
private GenericType<Map<String, String>> adressMap = new GenericType<Map<String, String>>() {};
并更改了第二个 while 为:
else if ("Adress".equals(reader.name())) {
user.string2Value((ctx.genson.deserialize(adressMap, reader, ctx)).get("String2"));
}
这确实有效。