jackson官方快速入门文档

官方地址: http://jackson.codehaus.org/

                  http://wiki.fasterxml.com/JacksonInFiveMinutes

                 http://wiki.fasterxml.com/JacksonDocumentation

Inspired by the quality and variety of XML tooling available for the Java platform (StAX, JAXB, etc.), the Jackson is a multi-purpose Java library for processing JSON. Jackson aims to be the best possible combination of fast, correct, lightweight, and ergonomic for developers.

This page gives an overview of Jackson's capabilities.

JSON Three Ways

Jackson offers three alternative methods (one with two variants) for processing JSON:

  • Streaming API (aka "Incremental parsing/generation") reads and writes JSON content as discrete events.

  • Tree Model provides a mutable in-memory tree representation of a JSON document.

    • org.codehaus.jackson.map.ObjectMapper can build trees; trees consist of JsonNode nodes.

    • The tree model is similar to the XML DOM.
  • Data Binding converts JSON to and from POJOs based either on property accessor conventions or annotations.

    • There are two variantssimple and full data binding

      • Simple data binding means converting to and from Java Maps, Lists, Strings, Numbers, Booleans and nulls

      • Full data binding means converting to and from any Java bean type (as well as "simple" types mentioned above)

    • org.codehaus.jackson.map.ObjectMapper performs the marshalling (writing JSON) and unmarshalling (reading JSON) for both variants.

    • Inspired by the annotation-based (code-first) variant of JAXB.

From usage perspective, one way to summarize these 3 methods is:

Given these properties, let's consider these in the reverse order, starting with what is usually the most natural and convenient method for Java developers: Jackson Data Binding API.

Examples

Full Data Binding (POJO) Example

Jackson's org.codehaus.jackson.map.ObjectMapper "just works" for mapping JSON data into plain old Java objects ("POJOs"). For example, given JSON data

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

It takes two lines of Java to turn it into a User instance:

切换行号显示
   1 ObjectMapper mapper = new ObjectMapper(); // can reuse, share globally
   2 User user = mapper.readValue(new File("user.json"), User.class);

Where the User class looks something like this (from anentry on Tatu's blog):

切换行号显示
   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 }
User.java

Marshalling back to JSON is similarly straightforward:

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

For fancier data binding (e.g., unmarshalling formatted dates into java.util.Date), Jackson provides annotations to customize the marshalling and unmarshalling process.

"Raw" Data Binding Example

(also known as "Untyped", or sometimes "simple" data binding)

In cases where you do not have (and don't want to create) specific Java classes to bind JSON to/from, "Untyped data binding" may be a better approach. It is used same way as full data binding, except that the formal binding type is specified simply as Object.class (or Map.classList.classString[].class if more specific typing is wanted). So the earlier binding of JSON that represent User data could have been done by:

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

and userData would be like one we would explicit construct by:

切换行号显示
   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==");

This obviously works both ways: if you did construct such a Map (or bind from JSON and modify), you could write out just as before, by:

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

How does this work? By specifying Map.class, we do not specify generic key/value types. But ObjectMapper does know how to bind JSON data to and from Maps (and Lists, arrays, wrapper types), and does just that. Fundamentally JSON data has no "real" type as far as Jackson is concerned -- if it can be properly mapped to a type you give, it will be mapped.

Concrete Java types that Jackson will use for simple data binding are:

JSON Type

Java Type

object

LinkedHashMap<String,Object>

array

ArrayList<Object>

string

String

number (no fraction)

IntegerLong or BigInteger (smallest applicable)

number (fraction)

Double (configurable to use BigDecimal)

true|false

Boolean

null

null

Data Binding with Generics

In addition to binding to POJOs and "simple" types, there is one additional variant: that of binding to generic (typed) containers. This case requires special handling due to so-called Type Erasure (used by Java to implement generics in somewhat backwards compatible way), which prevents you from using something like Collection<String>.class (which does not compile).

So if you want to bind data into a Map<String,User> you will need to use:

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

where TypeReference is only needed to pass generic type definition (via anynomous inner class in this case): the important part is <Map<String,User>> which defines type to bind to.

If you don't do this (and just pass Map.class), call is equivalent to binding to Map<?,?> (i.e. "untyped" Map), as explained above.

UPDATE: As an alternative, version 1.3 also allows programmatic construction of types by using TypeFactory.

Tree Model Example

Yet another way to get Objects out of JSON is to build a tree. This is similar to DOM trees for XML. The way Jackson builds trees is to use basic JsonNode base class, which exposes read access that is usually needed. Actual node types used are sub-classes; but the sub-type only needs to be used when modifying trees.

Trees can be read and written using either Streaming API (see below), or using ObjectMapper.

With ObjectMapper, you will do something like:

切换行号显示
   1 ObjectMapper m = new ObjectMapper();
   2 // can either use mapper.readTree(source), or mapper.readValue(source, JsonNode.class);
   3 JsonNode rootNode = m.readTree(new File("user.json"));
   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);

Or if you want to construct a Tree (for the User example) from scratch, you can do:

切换行号显示
   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);

(NOTE: with Jackson 1.2 you can use ObjectMapper directly, using ObjectMapper.createObjectNode() to create userOb -- above example will work with JAckson 1.0 and 1.1)

Streaming API Example

And finally, there is the third way: turbo-charged, high-performance method known as Streaming API (aka incremental mode, since content is read and written incrementally).

Just for fun, let's implement the writing functionality (equivalent to earlier examples) using "raw" Streaming 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(); // important: will force flushing of output, close underlying output stream

Not horribly bad (esp. compared to amount of work needed for writing, say, equivalent XML content), but certainly more laborious than basic Object mapping.

On the other hand, you do have full control over each and every detail. And overhead is minimal: this is still a bit faster than using ObjectMapper; not a whole lot (perhaps 20-30% faster in common cases), but still. And perhaps most importantly, output is done in streaming manner: except for some buffering, all content will be written out right away. This means that memory usage is also minimal.

How about parsing, then? Code could look something like:

切换行号显示
   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(User.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

which is quite a bit more than you'll use with data binding.

One final trick: it is also possible to use data binding and tree model directly from JsonParser and JsonGenerator. To do this, have a look at methods:

  • JsonParser.readValueAs()

  • JsonParser.readValueAsTree()

  • JsonGenerator.writeObject()

  • JsonGenerator.writeTree()

which do about what you might expect them to do.

The only (?) trick is that you MUST make sure you use org.codehaus.jackson.map.MappingJsonFactory for constructing "data-binding capable" parser and generator instances (instead of basicorg.codehaus.jackson.JsonFactory).

Streaming API Example 2: arrays

(as contributed by Ransom Briggs)

Let's consider following POJO:

切换行号显示
   1   public class Foo {
   2     public String foo;
   3   }

and sample JSON stream of:

  String json = [{\"foo\": \"bar\"},{\"foo\": \"biz\"}]";

while there are convenient ways to work on this with databinding (see ObjectReader.readValues() for details), you can easily use streaming to iterate over stream, bind individual elements as well:

切换行号显示
   1   JsonFactory f = new JsonFactory();
   2   JsonParser jp = f.createJsonParser(json);
   3   // advance stream to START_ARRAY first:
   4   jp.nextToken();
   5   // and then each time, advance to opening START_OBJECT
   6   while (jp.nextToken() == JsonToken.START_OBJECT)) {
   7     Foo foobar = mapper.readValue(jp, Foo.class);
   8     // process
   9     // after binding, stream points to closing END_OBJECT
  10   }

Next Steps

You may want to check out rest of JacksonDocumentation for more inspiration.


CategoryJackson

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
spring boot中文文档,从安装到部署。 I. Spring Boot文件 1.关于文档 2.获得帮助 3.第一步 4.使用Spring Boot 5.了解Spring Boot功能 6.转向生产 7.高级主题 II。入门 8.介绍Spring Boot 9.系统要求 9.1.Servlet容器 10.安装Spring Boot 10.1.Java Developer的安装说明 10.1.1.Maven安装 10.1.2.Gradle安装 10.2.安装Spring Boot CLI 10.2.1.手动安装 10.2.2.使用SDKMAN安装! 10.2.3.OSX Homebrew安装 10.2.4.MacPorts安装 10.2.5.命令行完成 10.2.6.Windows Scoop安装 10.2.7.快速启动Spring CLI示例 10.3.从早期版本的Spring Boot升级 11.开发您的第一个Spring Boot应用程序 11.1.创建POM 11.2.添加Classpath依赖项 11.3.编写代码 11.3.1.@RestController和@RequestMapping Annotations 11.3.2.@EnableAutoConfiguration注释 11.3.3.“主要”方法 11.4.运行示例 11.5.创建一个可执行的Jar 12.接下来要阅读的内容 III。使用Spring Boot 13.构建系统 13.1.依赖管理 13.2.Maven 13.2.1.继承Starter Parent 13.2.2.在没有父POM的情况下使用Spring Boot 13.2.3.使用Spring Boot Maven插件 13.3.Gradle 13.4.Ant 13.5.Starters 14.构建您的代码 14.1.使用“默认”包 14.2.找到主应用程序类 15.配置类 15.1.导入其他配置类 15.2.导入XML配置 16.自动配置 16.1.逐步更换自动配置 16.2.禁用特定的自动配置类 17. Spring Beans和依赖注入 18.使用@SpringBootApplication Annotation 19.运行您的应用程序 19.1.从IDE运行 19.2.作为打包应用程序运行 19.3.使用Maven插件 19.4.使用Gradle插件 19.5.热插拔 20.开发人员工具 20.1.Property默认值 20.2.自动重启 20.2.1.记录条件评估中的更改 20.2.2.不包括资源 20.2.3.观看其他路径 20.2.4.禁用重启 20.2.5.使用触发器文件 20.2.6.自定义重新启动类加载器 20.2.7.已知限制 20.3.LiveReload 20.4.全局设置 20.5.远程应用 20.5.1.运行远程客户端应用程序 20.5.2.远程更新 21.包装您的生产

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值