posts - 495,comments - 227,trackbacks - 0
          <2012年9月>
          2627282930311
          2345678
          9101112131415
          16171819202122
          23242526272829
          30123456

          常用鏈接

          留言簿(46)

          隨筆分類(476)

          隨筆檔案(495)

          最新隨筆

          搜索

          •  

          積分與排名

          • 積分 - 1396799
          • 排名 - 16

          最新評論

          閱讀排行榜

          評論排行榜

          http://simpleframework.net/blog/v/20118.html


          在Java平臺(StAX, JAXB等)XML處理質量和多樣化的激勵下,Jackson為多功能的Java JSON處理包其目標為集快捷、正確、輕量和符合人體工程學與一體。

          本文將給出Jackson的功能概覽。

          JSON的三種處理方式 
          Jackson提供了三種可選的JSON處理方法(一種方式及其兩個變型):

          • 流式 API(也稱為"增量分析/生成") 讀取和寫入 JSON 內容作為離散事件。

          • 樹模型 :提供一個 JSON 文檔可變內存樹的表示形式。

            • org.codehaus.jackson.map.ObjectMapper 生成樹 ;樹組成 JsonNode 節點集。

            • 樹模型類似于 XML DOM。
          • 數據綁定: JSON和POJO相互轉換,基于屬性訪問器規約或注解。

            • 兩種變體簡單完整 的數據綁定:

            • 簡單數據綁定: 是指從Java Map、List、String、Numbers、Boolean和空值進行轉換

            • 完整數據綁定 :是指從任何 Java bean 類型 (及上文所述的"簡單"類型) 進行轉換

            • org.codehaus.jackson.map.ObjectMapper 對兩個變種,進行編組(marshalling )處理 (寫入 JSON) 和反編組(unmarshalling ,讀 JSON)。

            • JAXB激勵下的基于注釋的 (代碼優先)變種。

          從使用的角度來看,總結這些3 種方法的用法如下:

          • 流 API: 性能最佳的方式 (最低開銷、 速度最快的讀/寫; 其它二者基于它實現)。

          • 數據綁定 :使用最方便的方式。

          • 樹模型: 最靈活的方式。

          鑒于這些特性,讓我們考慮以相反的順序,以Java開發人員最自然和方便的方法開始使用: 杰Jackson數據綁定 API

          Jackson的 org.codehaus.jackson.map.ObjectMapper "只是"將JSON 數據映射為POJO 對象 。例如,給定 JSON 數據:

          {
            "name" : { "first" : "Joe", "last" : "Sixpack" },
            "gender" : "MALE",
            "verified" : false,
            "userImage" : "Rm9vYmFyIQ=="
          }

          用兩行代碼把它變成一個用戶實例:

          1 ObjectMapper mapper = new ObjectMapper(); // can reuse, share globally
          2 User user = mapper.readValue(new File("user.json"), User.class);

          用戶類大致如下(源自另一博客):

          1 public class User {
          2 public enum Gender { MALE, FEMALE };
          3
          4 public static class Name {
          5 private String _first, _last;
          6
          7 public String getFirst() { return _first; }
          8 public String getLast() { return _last; }
          9
          10 public void setFirst(String s) { _first = s; }
          11 public void setLast(String s) { _last = s; }
          12 }
          13
          14 private Gender _gender;
          15 private Name _name;
          16 private boolean _isVerified;
          17 private byte[] _userImage;
          18
          19 public Name getName() { return _name; }
          20 public boolean isVerified() { return _isVerified; }
          21 public Gender getGender() { return _gender; }
          22 public byte[] getUserImage() { return _userImage; }
          23
          24 public void setName(Name n) { _name = n; }
          25 public void setVerified(boolean b) { _isVerified = b; }
          26 public void setGender(Gender g) { _gender = g; }
          27 public void setUserImage(byte[] b) { _userImage = b; }
          28 }

          編組為JSON同樣簡單:

          mapper.writeValue(new File("user-modified.json"), user);

           對于更復雜的數據綁定 (例如,反編排格式日期到 java.util.Date),Jackson提供注解來自定義編排和反編排的處理過程。

          簡單的數據綁定示例
          如果你沒有 (或不想創建)從 JSON到 Java 的相互轉化類,簡單數據綁定可能是更好的方法。它用相同方式實現完整的數據綁定,除非形式化綁定類型只指定為 Object.class (或 Map.class, List.class,即使需要更多的類型定義)。因此早期綁定JSON的用戶數據可能如此實現:

          Map<String,Object> userData = mapper.readValue(new File("user.json"), Map.class);

           userData 像一個的顯式結構:

             1 Map<String,Object> userData = new HashMap<String,Object>();    2 Map<String,String> nameStruct = new HashMap<String,String>();    3 nameStruct.put("first", "Joe");    4 nameStruct.put("last", "Sixpack");    5 userData.put("name", nameStruct);    6 userData.put("gender", "MALE");    7 userData.put("verified", Boolean.FALSE);    8 userData.put("userImage", "Rm9vYmFyIQ=="); 
          這顯然是雙向的: 如果利用諸如Map 的結構構建(或從 JSON綁定及修改),也可以如前法實現:
          Map<String,Object> userData = mapper.readValue(new File("user.json"), Map.class);
          將如何工作呢? 只定義了Map.class,未定義一般的Key/valie類型,但ObjectMapper 卻知曉與Map(及List、數組、wrapper類型 )之間如何相互轉換,僅是如此即可。如果它可以正確地映射到您所提供的類型,它將被映射。
           
          Jackson將使用簡單數據綁定的具體Java 類型包括:
          JSON Type Java Type
          object LinkedHashMap<String,Object>
          array ArrayList<Object>
          string String
          number(no fraction) Integer, Long or BigInteger (smallest applicable)
          number (fraction) BigDecimal
          true|false boolean
          null null

          泛型的數據綁定

          除綁定到POJO和簡單類型外,還有一個額外的變型:綁定到泛型(類型)容器。此時,由于所謂的類型擦除(Java采用向后兼容的方式實現泛型),需要進行特殊處理,以防止使用類似 Collection<String>.class(不被編譯)。

          所以,熱想綁定數據島Map<String,User>,方式如下:

          Map<String,User> result = mapper.readValue(src, new TypeReference<Map<String,User>>() { });

          其中TypeReference只需傳入泛型類型即可(此時需要匿名內部類):重要部分為<Map<String,User>>,定義要綁定的數據類型。

          若不如此(僅定義Map.class),其調用等價于綁定到 Map<?,?>(亦即 “untyped” Map),如前所述。

          更新:1.3版的Jackson允許利用TypeFactory實現構造類型。

          樹模式示例

          另一種從JSON獲取對象方式是構造“樹”,類似于XML的DOM樹。Jackson構造樹的方法利用JsonNode基類,其中包含公開的通常所需的讀取訪問方法,實際所用的節點類型為其子類;但子類型僅在修改樹時需要。

          JSON樹可通過流式API或ObjectMapper方式讀、寫。

          利用 ObjectMapper,方法如下:

            1 ObjectMapper m = new ObjectMapper();
             2 // can either use mapper.readTree(JsonParser), or bind to JsonNode
             3 JsonNode rootNode = m.readValue(new File("user.json"), JsonNode.class);
             4 // ensure that "last name" isn't "Xmler"; if is, change to "Jsoner"
             5 JsonNode nameNode = rootNode.path("name");
             6 String lastName = nameNode.path("last").getTextValue().
             7 if ("xmler".equalsIgnoreCase(lastName)) {
             8   ((ObjectNode)nameNode).put("last", "Jsoner");
             9 }
            10 // and write it out:
            11 m.writeValue(new File("user-modified.json"), rootNode);

           或你想馬上構造一棵樹,方法如下:

            1 TreeMapper treeMapper = new TreeMapper();
             2 ObjectNode userOb = treeMapper.objectNode();
             3 Object nameOb = userRoot.putObject("name");
             4 nameOb.put("first", "Joe");
             5 nameOb.put("last", "Sixpack");
             6 userOb.put("gender", User.Gender.MALE.toString());
             7 userOb.put("verified", false);
             8 byte[] imageData = getImageData(); // or wherever it comes from
             9 userOb.put("userImage", imageData);

           (注意: Jackson 1.2可直接使用ObjectMapper:通過ObjectMapper.createObjectNode()創建userOb -- 上例工作于Jackson 1.0 和 1.1)。

          流式 API 示例
           
          最后,還有第三種方式: 渦輪增壓、 高性能的方法稱為流 API (或增量模式,因為內容是增量讀取和寫入的)。

          只是為了好玩,讓我們實現使用"原生"Stream  API 的寫入功能 (相當于前面示例): WriteJSON.java

             1 JsonFactory f = new JsonFactory();
             2 JsonGenerator g = f.createJsonGenerator(new File("user.json"));
             3
             4 g.writeStartObject();
             5 g.writeObjectFieldStart("name");
             6 g.writeStringField("first", "Joe");
             7 g.writeStringField("last", "Sixpack");
             8 g.writeEndObject(); // for field 'name'
             9 g.writeStringField("gender", Gender.MALE);
            10 g.writeBooleanField("verified", false);
            11 g.writeFieldName("userImage"); // no 'writeBinaryField' (yet?)
            12 byte[] binaryData = ...;
            13 g.writeBinary(binaryData);
            14 g.writeEndObject();
            15 g.close(); // 重要:強制寫入輸出,并關閉輸出流!

           非常不錯 (尤其是相對寫入所需的工作量,亦即等效的 XML 內容),但肯定比基本對象映射更辛苦。

          另一方面,必須完全控制每一個細節。開銷很小: 這仍然快于使用 ObjectMapper;并非快很多 ,但還是要快些(一般快或許 20-30%)。也許最重要的是,以流方式輸出: 除一些緩沖外,所有內容都將馬上輸出。這意味著該方式內存使用量也是最小的。

          然后如何解析呢?代碼可能看起來類似:

             1 JsonFactory f = new JsonFactory();
             2 JsonParser jp = f.createJsonParser(new File("user.json"));
             3 User user = new User();
             4 jp.nextToken(); // will return JsonToken.START_OBJECT (verify?)
             5 while (jp.nextToken() != JsonToken.END_OBJECT) {
             6   String fieldname = jp.getCurrentName();
             7   jp.nextToken(); // move to value, or START_OBJECT/START_ARRAY
             8   if ("name".equals(fieldname)) { // contains an object
             9     Name name = new Name();
            10     while (jp.nextToken() != JsonToken.END_OBJECT) {
            11       String namefield = jp.getCurrentName();
            12       jp.nextToken(); // move to value
            13       if ("first".equals(namefield)) {
            14         name.setFirst(jp.getText());
            15       } else if ("last".equals(namefield)) {
            16         name.setLast(jp.getText());
            17       } else {
            18         throw new IllegalStateException("Unrecognized field '"+fieldname+"'!");
            19       }
            20     }
            21     user.setName(name);
            22   } else if ("gender".equals(fieldname)) {
            23     user.setGender(Gender.valueOf(jp.getText()));
            24   } else if ("verified".equals(fieldname)) {
            25     user.setVerified(jp.getCurrentToken() == JsonToken.VALUE_TRUE);
            26   } else if ("userImage".equals(fieldname)) {
            27     user.setUserImage(jp.getBinaryValue());
            28   } else {
            29     throw new IllegalStateException("Unrecognized field '"+fieldname+"'!");
            30   }
            31 }
            32 jp.close(); // ensure resources get cleaned up timely and properly

           這是不是您將更多使用的數據綁定方法。

          最后提醒的一個竅門: 可可能通過JsonParser 和 JsonGeneratorit 直接實現數據綁定和樹模式。請參閱如下方法:

          • JsonParser.readValueAs()
          • JsonParser.readValueAsTree()
          • JsonGenerator.writeObject()
          • JsonGenerator.writeTree()

          將實現你期望的結果。
          切記,確保所用的 org.codehaus.jackson.map.MappingJsonFactory是"適用數據綁定“的解析器和生成器實例(而非基本的org.codehaus.jackson.JsonFactory)。

          posted on 2012-09-06 16:47 SIMONE 閱讀(17405) 評論(2)  編輯  收藏 所屬分類: JAVA

          FeedBack:
          # re: Java JSON(二)5分鐘學會Jackson
          2013-12-27 11:50 | 柳qing·
          User user = mapper.readValue(new File("user.json"), User.class);

          讀文件老是錯誤,怎么回事呢?  回復  更多評論
            
          # JSON
          2013-12-28 09:58 | JSON
          JSON是個好東西. 優點數據傳輸體積小,跨平臺跨語言都可以使用.

          另外推薦一個JSON工具 http://www.sojson.com

          無廣告加載快, 很適合新手和經常用JSON的同學們  回復  更多評論
            
          主站蜘蛛池模板: 盐池县| 罗平县| 巴中市| 达拉特旗| 调兵山市| 同心县| 神池县| 冷水江市| 南华县| 沙河市| 唐山市| 依兰县| 扬州市| 新田县| 英德市| 苍山县| 彭泽县| 昭通市| 改则县| 昭平县| 莱西市| 上高县| 新巴尔虎右旗| 于都县| 藁城市| 门源| 泌阳县| 绥化市| 哈密市| 宜黄县| 科技| 凤阳县| 日土县| 灌云县| 民乐县| 秭归县| 渝中区| 江华| 东乌珠穆沁旗| 信宜市| 陕西省|