如何使用" JSR-353:用于JSON处理的Java API,"没有方法链接

时间:2014-11-09 21:18:57

标签: java json fluent-interface alternate jsr-353

我想与使用新的JSR-353(JSON Processing的Java API)分享我的问题/答案。具体来说,您可以在2个不同的" API"中操作JSON数据。 Streaming和Object API。

如果您输入" jsr-353教程"进入谷歌你会得到很多结果。

https://jcp.org/en/jsr/detail?id=353〜具体请求的详细信息。

https://jsonp.java.net/ ~API的主要网站,也链接到"文档"下的Oracle教程。位于https://docs.oracle.com/javaee/7/tutorial/doc/jsonp.htm我稍后会详细介绍本教程。

最后这一个

http://www.javabeat.net/java-json-api-jsr-353/

我想先谈谈最后一个链接,因为它为我提供了很多很好的细节,并且是其中一个真正的教程(还有其他的,但它们基本上都是同样的。)

我真正试图了解的API,不仅是这个API的新手,而且通常是JSON。

何时使用流式API和对象模型API?

如果您希望将JSON数据写入字符流(如文件或字节流),那么Streaming API将是最佳选择,因为它直接在缓冲区中执行写入操作不在内存中构造对象树,即在创建最终JSON数据之前没有生成中间形式。

如果要将JSON数据作为内存中的对象树保存,即不写入任何流,而是将树存储在内存中,以便可以重用JSON数据而无需重新分析它或者也可以序列化对象树以保存/保存JSON数据。这里JSON数据将以对象树的形式表示。

现在Streaming API描述对我来说很有意义,我需要保存一个文件,这对我来说很有意义。

对于Object API,它也是有意义的,保存对象,以便我可以在以后的代码中重用它,真棒。

问题是我没有得到我的问题的答案,我将解释我现在正在寻找什么。

我的问题是:

我基本上有一个包含其他对象/数组的对象。

最初我使用BufferedWriter将数据写入新行到文本文件中。

我的格式看起来像这样。

bw.write(1);
bw.newLine();
bw.write(2);
bw.newLine();

for(int i = 0; i < 4; i++)
{
bw.write(i);
bw.newLine();
}

bw.write(2);
bw.newLine();

for(int j = 0; j < 2; j++)
{
bw.write(j);
bw.newLine();
bw.write(j+5);
bw.newLine();
bw.write(2);
bw.newLine();
bw.write(j*4);
bw.newLine();
}

bw.write(12);
bw.newLine();

for(int k = 0; k < 82; k++)
{
bw.write(k);
bw.newLine();
bw.write(k*5);
bw.newLine();

//do some additional code here

bw.write(2);
bw.newLine();
bw.write(k*4);
bw.newLine();
}

然后结束。数字等等是占位符,实际上从写入数据到循环量的所有内容都是我从另一个文件中读取的可变数据。

正如你所看到的,我无法使用传统的&#34;方法链接&#34;随JSR-353一起提供。

关于链接的方法,请查看wiki http://en.wikipedia.org/wiki/Method_chaining。使用Streaming API的方法链接示例如下所示:

FileWriter writer = new FileWriter("c:\\example.txt");
JsonGenerator gen = Json.createGenerator(writer);

gen.writeStartObject()
   .write("firstName", "Duke")
   .write("lastName", "Java")
   .write("age", 18)
   .write("street/Address", "100 Internet Dr")
   .write("city", "JavaTown")
   .write("state", "JA")
   .write("postalCode", "12345")
   .writeStartArray("phoneNumbers")
      .writeStartObject()
         .write("type", "mobile")
         .write("number", "111-111-1111")
      .writeEnd()
      .writeStartObject()
         .write("type", "home")
         .write("number", "222-222-2222")
      .writeEnd()
   .writeEnd()
.writeEnd();
gen.close();

我还查看了Oracle教程,这让我感到困惑,我看到了#34;生成/解析&#34;因为我正在寻找一种保存文件的方法。

https://docs.oracle.com/javaee/7/tutorial/doc/jsonp001.htm

  

19.1.3生成和解析JSON数据

     

为了生成和解析JSON数据,有两种编程模型,类似于用于XML文档的编程模型。

     

流模型使用基于事件的解析器,一次读取一个元素的JSON数据。当对象或数组开始或结束,找到键或找到值时,解析器生成事件并停止处理。应用程序代码可以处理或丢弃每个元素,然后解析器继续执行下一个事件。这种方法适用于本地处理,其中元素的处理不需要来自其余数据的信息。 流模型通过一次调用一个元素来生成给定流的JSON输出。

教程提到了这一点,但它确切地混淆了这意味着什么,特别是我认为这是写作而不是阅读。当它提到最后一行(以粗体显示)时,为什么它会一次一个地做到这一点并没有多大意义,并使它看起来只处理对象的一部分而不是整体,作为对象API提到处理整个树。

因此,我开始使用Object API,而不是处理Streaming API。我尝试首先将文件保存到FileWriter,但不会保存任何内容。最后我切换到StringWriter并在我的项目中使用它。我决定在完成我的结构之后切换回FileWriter并以某种方式保存到文件中,但我意识到我的部分代码在最后被截断了。我试图做一个小结构,它什么都不打印。

2 个答案:

答案 0 :(得分:8)

现在回答我的问题。

允许我使用Object API写入文件是一些奇怪的错误,因为显然Object API并不是要保存任何数据,而只是将其保存为Object。 Streaming API的目的是保存或发送到流,但根本不保存。如果我们需要这两个选项,那么选择这两个选项是很方便的。

在遇到这个问题后,我决定切换回Streaming API并且它可以工作,所以我想分享我对Streaming API和Object API的答案,因为两者都有不同的编码方式。

使用Method-Chaining的流式API

private static void buildJsonUsingStreamingApi() {

  //Create a StringWriter instance to buffer the JSON data.
  StringWriter writer = new StringWriter();

  //Create a JSON generator backed by the StringWriter instance created above.
  JsonGenerator generator = Json.createGenerator(writer);

  //Start building the JSON Data- Uses Method chaining technique.
  //The JSON data gets streamed in the buffer as and when the
  //different methods are invoked.
  generator.writeStartArray()
            .writeStartObject()//Indicates the start of an JSON object
              .write("parentid", 23424900)
              .write("name","Mexico City")
              .write("url", "http://where.yahooapis.com/v1/place/116545")
              .writeStartObject("placeType")//Creating a nested object i.e an JSON object withing another object
                .write("name","Town")
                .write("code", 7)
              .writeEnd()
              .write("woeid", 116545)
            .writeEnd()//Indicates the end of an JSON object
            .writeStartObject()
              .write("name","Jackson")
              .write("url", "http://where.yahooapis.com/v1/place/2428184")
              .writeStartObject("placeType")
                .write("name","Town")
                .write("code", 7)
              .writeEnd()
            .write("parentid", 23424977)
            .write("woeid", 2428184)
            .writeEnd()
          .writeEnd();//Indicates the end of the JSON array.
  //Writes the data in the buffer to the String buffer.
  generator.flush();

  //Prints the JSON data onto the console.
  System.out.println(writer.toString());
}

输出:

[
 {
   "parentid": 23424900,
   "name": "Mexico City",
   "url": "http://where.yahooapis.com/v1/place/116545",
   "placeType": {
     "name": "Town",
     "code": 7
   },
   "woeid": 116545
 },
 {
   "name": "Jackson",
   "url": "http://where.yahooapis.com/v1/place/2428184",
   "placeType": {
     "name": "Town",
     "code": 7
   },
   "parentid": 23424977,
   "woeid": 2428184
 }
]

现在你可以看到直接的方法,但是我不能用我的应用程序做到这一点,所以这就是我完成它的方法。

没有方法链接的流式传输API

         FileWriter fw = new FileWriter("c:\\example.txt");

        JsonGenerator gen = Json.createGenerator(fw);
        JsonGenerator mainObj = gen.writeStartObject(); //create your start object from the generator

        mainObj.write("object1", 10); //write value:key pairs as needed
        mainObj.write("object2", 1);
        mainObj.write("object3", 11);
        mainObj.write("object4", 11);
        mainObj.write("object5", 12); 

        JsonGenerator loop1 = mainObj.writeStartArray("Loop1"); //When needing to create a new 
                                                               //Array create a new start array                                                                                         
       for(int i = 0; i < 2; i++)     //based on the parent Object/Array, in this case "mainObj."
          loop1.write(5);            //could method chain

        loop1.writeEnd(); //in this case I did not need to create a new  
                          //object for each as I have only one element.

        JsonGenerator loop2 = mainObj.writeStartArray("Loop2"); //same as above to create Array.
        JsonGenerator loopObj2;                                //create new object 


        for(int i = 0; i < 9; i++)
        {

           loopObj2 = loop2.writeStartObject();         //using method-chaining with inner object
                   .write("LoopItem1",10)               //creates an object each time from loop2.
                   .write("LoopItem2",12).writeEnd();   //note method-chaining doesn't have to be 
                                                        //used here
              /*loop2.writeStartObject()                //If we switched to using this code we 
                .write("LoopItem1",10)                  //would be stuck with method-chaining.    
               .write("LoopItem2",12).writeEnd();*/     //loopObj2 isn't needed technically.

        }
        loop2.writeEnd();

        JsonGenerator loop3 = mainObj.writeStartArray("Loop3"); //same as above
        JsonGenerator loopObj3; //same as above

         for(int i = 0; i < 3; i++)
        {
             loopObj3 = loop3.writeStartObject(); //create new object from loop3.
                                                 //note this is exactly the same as above, we 
                                                //just don't use method chaining here, even                 
                                               //though we could chain the first 3



            loopObj3.write("LoopItem1", 57);
            loopObj3.write("LoopItem2", 67);
            loopObj3.write("LoopItem3", 0);
            System.out.println("Breaking Method-Chain just to do it...");
            loopObj3.write("LoopItem4", 9);
            loopObj3.writeEnd();                
        }

        loop3.writeEnd();
        mainObj.writeEnd();
        gen.close();

输出:

{  
   "object1":10,
   "object2":1,
   "object3":11,
   "object4":11,
   "object5":12,
   "Loop1":[  
      5,
      12,
      5,
      12
   ],
   "Loop2":[  
      {  
         "LoopItem1":10,
         "LoopItem2":12
      },
      {  
         "LoopItem1":10,
         "LoopItem2":12
      },
      {  
         "LoopItem1":10,
         "LoopItem2":12
      },
      {  
         "LoopItem1":10,
         "LoopItem2":12
      },
      {  
         "LoopItem1":10,
         "LoopItem2":12
      },
      {  
         "LoopItem1":10,
         "LoopItem2":12
      },
      {  
         "LoopItem1":10,
         "LoopItem2":12
      },
      {  
         "LoopItem1":10,
         "LoopItem2":12
      },
      {  
         "LoopItem1":10,
         "LoopItem2":12
      }
   ],
   "Loop3":[  
      {  
         "LoopItem1":57,
         "LoopItem2":67,
         "LoopItem3":0,
         "LoopItem4":9
      },
      {  
         "LoopItem1":57,
         "LoopItem2":67,
         "LoopItem3":0,
         "LoopItem4":9
      },
      {  
         "LoopItem1":57,
         "LoopItem2":67,
         "LoopItem3":0,
         "LoopItem4":9
      }
   ]
}

我还想展示如何使用方法链接和调用来完成循环3。

            loopObj3.write("LoopItem1", 57)
            .write("LoopItem2", 67)
            .write("LoopItem3", 0);

            System.out.println("Breaking Method-Chain just to do it...");

            loopObj3.write("LoopItem4", 9);
            loopObj3.writeEnd();  

具有方法链接的对象API

    private static void buildJsonUsingObjectModelApi() {
  System.out.println("Json Building using Object Model API");
  JsonArray jsonArray =
          //Create an Array Builder to build an JSON Array
          Json.createArrayBuilder()
            .add(Json.createObjectBuilder()//Create an Object builder to build JSON Object
              .add("parentid", 23424900)
              .add("name","Jackson")
              .add("url", "http://where.yahooapis.com/v1/place/2428184")
              .add("placeType", Json.createObjectBuilder()//Another nested JSON Object
                    .add("name", "Town")
                    .add("code",7)
                  )
              .add("woeid", 116545)
              .build()//The JSON Object completely constructed.
            )
            .add(Json.createObjectBuilder()//Another object builder to build JSON Object.
              .add("name","Mexico City")
              .add("url", "http://where.yahooapis.com/v1/place/116545")
              .add("placeType", Json.createObjectBuilder()
                    .add("name", "Town")
                    .add("code",7)
                  )
              .add("parentid", 23424977)
              .add("woeid", 2428184)
              .build()
             )
            .build();
  StringWriter writer = new StringWriter();

  //Extracting the JSON data from the JSON object tree into the string.
  Json.createWriter(writer).writeArray(jsonArray);

  System.out.println(writer.toString());

}

输出:

    [
   {
      "parentid":23424900,
      "name":"Jackson",
      "url":"http://where.yahooapis.com/v1/place/2428184",
      "placeType":{
         "name":"Town",
         "code":7
      },
      "woeid":116545
   },
   {
      "name":"Mexico City",
      "url":"http://where.yahooapis.com/v1/place/116545",
      "placeType":{
         "name":"Town",
         "code":7
      },
      "parentid":23424977,
      "woeid":2428184
   }
]

没有方法链接的对象API

            JsonObjectBuilder mainObj = Json.createObjectBuilder();

            mainObj.add("object1", 10);
            mainObj.add("object2", 1);
            mainObj.add("object3", 11);
            mainObj.add("object4", 11);
            mainObj.add("object5", 12); 

            JsonArrayBuilder loop1 = Json.createArrayBuilder();
            for(int i = 0; i < 2; i++)
                loop1.add(i);

            mainObj.add("Loop1", loop1);


            JsonArrayBuilder loop2 = Json.createArrayBuilder();
            for(int i = 0; i < 9; i++)
            {


                loop2.add(Json.createObjectBuilder()
                .add("LoopItem1",10)
                .add("LoopItem2",12));
            }
            mainObj.add("Loop2",loop2);




            JsonArrayBuilder loop3 = Json.createArrayBuilder();
            JsonObjectBuilder loop3Obj;
            for(int i = 0; i < 3; i++)
            {
                loop3Obj = Json.createObjectBuilder()
                .add("LoopItem1", 57)
                .add("LoopItem2", 67)
                .add("LoopItem3", 0);
                System.out.println("Breaking Method-Chain just to do it...");
                loop3Obj.add("LoopItem4", 9);


             loop3.add(loop3Obj);

            }

                mainObj.add("Loop3", loop3);

        JsonObject planObj = mainObj.build();
            StringWriter writer = new StringWriter();
            JsonWriter jwrite = Json.createWriter(writer);
            jwrite.write(planObj);
             System.out.println(planObj.toString());

输出:

   {
   "object1":10,
   "object2":1,
   "object3":11,
   "object4":11,
   "object5":12,
   "Loop1":[
      0,
      1
   ],
   "Loop2":[
      {
         "LoopItem1":10,
         "LoopItem2":12
      },
      {
         "LoopItem1":10,
         "LoopItem2":12
      },
      {
         "LoopItem1":10,
         "LoopItem2":12
      },
      {
         "LoopItem1":10,
         "LoopItem2":12
      },
      {
         "LoopItem1":10,
         "LoopItem2":12
      },
      {
         "LoopItem1":10,
         "LoopItem2":12
      },
      {
         "LoopItem1":10,
         "LoopItem2":12
      },
      {
         "LoopItem1":10,
         "LoopItem2":12
      },
      {
         "LoopItem1":10,
         "LoopItem2":12
      }
   ],
   "Loop3":[
      {
         "LoopItem1":57,
         "LoopItem2":67,
         "LoopItem3":0,
         "LoopItem4":9
      },
      {
         "LoopItem1":57,
         "LoopItem2":67,
         "LoopItem3":0,
         "LoopItem4":9
      },
      {
         "LoopItem1":57,
         "LoopItem2":67,
         "LoopItem3":0,
         "LoopItem4":9
      }
   ]
}

前3个被链接,然后我有我的阻止器,它只是println,然后我写了另一个项目,然后writeEnd()与单独的方法调用。

现在有些人可能会抱怨“但你确实在你的一个内部对象中使用方法链接!!!”是的,是的,但是正如我所提到的那样,我没有必要,而且我想解释一下,无论有没有,我都可以这样做,甚至可以同时使用它们来表现出灵活性。

我希望这有助于其他人。这花了我几天时间来学习和理解API,所以我想分享我的发现。我也花了大约3-4个小时来编写本教程,所以我希望它能得到一些用处,人们会喜欢它。

谢谢大家:)。

答案 1 :(得分:-2)

向Oracle人员发表讲话,JSR 353教程链接已经更改。链接现在是:

http://docs.oracle.com/javaee/7/tutorial/jsonp.htm

(tutorial / jsonp.htm而非教程/ doc /jsonp.htm)

“文档”链接也已修复:

https://jsonp.java.net/

并且可能是更可靠的链接,而不是指向教程的直接链接。

OP可能希望使用此更新进行编辑。