Фильтрация JSon с использованием GSON и Lambda - PullRequest
0 голосов
/ 06 апреля 2020

У меня огромный 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, я получил карту, теперь я пытаюсь отфильтровать элементы, где выполняется условие. :

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

}

Ответы [ 2 ]

0 голосов
/ 07 апреля 2020

Определить некоторые классы POJO

JSON предназначен для чтения / десериализации в некоторые объекты. Таким образом Gson (или, альтернативно, Джексон) называется mapper . Они отображают JSON в POJO (простые старые Java объекты).

Итак, давайте определим модель. Для простоты используется Lombok (конструкторы, getter / setter, toString).

Item

import lombok.Data;
import lombok.NoArgsConstructor;

@NoArgsConstructor
@Data
public class Item {

    private String d1;

}

Контейнер (содержащий items )

Дополнительно использовал аннотацию Gson для соблюдения Java -naming-Convention (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);

Отфильтровать контейнеры, в которых есть элементы, соответствующие указанному критерию

, используя функционал Предикат и streaming (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());
    }

Удаляет элементы, соответствующие указанному критерию

, используя функционал на основе потока и удобный метод в List (Java 8):

(a) Простой вариант (предикат, встроенный с использованием лямбда-выражения ):

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

Полный сервис e-class

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" +
                "]";
    }
}
0 голосов
/ 07 апреля 2020

во-первых, не отображать старое «ROW», но новый объект, который вы создаете после потока

, во-вторых, я добавил фильтр, в котором я выбрасываю List -> Map-> и изменяю значения в элемент и проверьте, есть ли другие, которые соответствуют критерию

ниже моего решения -> пример

List<Map<String, Object>> newRows = rows.stream()
        .filter(r -> r.containsKey("item"))
        .filter(r -> {
          List<Map<String, String>> item = (List<Map<String, String>>) r.get("item");
          List<Map<String, String>> newList = item.stream().filter(x -> !x.get("d1").toUpperCase().equals("ST")).collect(Collectors.toList());
          r.put("item", newList);
          return !newList.isEmpty();
        })
        .collect(Collectors.toList());
System.out.println(gson.toJson(newRows));

вот тест моего примера

I использовал ваш пример для проверки

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.jetbrains.annotations.NotNull;
import org.junit.Test;

import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static org.junit.Assert.assertEquals;

public class GsonLambda {
  @Test
  public void test() {
    //given
    final String json = getJson();
    Gson gson = new Gson();
    Type rowListType = new TypeToken<List<Map<String, Object>>>() {
    }.getType();
    final List<Map<String, Object>> rows = gson.fromJson(json, rowListType);
    //when
    List<Map<String, Object>> newRows = rows.stream()
            .filter(r -> r.containsKey("item"))
            .filter(r -> {
              List<Map<String, String>> item = (List<Map<String, String>>) r.get("item");
              List<Map<String, String>> newList = item.stream().filter(x -> !x.get("d1").toUpperCase().equals("ST")).collect(Collectors.toList());
              r.put("item", newList);
              return !newList.isEmpty();
            })
            .collect(Collectors.toList());
    //then
    assertEquals("[{\"containertype\":\"check2\",\"item\":[{\"d1\":\"Pt\"}],\"contenttype\":\"test\"}]", gson.toJson(newRows));
  }

  @NotNull
  private String getJson() {
    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\": \"St\"\n" +
            "    },\n" +
            "    {\n" +
            "      \"d1\": \"St\"\n" +
            "    },\n" +
            "    {\n" +
            "      \"d1\": \"st\"\n" +
            "    }\n" +
            "  ],\n" +
            "  \"contenttype\": \"test\"\n" +
            "}" +
            "]";
  }
}
...