创建动态嵌套JSON Java

时间:2017-01-08 17:44:16

标签: java json rest gson

我想用一个字符串数组创建一个Json,每个字符串看起来像: " id.categoryvalue.subcatvalue.subsubcatvalue.score" 结果应如下所示:



{
  "user-id": "u42",
  "categories": [
    {
      "category": "value",
      "subcats": [
        {
          "subcat": "value",
          "subsubcats": [
            {
              "subsubcat": "value",
              "score": 47
            }  
          ]
        }
      ]
    }
  ]
}




我不想复制同一类别中的值,解决问题的有效方法是什么?谢谢!

2 个答案:

答案 0 :(得分:0)

假设输入格式保持不变,您可以执行以下操作:

  • Tokenize输入字符串,将其与.
  • 分开
  • 声明/初始化结构(例如Map并设置适当的值)
  • 使用任何String解析器
  • 将结果对象转换为JSON

下面的例子演示了它:

public static void main(String[] args) throws Exception{
    Map<String, Object> result = convertToMap("id.categoryvalue.subcatvalue.subsubcatvalue.score");
    System.out.println(new ObjectMapper().writeValueAsString(result));
}

public static Map<String, Object> convertToMap(String input){
    Map<String, Object> result = new LinkedHashMap<>();
    String[] tokens = input.split("\\.");

    if(tokens.length < 5){
        //Invalid string, return
        throw new IllegalArgumentException("Insufficient tokens");
    }

    //Add user id
    result.put("user-id", tokens[0]);

    //Add category
    Map<String, Object> category = new LinkedHashMap<>();
    category.put("category", tokens[1]);

    //Add sub category
    Map<String, Object> subCategory = new LinkedHashMap<>();
    subCategory.put("subcat", tokens[2]);

    //Add nested category
    Map<String, Object> nestedSubCategory = new LinkedHashMap<>();
    nestedSubCategory.put("subsubcat", tokens[3]);
    nestedSubCategory.put("score", Integer.parseInt(tokens[4]));

    subCategory.put("subcats", Arrays.asList(new Map[] {nestedSubCategory}));
    category.put("subcats", Arrays.asList(new Map[] {subCategory}));
    result.put("categories", Arrays.asList(new Map[] {category}));

    return result;
}

答案 1 :(得分:0)

使用Gson,您可以使用对象模型方式或流式方式生成JSON。第一个需要在以强类型方式(见下文)或弱类型方式生成JSON之前构建整个对象(如Darshan Mehta建议的那样 - 他使用基于Java映射的弱对象)

对象模型方法

将给定数据分解为几个数据包类,构造这些类的对象,只需调用Gson:

public final class ObjectModelDemo {

    private ObjectModelDemo() {
    }

    public static void main(final String... args) {
        final String[] tokens = "id31.english.B1.Animals.11".split("\\.");
        if ( tokens.length != 5 ) {
            throw new IllegalArgumentException("Not 5 tokens in " + "id31.english.B1.Animals.11");
        }
        final String userId = tokens[0];
        final String category = tokens[1];
        final String subcategory = tokens[2];
        final String subsubcategory = tokens[3];
        final int score = parseInt(tokens[4]);
        final User user = new User(
                userId,
                singletonList(new Category(
                        category,
                        singletonList(new Subcategory(
                                subcategory,
                                singletonList(new Subsubcategory(subsubcategory, score))
                        ))
                ))
        );
        final Gson gson = new GsonBuilder().create();
        out.println(gson.toJson(user));
    }

    private static final class User {

        @SerializedName("user-id")
        private final String userId;

        @SerializedName("categories")
        private final List<Category> categories;

        private User(final String userId, final List<Category> categories) {
            this.userId = userId;
            this.categories = categories;
        }

    }

    private static final class Category {

        @SerializedName("category")
        private final String category;

        @SerializedName("subcats")
        private final List<Subcategory> subcategories;

        private Category(final String category, final List<Subcategory> subcategories) {
            this.category = category;
            this.subcategories = subcategories;
        }

    }

    private static final class Subcategory {

        @SerializedName("subcat")
        private final String subcategory;

        @SerializedName("subsubcats")
        private final List<Subsubcategory> subsubcategories;

        private Subcategory(final String subcategory, final List<Subsubcategory> subsubcategories) {
            this.subcategory = subcategory;
            this.subsubcategories = subsubcategories;
        }

    }

    private static final class Subsubcategory {

        @SerializedName("subsubcat")
        private final String subsubcategory;

        @SerializedName("score")
        private final int score;

        private Subsubcategory(final String subsubcategory, final int score) {
            this.subsubcategory = subsubcategory;
            this.score = score;
        }

    }

}

此类数据包称为DTO(data-transfer objects),旨在映射Java对象及其各自的JSON表示。这为Java编译器提供了非常强大的编译时控制支持。这种方法的缺点是必须在任何JSON生成开始之前收集所有数据(通常这对于对内存敏感的应用程序非常重要)。但是,对于您的情况,这可能会更容易,也可能是最容易的。

输出:

  

{ “用户ID”: “ID31”, “类别”:[{ “类别”: “英语”, “subcats”:[{ “SUBCAT”: “B1”, “subsubcats”:[{“subsubcat “:” 动物”, “分数”:11}]}]}]}

流媒体方法

基于将JSON中间写入目标的替代方法。这种方法是一种更复杂的数据推送方法,但从内存消耗的角度来看它更有效(甚至更多,你可以使用这种方法轻松生成无限的JSON,但我怀疑你会遇到这样的情况:))。

    public static void main(final String... args)
            throws IOException {
        final String[] tokens = "id21.english.B2.Insects.24".split("\\.");
        if ( tokens.length != 5 ) {
            throw new IllegalArgumentException("Not 5 tokens in " + "id21.english.B2.Insects.24");
        }
        final String userId = tokens[0];
        final String category = tokens[1];
        final String subcategory = tokens[2];
        final String subsubcategory = tokens[3];
        final int score = parseInt(tokens[4]);
        final JsonWriter jsonWriter = new JsonWriter(new OutputStreamWriter(out));
        writeUser(jsonWriter, userId, category, subcategory, subsubcategory, score);
        jsonWriter.flush();
        // do not invoke jsonWriter.close() -- let the caller decide what to do
    }

    private static void writeUser(final JsonWriter jsonWriter, final String userId, final String category, final String subcategory,
            final String subsubcategory, final int score)
            throws IOException {
        jsonWriter.beginObject();
        jsonWriter.name("user-id");
        jsonWriter.value(userId);
        jsonWriter.name("categories");
        writeCategories(jsonWriter, category, subcategory, subsubcategory, score);
        jsonWriter.endObject();
    }

    private static void writeCategories(final JsonWriter jsonWriter, final String category, final String subcategory, final String subsubcategory,
            final int score)
            throws IOException {
        jsonWriter.beginArray();
        jsonWriter.beginObject();
        jsonWriter.name("category");
        jsonWriter.value(category);
        jsonWriter.name("subcats");
        writeSubcategories(jsonWriter, subcategory, subsubcategory, score);
        jsonWriter.endObject();
        jsonWriter.endArray();
    }

    private static void writeSubcategories(final JsonWriter jsonWriter, final String subcategory, final String subsubcategory, final int score)
            throws IOException {
        jsonWriter.beginArray();
        jsonWriter.beginObject();
        jsonWriter.name("subcat");
        jsonWriter.value(subcategory);
        jsonWriter.name("subsubcats");
        writeSubsubcategories(jsonWriter, subsubcategory, score);
        jsonWriter.endObject();
        jsonWriter.endArray();
    }

    private static void writeSubsubcategories(final JsonWriter jsonWriter, final String subsubcategory, final int score)
            throws IOException {
        jsonWriter.beginArray();
        jsonWriter.beginObject();
        jsonWriter.name("subsubcat");
        jsonWriter.value(subsubcategory);
        jsonWriter.name("score");
        jsonWriter.value(score);
        jsonWriter.endObject();
        jsonWriter.endArray();
    }

}

注意数据如何写入输出流:一旦有足够的已知数据,就可以轻松将其刷新到输出流。是的,这是一种更难写的方法,但这是另一种选择。

输出:

  

{ “用户ID”: “ID21”, “类别”:[{ “类别”: “英语”, “subcats”:[{ “SUBCAT”: “B2”, “subsubcats”:[{“subsubcat “:” 昆虫”, “分数”:24}]}]}]}