Найдите родительский элемент верхней категории и добавьте дочерний элемент под соответствующим родительским элементом в примере JSON с использованием Java

#java #json

#java #json

Вопрос:

Я нашел этот образец JSON для электронной коммерции. Я хотел упорядочить этот JSON иерархически.

Вы можете найти этот файл JSON по приведенному ниже URL.

https://stark-spire-93433.herokuapp.com/json

Я хотел упорядочить этот JSON следующим образом.

 Mens Wear
    |Bottom Wear
        |Jeans
        |Tracks amp; Trousers
    |Foot Wear
        |Casuals
        |Formals
    |Upper Wear
        |Shirts
        |T-Shirts
Electronics
    |Mobiles
        |Apple
        |Samsung
    |Laptops
        |Dell
        |Toshiba
        
  

Все варианты будут соответствовать последней иерархии продуктов. Например, Dell, Apple, Shirts и так далее.

Я создал классы моделей для этого JSON.

 public class Data {
    public ArrayList<Category> categories;
    public ArrayList<Rank> rankings;
}

public class Category {
    public int id;
    public String name;
    public ArrayList<Product> products;
    public ArrayList<Integer> child_categories;
}

public class Rank {
    public String ranking;
    public ArrayList<Product> products;
}

public class Product {
    public int id;
    public String name;
    public String date_added;
    public ArrayList<Variant> variants;
    public Tax tax;
    public int view_count;
    public int order_count;
    public int shares;
}

public class Tax {
    public String name;
    public double value;
}

public class Variant {
    public int id;
    public String color;
    //in some variants size is null eg. mobiles, if null pass 0.
    public int size;
    public double price;
}
  

Теперь я не понимаю, с чего мне начать.

Комментарии:

1. Я бы посоветовал не использовать никакого сопоставления объектов. Я бы подготовил несколько классов, чтобы представить древовидную структуру, которую вы хотите, например, если вам нужно будет построить дерево программно. Например, ваша категория должна содержать не ArrayList<Целое число> дочерние категории, а ArrayList<Категория> дочерние элементы… После этого используйте потоковый синтаксический анализ baeldung.com/jackson-streaming-api и постройте свое дерево, проходящее через токены JSON, как вам нужно.

Ответ №1:

Вот мое решение

Схема

  1. измените модель класса из древовидной структуры после добавления, используя составной шаблон проектирования
  2. десериализуйте json в модель класса из post, используя библиотеку Jackson.
  3. создайте Map<Integer, Category> , который обеспечивает прямой доступ к категории по ее идентификатору
  4. выполните итерацию по категориям, для каждой из них выполните итерацию по ее дочерним элементам, для каждого дочернего идентификатора получите дочернюю категорию с карты и назначьте в качестве дочернего экземпляра
  5. наконец, выполните итерацию по дереву, используя поиск в глубину, и распечатайте категории, используя шаблон посетителя

Структура данных

Я взял вашу модель и немного изменил:

  1. Изменены списки, которые будут определены как интерфейс. это связано с тем, что построение переменной выполняется десериализатором json, который может решить использовать другую реализацию List
  2. Добавлены коллекции для реализации составного шаблона: каждая Category имеет список дочерних категорий в качестве Category экземпляров, Data добавлен список корней дерева.
  3. Изменены имена переменных, чтобы лучше отражать назначение и использование.

Вот как выглядят измененные классы Data и Category :

 public class Category
{
    public int id;
    public String name;
    public List<Product> products;
    @JsonProperty("child_categories")
    public List<Integer> childCategoryIds;

    // tree-structure properties
    public boolean isRoot = true;
    public List<Category> childCategories = new ArrayList<>();

    public void visit(Visitor<Category> visitor, int level) {
        visitor.accpet(this, level);
        childCategories.forEach(cat -> cat.visit(visitor, level   1));
    }
}

public class Data
{
    public List<Category> categories;
    public List<Rank> rankings;

    // tree-structure properties
    public List<Category> tree;

    // initiate traversal of each root withj printer visitor
    public void printTree() {
        Visitor<Category> printer = new Printer();
        tree.forEach(root -> root.visit(printer, 0));
    }
}
  

Реализация решения

Шаблон посетителя

 // visitor interface
public interface Visitor<T>
{
    /**
     * @param level 0 is root, 1 root's child and so on
     */
    public void accpet(T node, int level);
}

// printer visitor: prints to console each visited category, properly indented 
public class Printer implements Visitor<Category>
{
    @Override
    public void accpet(Category node, int level) {
        System.out.println(indentByLevel(level)   node.id   " "   node.name);
        // in case of category with products - print them and variants
        if (node.products != null  amp;amp;  !node.products.isEmpty()) {
            printProducts(node, level);
        }
    }

    private void printProducts(Category node, int level) {
        node.products.forEach(product -> {
            System.out.println(indentByLevel(level 1)   product.id   " "   product.name);
            if (product.variants != null  amp;amp;  !product.variants.isEmpty()) {
                product.variants.forEach(variant -> {
                    System.out.println(indentByLevel(level 2)   variant.id   " "   variant.color);
                });
            }
        });
    }

    private static final String levelIndent = "    ";
    private String indentByLevel(int level) {
        if (level > 0) {
            return String.join("", Collections.nCopies(level, levelIndent));
        }
        return "";
    }
}
  

Основной класс

 public class JsonToTree
{
    public static void main(String[] args) {
        try {
            Data data = readJson("https://stark-spire-93433.herokuapp.com/json");
            jsonToTree(data);
            data.printTree();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // read and parse source to Data object
    // using java 11 HttpURLConnection and Jackson ObjectMapper
    public static Data readJson(String url) throws IOException {
        HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
        connection.setRequestMethod("GET");
        try (InputStream responseStream = connection.getInputStream()) {
            ObjectMapper mapper = new ObjectMapper();
             return mapper.readValue(responseStream, Data.class);
        }
    }

    public static void jsonToTree(Data data) {
        // populate array of categories. array index is category id
        // this will allow random access to category by its id
        Map<Integer, Category> categoryById = data.categories.stream()
            .collect(Collectors.toMap(cat -> cat.id, Function.identity(), (cat1, cat2) -> cat1));

        // populate list of category objects for each category according to list of child ids
        // along the way, mark each child category as not root
        data.categories.stream()
            .filter(cat -> cat.childCategoryIds != null  amp;amp;  !cat.childCategoryIds.isEmpty())
            .forEach(catWithChildren ->
                catWithChildren.childCategoryIds.forEach(id -> {
                    Category child = categoryById.get(id);
                    if (child != null) {
                        catWithChildren.childCategories.add(child);
                        child.isRoot = false;
                    }
                })
            );

        // build tree in data from root categories
        data.tree = new ArrayList<>();
        data.categories.stream()
            .filter(cat -> cat.isRoot)
            .forEach(root -> data.tree.add(root));
    }
}
  

Распечатка

 3 Mens Wear
    4 Bottom Wear
        2 Jeans
            3 Spykar Denim
                9 Blue
                10 Black
                11 Blue
                12 Blue
            4 Lee Cotton Jeans
                13 Blue
                14 Black
                15 White
                16 Black
            24 Denim Wash
                71 Blue
                72 Grey
            25 Pepe Jeans Slim Fit
                73 Blue
                74 Light Blue
            26 Spykar Funky Regular
                75 Blue
                76 Black
        8 Tracks amp; Trousers
            7 Comfort Tracks
                25 Blue
                26 Red
                27 White
                28 Red
            8 Adidas Trousers
                29 White
                30 Yellow
                31 Green
                32 Red
            30 Superdry track
                83 Red
                84 Blue
            31 Night Comfy Track
                85 Red
                86 Black
            32 Superdry Joggers
                87 Red
                88 Blue
    5 Foot Wear
        1  Casuals
            1 Nike Sneakers
                1 Blue
                2 Red
                3 Blue
                4 Red
            2 Adidas Running Shoes
                5 White
                6 Black
                7 White
                8 Red
            21 Roadster Loafers
                65 Black
                66 Blue
            22 Light Loafers
                67 Blue
                68 Yellow
            23 Floaters
                69 Black
                70 Red
        9 Formals
            9 Bata Lace up Shoes
                33 Black
                34 Brown
                35 Black
                36 Brown
            10 Franco Leather
                37 Black
                38 Brown
                39 Black
                40 Brown
    6 Upper Wear
        7 T-Shirts
            5 Polo Collar T-Shirt
                17 Blue
                18 Red
                19 White
                20 Red
            6 Adidas Nylon
                21 White
                22 Yellow
                23 Green
                24 Red
            27 Being Human Collar T-shirt
                77 Blue
                78 Black
            28 V - Neck Smart T-Shirt
                79 Blue
                80 Black
            29 Manchester United
                81 Red
                82 Red
        10 Shirts
            11 Wrangler Checked Shirt
                41 Blue
                42 Red
                43 Black
                44 White
            12 Printed Shirt
                45 Blue
                46 Black
                47 Red
                48 Brown
11 Electronics
    12 Mobiles
        14 Apple
            13 Iphone 6S
                49 Silver
                50 Golden
            14 Iphone 7
                51 Black
                52 Silver
            33 Iphone 6
                89 Silver
                90 Golden
            34 Iphone 6s Plus
                91 Silver
                92 Golden
            35 Iphone 7 Plus
                93 Black
                94 Grey
        15 Samsung
            15 Galaxy S7 Edge
                53 Black
                54 White
            16 Galaxy J5
                55 Black
                56 White
            36 Galaxy J7
                95 Black
                96 White
            37 Galaxy Grand Prime
                97 Black
                98 White
            38 Note 4
                99 Black
                100 White
    13 Laptops
        16 Dell
            17 Dell Inspiron Core
                57 Black
                58 Red
            18 Dell Inspiron 11
                59 Black
                60 Red
        17 Toshiba
            19 Satellite Pro
                61 Black
                62 Red
            20 Satellite P50
                63 Black
                64 Red
  

Ответ №2:

Ну, проблема заключается в использовании косвенных ссылок на дочерние категории с использованием идентификаторов. Целью было бы преобразовать косвенные ссылки в прямые ссылки, такие как data.getCategory().getChildCategory().getName() возможно.

Я бы решил это, введя два уровня абстракции:

Первый существует только для десериализации. Классы — давайте назовем их JsonBean s — этого уровня будут очень похожи на структуру json, поэтому дочерние категории — это только числа. Это также имеет то преимущество, что JsonBean s могут содержать специальные аннотации для десериализации, как они используются Jackson .

Вторым слоем будет граф объектов, который используется в приложении, и он заменяет дочерние категории конкретными объектами. Давайте просто назовем этот тип классов Bean . Bean s будут независимы от дизайна JSON таким образом, что их можно будет использовать повторно, даже если данные загружаются из базы данных вместо JSON.

Затем процесс десериализации будет состоять из двух этапов: сначала необработанная десериализация в JsonBean s. Затем следует служба преобразования, которая будет копировать JsonBean файлы в приложения Bean . Затем это преобразование преобразует идентификаторы дочерних категорий в конкретные Category объекты.

Разделение между моделью чистого значения и моделью сохранения также обеспечивает некоторую безопасность на случай, если структура JSON будет изменена в будущем. Пока изменение не слишком серьезное, это мало повлияет на ваше приложение, поскольку вам нужно будет изменить только JsonBean s и преобразование, а не все остальное, что использует данные после десериализации.