有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何使用Jackson将JSON属性按前缀映射/分组到对象列表?

我有以下回应:

{
  "part1.id": "1",  
  "part1.name": "Name1",                 
  "part2.id": "2",                
  "part2.name": "Name2"
}

1个用户的POJO/DTO类:

public class User {

  private String id;
  private String name;

  // set/get
}

整个回答的类别:

public class UsersResponse {

  private List<User> users;

  // set/get
}

我可以在Map中检索值,然后在代码中手动解析/Map,如 Jackson JSON map key as property of contained object

还有@JsonAlias用于多个命名变体,但它映射到一个对象

是否有其他方法可以将提供的前缀的JSON值映射/分组到列表中


共 (1) 个答案

  1. # 1 楼答案

    没有已经实现的注释允许通过配置来实现。您需要实现反序列化程序。反序列化程序的简单版本如下所示:

    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);
        }
    }
    

    给定JSON的Abobe应用程序:

    {
      "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{}和JSON