You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Jackson实现嵌套Map过滤保留结构:筛选Hit为True的电影

筛选JSON中hit为true的电影(保留层级结构)

问题说明

需要从层级结构的JSON文件中筛选出所有hit字段为true的电影条目,同时保留原有的地区(Bollywood/Hollywood)和类型(Action/Romance)层级结构,但当前编写的Jackson解析代码报错,无法实现需求。

示例JSON内容

{
    "Bollywood": {
        "Romance": {
            "hit": false,
            "name": "Prithvi Raj"
        },
        "Action": {
            "hit": true,
            "name": "3 Idiots"
        }
    },
    "Hollywood": {
        "Romance": {
            "hit": false,
            "name": "Intimacy"
        },
        "Action": {
            "hit": true,
            "name": "Seven Samurai"
        }
    }
}

当前错误代码

import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.node.ObjectNode;


public class TestJson
{
    public static void main(String[] args)
    {
        try {
    // 创建ObjectMapper实例
    ObjectMapper mapper = new ObjectMapper();

    // 将JSON文件转换为Map
    Map<?, ?> map = mapper.readValue(Paths.get("movie.json").toFile(), Map.class);

    map =  map.entrySet().stream().collect(
                Collectors.toMap(
                        Map.Entry::getKey,
                        entry -> entry.getValue()
                           .entrySet()
                           .stream()
                           .filter(subEntry -> subEntry.getValue().equals(true))
                           .collect(Collectors.toMap(Map.Entry::getKey,
                                 Map.Entry::getValue)))
                        );


    map.forEach((k,v) -> System.out.println("Key : " + k + ", Value : " + v));
        
} catch (Exception ex) {
    ex.printStackTrace();
}
    }
}

报错信息

TestJson.java:46: error: cannot find symbol
                           .entrySet()
                           ^
  symbol:   method entrySet()
  location: class Object
TestJson.java:49: error: incompatible types: cannot infer type-variable(s) T,K#1,U
                           .collect(Collectors.toMap(Map.Entry::getKey,
                                                    ^
    (argument mismatch; invalid method reference
      method getKey in interface Entry<K#2,V> cannot be applied to given types
        required: no arguments
        found:    Object
        reason: actual and formal argument lists differ in length)
  where T,K#1,U,K#2,V are type-variables:
    T extends Object declared in method <T,K#1,U>toMap(Function<? super T,? extends K#1>,Function<? super T,? extends U>)
    K#1 extends Object declared in method <T,K#1,U>toMap(Function<? super T,? extends K#1>,Function<? super T,? extends U>)
    U extends Object declared in method <T,K#1,U>toMap(Function<? super T,? extends K#1>,Function<? super T,? extends U>)
    K#2 extends Object declared in interface Entry
    V extends Object declared in interface Entry
2 errors

期望输出结果

{
    "Bollywood": {
        "Action": {
            "hit": true,
            "name": "3 Idiots"
        }
    },
    "Hollywood": {
        "Action": {
            "hit": true,
            "name": "Seven Samurai"
        }
    }
}

错误原因分析

  1. 类型转换问题:将JSON转为Map<?, ?>后,entry.getValue()的类型是Object,无法直接调用entrySet()方法,必须先明确其为Map类型。
  2. 筛选条件错误:原代码判断subEntry.getValue().equals(true),但subEntry.getValue()是包含hit和name的对象,不是直接的布尔值,需要提取hit字段的值再判断。

解决方案

方案一:使用泛型Map明确层级结构

通过指定泛型类型,避免Object类型的转换问题,同时修正筛选逻辑:

import java.io.File;
import java.util.Map;
import java.util.stream.Collectors;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

public class TestJson {
    public static void main(String[] args) {
        try {
            ObjectMapper mapper = new ObjectMapper();
            // 明确JSON的层级泛型:地区 -> 电影类型 -> 电影属性
            Map<String, Map<String, Map<String, Object>>> movieMap = mapper.readValue(
                new File("movie.json"),
                new TypeReference<Map<String, Map<String, Map<String, Object>>>>() {}
            );

            // 层级筛选:保留每个地区下hit为true的电影类型
            Map<String, Map<String, Map<String, Object>>> filteredMap = movieMap.entrySet().stream()
                .collect(Collectors.toMap(
                    Map.Entry::getKey,
                    regionEntry -> regionEntry.getValue().entrySet().stream()
                        // 提取hit字段并判断是否为true
                        .filter(typeEntry -> (Boolean) typeEntry.getValue().get("hit"))
                        .collect(Collectors.toMap(
                            Map.Entry::getKey,
                            Map.Entry::getValue
                        ))
                ));

            // 格式化输出结果
            mapper.enable(SerializationFeature.INDENT_OUTPUT);
            System.out.println(mapper.writeValueAsString(filteredMap));

        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

方案二:使用Jackson JsonNode处理(更灵活)

利用Jackson的JsonNodeAPI直接操作JSON节点,无需依赖泛型,适合结构复杂的JSON:

import java.io.File;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.SerializationFeature;

public class TestJson {
    public static void main(String[] args) {
        try {
            ObjectMapper mapper = new ObjectMapper();
            JsonNode rootNode = mapper.readTree(new File("movie.json"));

            // 创建空节点存储筛选结果
            ObjectNode filteredRoot = mapper.createObjectNode();

            // 遍历每个地区节点
            rootNode.fields().forEachRemaining(regionEntry -> {
                String regionName = regionEntry.getKey();
                JsonNode regionNode = regionEntry.getValue();
                ObjectNode filteredRegion = mapper.createObjectNode();

                // 遍历地区下的所有电影类型
                regionNode.fields().forEachRemaining(typeEntry -> {
                    JsonNode movieNode = typeEntry.getValue();
                    // 判断hit字段是否为true
                    if (movieNode.get("hit").asBoolean()) {
                        filteredRegion.set(typeEntry.getKey(), movieNode);
                    }
                });

                // 仅保留包含有效电影的地区
                if (!filteredRegion.isEmpty()) {
                    filteredRoot.set(regionName, filteredRegion);
                }
            });

            // 格式化输出
            mapper.enable(SerializationFeature.INDENT_OUTPUT);
            System.out.println(mapper.writeValueAsString(filteredRoot));

        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

方案说明

  • 方案一通过泛型明确了JSON的层级结构,代码逻辑清晰,适合结构固定的JSON场景。
  • 方案二使用JsonNode操作节点,无需提前定义泛型,处理动态结构的JSON更灵活,可读性也更强。

内容的提问来源于stack exchange,提问作者isilia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 22:20:31