Quantcast
Channel: PayMoon贝明实验室
Viewing all articles
Browse latest Browse all 130

jackson 读写树

$
0
0
在Java平台(StAX, JAXB等)XML处理质量和多样化的激励下,Jackson为多功能的Java JSON处理包其目标为集快捷、正确、轻量和符合人体工程学与一体。 本文将给出Jackson的功能概览。 JSON的三种处理方式 Jackson提供了三种可选的JSON处理方法(一种方式及其两个变型):
  • 流式 API:(也称为"增量分析/生成") 读取和写入 JSON 内容作为离散事件。
    • org.codehaus.jackson.JsonParser 读, org.codehaus.jackson.JsonGenerator 写。
    • StAX API 的激励。
  • 树模型 :提供一个 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数据:
1
2
3
4
5
6
{
      "name" : { "first" : "Joe", "last" : "Sixpack" },
      "gender" : "MALE",
      "verified" : false,
      "userImage" : "Rm9vYmFyIQ=="
}
用两行代码把它变成一个用户实例:
1
2
ObjectMapper mapper = new ObjectMapper(); // can reuse, share globally
User user = mapper.readValue(new File("user.json"), User.class);
用户类大致如下(源自另一博客):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
public class User {
  private Gender _gender;
  private Name _name;
  private boolean _isVerified;
  private byte[] _userImage;
  public Name getName() {
    return _name;
  }
  public boolean isVerified() {
    return _isVerified;
  }
  public Gender getGender() {
    return _gender;
  }
  public byte[] getUserImage() {
    return _userImage;
  }
  public void setName(final Name n) {
    _name = n;
  }
  public void setVerified(final boolean b) {
    _isVerified = b;
  }
  public void setGender(final Gender g) {
    _gender = g;
  }
  public void setUserImage(final byte[] b) {
    _userImage = b;
  }
  public static class Name {
    private String _first;
    private String _last;
    public String getFirst() {
      return _first;
    }
    public String getLast() {
      return _last;
    }
    public void setFirst(final String s) {
      _first = s;
    }
    public void setLast(final String s) {
      _last = s;
    }
  }
  public enum Gender {
    MALE,
    FEMALE;
  }
}
编组为JSON同样简单:
1
mapper.writeValue(new File("user-modified.json"), user);
对于更复杂的数据绑定 (例如,反编排格式日期到 java.util.Date),Jackson提供注解来自定义编排和反编排的处理过程。 简单的数据绑定示例 如果你没有 (或不想创建)从 JSON到 Java 的相互转化类,简单数据绑定可能是更好的方法。它用相同方式实现完整的数据绑定,除非形式化绑定类型只指定为 Object.class (或 Map.class, List.class,即使需要更多的类型定义)。因此早期绑定JSON的用户数据可能如此实现:
1
Map<String,Object> userData = mapper.readValue(new File("user.json"), Map.class);
userData 像一个的显式结构:
1
2
3
4
5
6
7
8
Map<String,Object> userData = new HashMap<String,Object>();
Map<String,String> nameStruct = new HashMap<String,String>();
nameStruct.put("first", "Joe");
nameStruct.put("last", "Sixpack");
userData.put("name", nameStruct);
userData.put("gender", "MALE");
userData.put("verified", Boolean.FALSE);
userData.put("userImage", "Rm9vYmFyIQ==");
这显然是双向的: 如果利用诸如Map 的结构构建(或从 JSON绑定及修改),也可以如前法实现:
1
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>,方式如下:
1
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
2
3
4
5
6
7
8
9
10
11
ObjectMapper m = new ObjectMapper();
// can either use mapper.readTree(JsonParser), or bind to JsonNode
JsonNode rootNode = m.readValue(new File("user.json"), JsonNode.class);
// ensure that "last name" isn't "Xmler"; if is, change to "Jsoner"
JsonNode nameNode = rootNode.path("name");
String lastName = nameNode.path("last").getTextValue().
if ("xmler".equalsIgnoreCase(lastName)) {
  ((ObjectNode)nameNode).put("last", "Jsoner");
}
// and write it out:
m.writeValue(new File("user-modified.json"), rootNode);
或你想马上构造一棵树,方法如下:
1
2
3
4
5
6
7
8
9
TreeMapper treeMapper = new TreeMapper();
ObjectNode userOb = treeMapper.objectNode();
Object nameOb = userRoot.putObject("name");
nameOb.put("first", "Joe");
nameOb.put("last", "Sixpack");
userOb.put("gender", User.Gender.MALE.toString());
userOb.put("verified", false);
byte[] imageData = getImageData(); // or wherever it comes from
userOb.put("userImage", imageData);
(注意: Jackson 1.2可直接使用ObjectMapper:通过ObjectMapper.createObjectNode()创建userOb -- 上例工作于Jackson 1.0 和 1.1)。 流式 API 示例 最后,还有第三种方式: 涡轮增压、 高性能的方法称为流 API (或增量模式,因为内容是增量读取和写入的)。 只是为了好玩,让我们实现使用"原生"Stream  API 的写入功能 (相当于前面示例): WriteJSON.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
JsonFactory f = new JsonFactory();
JsonGenerator g = f.createJsonGenerator(new File("user.json"));
g.writeStartObject();
g.writeObjectFieldStart("name");
g.writeStringField("first", "Joe");
g.writeStringField("last", "Sixpack");
g.writeEndObject(); // for field 'name'
g.writeStringField("gender", Gender.MALE);
g.writeBooleanField("verified", false);
g.writeFieldName("userImage"); // no 'writeBinaryField' (yet?)
byte[] binaryData = ...;
g.writeBinary(binaryData);
g.writeEndObject();
g.close(); // 重要:强制写入输出,并关闭输出流!
非常不错 (尤其是相对写入所需的工作量,亦即等效的 XML 内容),但肯定比基本对象映射更辛苦。 另一方面,必须完全控制每一个细节。开销很小: 这仍然快于使用 ObjectMapper;并非快很多 ,但还是要快些(一般快或许 20-30%)。也许最重要的是,以流方式输出: 除一些缓冲外,所有内容都将马上输出。这意味着该方式内存使用量也是最小的。 然后如何解析呢?代码可能看起来类似:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
JsonFactory f = new JsonFactory();
JsonParser jp = f.createJsonParser(new File("user.json"));
User user = new User();
jp.nextToken(); // will return JsonToken.START_OBJECT (verify?)
while (jp.nextToken() != JsonToken.END_OBJECT) {
    String fieldname = jp.getCurrentName();
    jp.nextToken(); // move to value, or START_OBJECT/START_ARRAY
    if ("name".equals(fieldname)) { // contains an object
        Name name = new Name();
        while (jp.nextToken() != JsonToken.END_OBJECT) {
            String namefield = jp.getCurrentName();
            jp.nextToken(); // move to value
            if ("first".equals(namefield)) {
                name.setFirst(jp.getText());
            } else if ("last".equals(namefield)) {
                name.setLast(jp.getText());
            } else {
                throw new IllegalStateException("Unrecognized field '" + fieldname + "'!");
            }
        }
        user.setName(name);
    } else if ("gender".equals(fieldname)) {
        user.setGender(Gender.valueOf(jp.getText()));
    } else if ("verified".equals(fieldname)) {
        user.setVerified(jp.getCurrentToken() == JsonToken.VALUE_TRUE);
    } else if ("userImage".equals(fieldname)) {
        user.setUserImage(jp.getBinaryValue());
    } else {
        throw new IllegalStateException("Unrecognized field '" + fieldname + "'!");
    }
}
jp.close(); // ensure resources get cleaned up timely and properly
这是不是您将更多使用的数据绑定方法。 最后提醒的一个窍门: 可可能通过JsonParser 和 JsonGeneratorit 直接实现数据绑定和树模式。请参阅如下方法:
1
2
3
4
JsonParser.readValueAs()
JsonParser.readValueAsTree()
JsonGenerator.writeObject()
JsonGenerator.writeTree()
将实现你期望的结果。 切记,确保所用的 org.codehaus.jackson.map.MappingJsonFactory是"适用数据绑定“的解析器和生成器实例(而非基本的org.codehaus.jackson.JsonFactory)。 原文:http://simpleframework.net/news/view?newsId=15d30bbad7954851ab14aaae4f7d9f5b

Viewing all articles
Browse latest Browse all 130

Trending Articles