java - 使用 GSON 和 lambda 过滤 JSON

标签 java java-8 gson

我有以下示例格式的巨大 json 。我想过滤 "d1"等于 "St"的所有项目。我也想删除该对象,以防由于上述过滤而没有留下任何项目。

[
{
  "containertype": "check2",
  "item": [
    {
      "d1": "St"
    },
    {
      "d1": "Pt"
    },
    {
      "d1": "St"
    }
  ],
  "contenttype": "test"
},
{
  "containertype": "check2",
  "item": [
    {
      "d1": "St"
    },
    {
      "d1": "St"
    },
    {
      "d1": "st"
    }
  ],
  "contenttype": "test"
}

]

预期结果

[
{
  "containertype": "check2",
  "item": [

    {
      "d1": "Pt"
    }
  ],
  "contenttype": "test"
}

]

这是我尝试过的,我正在读取json,使用Gson,我现在得到了 map ,我正在尝试过滤满足条件的项目。 :

    public class Testing {
public static void main(String[] args) {


    try {
        final String json = "[{"containertype":"check2","item":[{"d1":"St"},{"d1":"Pt"},{"d1":"St"}],"contenttype":"test"},{"containertype":"check2","item":[{"d1":"Pt"},{"d1":"Pt"},{"d1":"Pt"}],"contenttype":"test"}]";
         Gson gson = new Gson();
        Type rowListType = new TypeToken<List<Map<String, Object>>>() {
        }.getType();
final List<Map<String, Object>> rows = gson.fromJson(json, rowListType);
            rows.stream()
                    .filter(r -> r.containsKey("item"))
                    .collect(Collectors.toList());
            System.out.println(gson.toJson(rows, rowListType));

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

}

最佳答案

定义一些POJO类

JSON 旨在读取/反序列化为某些对象。因此,Gson(或者 jackson )被称为映射器。他们将 JSON 映射到 POJO(普通的旧 Java 对象)。

那么让我们定义模型。 为了简单起见,使用了 Lombok(构造函数、getter/setter、toString)。

项目

import lombok.Data;
import lombok.NoArgsConstructor;

@NoArgsConstructor
@Data
public class Item {

    private String d1;

}

容器(包含元素)

另外使用 Gson 的注释来遵守 Java 命名约定(camelCase),同时允许您指定的字段名称(小写)。

import com.google.gson.annotations.SerializedName;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

@Data
@NoArgsConstructor
public class Container {

    @SerializedName("containertype")
    private String containerType;
    @SerializedName("item")
    private List<Item> items;
    @SerializedName("contenttype")
    private String contentType;
}

向服务类添加功能

将一些 JSON 映射到容器

使用类型引用让 Gson 知道要创建哪些对象。

Type containerListType = new TypeToken<ArrayList<Container>>(){}.getType();
gson = new Gson();
List<Container> containerList = gson.fromJson(json, containerListType);

过滤掉包含符合指定条件的项目的容器

使用函数谓词和(Java 8):

    public static Predicate<Item> itemWhereD1equalsSt = item -> "St".equals(item.getD1());

    public static Predicate<Container> containerHasItemsWhereD1equalsSt = container -> {
        List<Item> items = container.getItems();
        if (items != null) {
            boolean hasItemMatching = items.stream().anyMatch(itemWhereD1equalsSt);
            return hasItemMatching;
        }
        return false;
    };

    public List<Container> filterFromJson(List<Container> containerList, Predicate<Container> containerPredicate) {
        return containerList.stream()
                .filter(containerPredicate)
                .collect(Collectors.toList());
    }

删除符合指定条件的项目

在列表上使用基于流功能便捷方法(Java 8):

(a) 简单变体(使用 lambda 表达式内联谓词):

    public void removeItemsSimple(List<Container> containers) {
        for (Container container : containers) {
            container.getItems().removeIf(item -> item.getD1().equalsIgnoreCase("St"));
        }
    }

(b) 增强的变体(将谓词作为参数传递,我们已经在容器中使用):

    public List<Item> removeItemsBasedOnFilter(List<Container> containers, Predicate<Item> itemPredicate) {
        return containers.stream()
                .flatMap(container -> removeItemsBasedOnFilter(container, itemPredicate).stream())
                .collect(Collectors.toList());
    }

    public List<Item> removeItemsBasedOnFilter(Container container, Predicate<Item> itemPredicate) {
        // Optional: filter all items in container that should be removed
        List<Item> itemsToBeRemoved = container.getItems().stream()
                .filter(itemPredicate)
                .collect(Collectors.toList());

        // remove all items that match the predicate
        container.getItems().removeIf(itemPredicate);

        // Optional: return removed items
        return itemsToBeRemoved;
    }

完整的服务等级

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;

public class JsonFilter {
    private static final Type containerListType = new TypeToken<ArrayList<Container>>(){}.getType();
    public static Predicate<Item> itemWhereD1equalsSt = item -> "St".equals(item.getD1());

    public static Predicate<Container> containerHasItemsWhereD1equalsSt = container -> {
        List<Item> items = container.getItems();
        if (items != null) {
            boolean hasItemMatching = items.stream().anyMatch(itemWhereD1equalsSt);
            return hasItemMatching;
        }
        return false;
    };

    private final Gson gson;

    public JsonFilter() {
        gson = new Gson();
    }

    public List<Container> readContainers(String json) {
        List<Container> containerList = gson.fromJson(json, containerListType);
        return containerList;
    }

    public List<Container> filterFromJson(List<Container> containerList, Predicate<Container> containerPredicate) {
        return containerList.stream()
                .filter(containerPredicate)
                .collect(Collectors.toList());
    }

    public void removeItemsSimple(List<Container> containers) {
        for (Container container : containers) {
            container.getItems().removeIf(item -> item.getD1().equalsIgnoreCase("St"));
        }
    }
    public List<Item> removeItemsBasedOnFilter(List<Container> containers, Predicate<Item> itemPredicate) {
        return containers.stream()
                .flatMap(container -> removeItemsBasedOnFilter(container, itemPredicate).stream())
                .collect(Collectors.toList());
    }

    public List<Item> removeItemsBasedOnFilter(Container container, Predicate<Item> itemPredicate) {
        // Optional: filter all items in container that should be removed
        List<Item> itemsToBeRemoved = container.getItems().stream()
                .filter(itemPredicate)
                .collect(Collectors.toList());

        // remove all items that match the predicate
        container.getItems().removeIf(itemPredicate);

        // Optional: return removed items
        return itemsToBeRemoved;
    }

}

已测试

使用没有断言的JUnit5 - 只需打印到控制台。

import org.junit.jupiter.api.Test;
import java.util.List;

class JsonFilterTest {

    @Test
    void filterContainerList() {
        final String json = givenJson(); // your test-data

        final JsonFilter jsonFilter = new JsonFilter();

        // map JSON to a list of containers
        List<Container> containersRead = jsonFilter.readContainers(json);

        // first filter-out all containers that do not have specified items
        List<Container> containersFiltered = jsonFilter.filterFromJson(containersRead, JsonFilter.containerHasItemsWhereD1equalsSt);
        System.out.println("Filtered containers resulting: " + containersFiltered.size());

        // then remove specified items from these resulting containers
        List<Item> itemsRemoved = jsonFilter.removeItemsBasedOnFilter(containersFiltered, JsonFilter.itemWhereD1equalsSt);
        System.out.println("Removed items: " + itemsRemoved.size());
    }

    private String givenJson() {
        return "[\n" +
                "  {\n" +
                "    \"containertype\": \"check2\",\n" +
                "    \"item\": [\n" +
                "      {\n" +
                "        \"d1\": \"St\"\n" +
                "      },\n" +
                "      {\n" +
                "        \"d1\": \"Pt\"\n" +
                "      },\n" +
                "      {\n" +
                "        \"d1\": \"St\"\n" +
                "      }\n" +
                "    ],\n" +
                "    \"contenttype\": \"test\"\n" +
                "  },\n" +
                "  {\n" +
                "    \"containertype\": \"check2\",\n" +
                "    \"item\": [\n" +
                "      {\n" +
                "        \"d1\": \"Pt\"\n" +
                "      },\n" +
                "      {\n" +
                "        \"d1\": \"Pt\"\n" +
                "      },\n" +
                "      {\n" +
                "        \"d1\": \"Pt\"\n" +
                "      }\n" +
                "    ],\n" +
                "    \"contenttype\": \"test\"\n" +
                "  }\n" +
                "]";
    }
}

关于java - 使用 GSON 和 lambda 过滤 JSON,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61057908/

相关文章:

java - 定义 lambda 表达式时使用泛型类型参数 <T>

java - 比较错误: Cannot invoke compareTo(int) on the primitive type int

Java - 如何进行 JSON 日期验证?

java - websphere 的 session 过期精确度如何?

java8 用无用的组合器来减少

java - 使用Java 8新API的CollectionUtills编译报错

Android Gradle 找不到符号类 Gson

java - 如何使用 gson 创建一组键值对?

java - 使用 GSON 解析 JSON 时出错以及如何访问 JSON 的内部元素

java - 内部类的访问修饰符