如何通过前缀将 map/group JSON 属性添加到带有 Jackson 的对象列表中?
How to map/group JSON properties by prefix to List of objects with Jackson?
我有 JSON 回复:
{
"part1.id": "1",
"part1.name": "Name1",
"part2.id": "2",
"part2.name": "Name2"
}
1 个用户的 POJO/DTO class:
public class User {
private String id;
private String name;
// set/get
}
和 class 整个响应:
public class UsersResponse {
private List<User> users;
// set/get
}
我可以在 Map 中检索值,然后在代码中手动检索 parse/map
Jackson JSON map key as property of contained object
还有 @JsonAlias 多个命名变体,但它映射到一个对象。
是否有任何其他方法可以 map/group JSON 列出提供的前缀的值?
没有允许通过配置实现的注释。您需要实施反序列化器。反序列化器的简单版本如下所示:
class UsersResponseDeserializer extends JsonDeserializer<UsersResponse> {
private Pattern propertyPattern = Pattern.compile("^part(\d+)\.(.+)$");
@Override
public UsersResponse deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
Integer lastIndex = null;
String lastName = null;
Map<Integer, Map<String, String>> users = new LinkedHashMap<>();
while (p.currentToken() != null) {
switch (p.currentToken()) {
case FIELD_NAME:
String name = p.getText();
Matcher matcher = propertyPattern.matcher(name);
if (matcher.matches()) {
lastIndex = Integer.parseInt(matcher.group(1));
lastName = matcher.group(2);
}
break;
case VALUE_STRING:
if (lastIndex != null && lastName != null) {
Map<String, String> user = users.computeIfAbsent(lastIndex, k -> new HashMap<>());
user.put(lastName, p.getValueAsString());
lastIndex = null;
lastName = null;
}
break;
default:
break;
}
p.nextToken();
}
UsersResponse response = new UsersResponse();
response.setUsers(users);
return response;
}
}
我稍微改了一下 UsersResponse
如下所示:
@JsonDeserialize(using = UsersResponseDeserializer.class)
class UsersResponse {
private Map<Integer, Map<String, String>> users;
public Map<Integer, Map<String, String>> getUsers() {
return users;
}
public void setUsers(Map<Integer, Map<String, String>> users) {
this.users = users;
}
@Override
public String toString() {
return "UsersResponse{" +
"users=" + users +
'}';
}
}
用法示例:
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.type.CollectionLikeType;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class JsonApp {
public static void main(String[] args) throws Exception {
File jsonFile = new File("path to json").getAbsoluteFile();
ObjectMapper mapper = new ObjectMapper();
UsersResponse data = mapper.readValue(jsonFile, UsersResponse.class);
System.out.println(data);
CollectionLikeType usersListType = mapper.getTypeFactory().constructCollectionLikeType(List.class, User.class);
List<User> users = mapper.convertValue(data.getUsers().values(), usersListType);
System.out.println(users);
}
}
给定的 Abobe 应用 JSON
:
{
"part1.id": "1",
"part1.name": "Name1",
"part2.id": "2",
"part2.name": "Name2",
"part33.id": "33",
"part33.name": "Name33"
}
打印:
UsersResponse{users={1={name=Name1, id=1}, 2={name=Name2, id=2}, 33={name=Name33, id=33}}}
[User{id='1', name='Name1'}, User{id='2', name='Name2'}, User{id='33', name='Name33'}]
在解串器中我使用了 Map<Integer, Map<String, String>>
因为我不想玩匹配的 POJO
properties
和 JSON
键。
我有 JSON 回复:
{
"part1.id": "1",
"part1.name": "Name1",
"part2.id": "2",
"part2.name": "Name2"
}
1 个用户的 POJO/DTO class:
public class User {
private String id;
private String name;
// set/get
}
和 class 整个响应:
public class UsersResponse {
private List<User> users;
// set/get
}
我可以在 Map 中检索值,然后在代码中手动检索 parse/map Jackson JSON map key as property of contained object
还有 @JsonAlias 多个命名变体,但它映射到一个对象。
是否有任何其他方法可以 map/group JSON 列出提供的前缀的值?
没有允许通过配置实现的注释。您需要实施反序列化器。反序列化器的简单版本如下所示:
class UsersResponseDeserializer extends JsonDeserializer<UsersResponse> {
private Pattern propertyPattern = Pattern.compile("^part(\d+)\.(.+)$");
@Override
public UsersResponse deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
Integer lastIndex = null;
String lastName = null;
Map<Integer, Map<String, String>> users = new LinkedHashMap<>();
while (p.currentToken() != null) {
switch (p.currentToken()) {
case FIELD_NAME:
String name = p.getText();
Matcher matcher = propertyPattern.matcher(name);
if (matcher.matches()) {
lastIndex = Integer.parseInt(matcher.group(1));
lastName = matcher.group(2);
}
break;
case VALUE_STRING:
if (lastIndex != null && lastName != null) {
Map<String, String> user = users.computeIfAbsent(lastIndex, k -> new HashMap<>());
user.put(lastName, p.getValueAsString());
lastIndex = null;
lastName = null;
}
break;
default:
break;
}
p.nextToken();
}
UsersResponse response = new UsersResponse();
response.setUsers(users);
return response;
}
}
我稍微改了一下 UsersResponse
如下所示:
@JsonDeserialize(using = UsersResponseDeserializer.class)
class UsersResponse {
private Map<Integer, Map<String, String>> users;
public Map<Integer, Map<String, String>> getUsers() {
return users;
}
public void setUsers(Map<Integer, Map<String, String>> users) {
this.users = users;
}
@Override
public String toString() {
return "UsersResponse{" +
"users=" + users +
'}';
}
}
用法示例:
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.type.CollectionLikeType;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class JsonApp {
public static void main(String[] args) throws Exception {
File jsonFile = new File("path to json").getAbsoluteFile();
ObjectMapper mapper = new ObjectMapper();
UsersResponse data = mapper.readValue(jsonFile, UsersResponse.class);
System.out.println(data);
CollectionLikeType usersListType = mapper.getTypeFactory().constructCollectionLikeType(List.class, User.class);
List<User> users = mapper.convertValue(data.getUsers().values(), usersListType);
System.out.println(users);
}
}
给定的 Abobe 应用 JSON
:
{
"part1.id": "1",
"part1.name": "Name1",
"part2.id": "2",
"part2.name": "Name2",
"part33.id": "33",
"part33.name": "Name33"
}
打印:
UsersResponse{users={1={name=Name1, id=1}, 2={name=Name2, id=2}, 33={name=Name33, id=33}}}
[User{id='1', name='Name1'}, User{id='2', name='Name2'}, User{id='33', name='Name33'}]
在解串器中我使用了 Map<Integer, Map<String, String>>
因为我不想玩匹配的 POJO
properties
和 JSON
键。