Jackson 框架 用例详解

一、基本介绍

Jackson的功能好处就不介绍

具体见:http://bbs.jee-soft.cn:8086/showtopic-155.aspx

官方介绍:http://www.cowtowncoder.com/blog/archives/2010/11/entry_434.html

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

二、准备工作

1、下载依赖库jar

Jackson maven 目前有2.0暂时使用1.9.8比较稳定


<dependency>


<groupId>org.codehaus.jackson</groupId>


<artifactId>jackson-core-asl</artifactId>


<version>1.9.8</version>


<type>jar</type>


<scope>compile</scope>


</dependency>


<dependency>


<groupId>org.codehaus.jackson</groupId>


<artifactId>jackson-core-lgpl</artifactId>


<version>1.9.8</version>


<type>jar</type>


<scope>compile</scope>


</dependency>

 

 

官方示例:http://wiki.fasterxml.com/JacksonInFiveMinutes

因为下面的程序是用junit测试用例运行的,所以还得添加junitjar包。

版本是junit-4.2.8

2.测试的项目

目前要进行hibernate的懒加载等其它功能,我直接使用joffice项目的工程,避免要配置hibernate等测试环境。

Department.java

/**
* @description 部门管理
* @class Department
* @author 宏天软件
* @company www.jee-soft.cn
* @createtime 2011-1-18AM
* 
*/
public class Department extends BaseModel {

public final static long serialVersionUID = 1L;

/**集团*/
public final static Short ORG_TYPE_GROUP=0;

/**公司*/
public final static Short ORG_TYPE_COMPANY=1;

/**部门*/
public final static Short ORG_TYPE_DEPARTMENT=2;

protected Long depId;

protected String depName;

protected String depDesc;

protected Integer depLevel;

protected Long parentId;

protected String path;

protected Short orgType;

protected Long creatorId;

protected java.util.Date createtime;

protected Long updateId;

protected java.util.Date updatetime;

protected Integer sn;

protected com.htsoft.oa.model.system.Demension demension;

protected Set appUsers = new java.util.HashSet();

protected Set userOrgs = new java.util.HashSet();

protected String chargeIds;

protected String chargeNames;

//====get和set 省略
}

Demension.java

/**
* @description 维度管理
* @class Department
* @author 宏天软件
* @company www.jee-soft.cn
* @createtime 2011-1-18AM
*/
public class Demension extends com.htsoft.core.model.BaseModel {

/**
* 行政维度的id
*/
public final static Long ADMIN_DEMENSION_ID=1l;

protected Long demId;

protected String demName;

protected String demDesc;

protected Long demType;

protected java.util.Set organizations = newjava.util.HashSet();

//====get和set 省略
}

三、一些常用的示例

三、一些常用的示例

具体的帮助类请参考 ——》

jackson.rar (, 下载次数:6)

 

1.ObjectJson


Jackson 框架 用例详解_第1张图片

 

Object可以是StringIntegerLongList ,pojo(实体等对象

         通过调用方法如下:

       

  

 

输出结果:

  1. {"version":null,"orgId":null,"orgPath":null,"depId":1,"depName":"宏天软件","depDesc":"宏天软件","depLevel":1,"parentId":0,"path":"0.1.","orgType":1,"creatorId":1,"createtime":1314547200000,"updateId":1,"updatetime":"1314547200000","sn":null,"chargeIds":"","chargeNames":"","demension":{"version":null,"orgId":null,"orgPath":null,"demId":1,"demName":"行政维度","demDesc":"行政维度","demType":1,"organizations":[]}}
复制代码


2.JsonObject


Jackson 框架 用例详解_第2张图片

 

测试类:


Jackson 框架 用例详解_第3张图片

 

输出结果:

  1. 宏天软件
  2. Mon Aug 29 08:00:00 CST 2011
  3. 行政维度
复制代码

 


3.日期格式设置

你看上面的例子 objectJson日期输入的是时间戳(数字)的格式,那我们需要把它转换成我们需要的日期格式比如:yyyy-MM-dd HH:mm:ss 2种方式解决这个问题:

1)普通的方式

默认是转成timestamps形式的,通过下面方式可以取消timestamps。

objectMapper.configure(Feature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT,false);

 

这样将使时间生成使用所谓的使用 [ISO-8601 ]-compliant notation, 输出类似如下格式的时间: "1970-01-01T00:00:00.000+0000".

当然也可以自定义输出格式:


Jackson 框架 用例详解_第4张图片

 


Jackson 框架 用例详解_第5张图片

 

2)注解方式
可以支持序列化@JsonSerialize(using=CustomDateTimeSerializer.class)
和反序列化(@JsonDeserialize(using=CustomDateTimeDeserializer.class)



Jackson 框架 用例详解_第6张图片

 

Jackson 框架 用例详解_第7张图片

 

然后在你的POJO上找到日期的属性上加上:


76

 

4.解决hibernate延时加载设置

因为jsonplugin用的是java的内审机制.hibernate会给被管理的pojo加入一个 hibernateLazyInitializer属性,jsonplugin会把hibernateLazyInitializer也拿出来操作,并读取里面一个不能被反射操作的属性就产生了这个异常.   
1)不过我用的是jackson来转json,所以想到了用annotation来排除hibernateLazyInitializer这个属性

在你的pojo类声明加上


 

2)采用别人写的相关插件 我用是hibernate3

import com.fasterxml.jackson.datatype.hibernate3.Hibernate3Module;


/**
* 带是否懒加载 的构造方法
* @param forceLazyLoading 是否懒加载   true为懒加载,否则false
*/
public JacksonMapper(boolean forceLazyLoading){
Hibernate3Module mod = new Hibernate3Module();
     mod.configure(Hibernate3Module.Feature.FORCE_LAZY_LOADING, forceLazyLoading);
     registerModule(mod);
}

 

5.设置循环策略 :解决json最头疼的问题死循环  

能够干净地处理循环类型的某些子集,成为父/子链接。 这些都是互相紧密耦合的引用,其中两个对象以层次结构的方式交叉引用,如父/子树节点的关联,或更常见的,ORM采用的表间连接(join)的描述。

对引用问题(或更普遍的,循环引用),JSON没有处理它们的自然方法。,不像Java对象,没有标识信息可用。
  常用的解决方法是只标记一个被忽略的引用(Jackson可通过使用
@ JsonIgnore解实现),但其缺点是反序列化时会丢失实际的耦合目标。
Jackson 有简单的基于注解的解决该问题的方案:两个引用需要一个注解(对连接作@JsonManagedReference 注解,对返回连接作@JsonBackReference注解),并在此基础,Jackson知道要省略反向引用的序列化,但反序列化对象时要恢复它。此方式适用于典型的ORM用例。
1)父子关系引用

直接输出肯定是报循环错误,Jackson 提供了两个注解

@JsonManagedReference @JsonBackReference


@JsonManagedReference

protected com.htsoft.oa.model.system.Demension demension;

 

@JsonBackReference

protected Set appUsers = new java.util.HashSet();

 

 

 

参考这:http://wiki.fasterxml.com/JacksonFeatureBiDirReferences

把官网的例子拿下来分析:New annotations
Annotations are: 
@JsonManagedReference is the "forward" part of reference: one that gets serialized normally, and handling of which triggers back-linkage for the other reference 
Annotated property can be a bean, array, Collection (List, Set) or Map type, and it must be a bean property (handled by a property of type serialized using BeanSerializer 
@JsonBackReference is the "back" part of reference: it will be omitted from serialization, and re-constructed during deserialization of forward reference. 
翻译器翻译:(
新的注解
注解是:
@ JsonManagedReference是“前进”的部分关联:一,通常被序列化,并处理其中触发后面的其他参考联动
注释的属性可以是一个Bean,数组,集合(List,Set)或Map类型,它必须是一个bean的属性(使用的BeanSerializer序列类型的属性处理
@ JsonBackReference是“反向的关联:从序列,它会被省略,向前引用的反序列化过程中重新构建。

Example

Here is a simple example of a double-linked linked list, where references are both in same class 

(这里是一个简单的例子,双联链表,引用都在同一类)


public class Node
{
   public String name; // simple property

   // reference with default name        
   @JsonManagedReference public SimpleTreeNode child; // forward reference, serialized
   @JsonBackReference public Node parent; // backward reference, not serialized

   public SimpleTreeNode() { this(null); }
    public SimpleTreeNode(String n) { name = n; }
	}


Linkage also works for structured types (arrays, Collections, Maps), as long as only forward reference is of such type. For example: 

public class NodeList
{
    @JsonManagedReference
    public List<NodeForList> nodes;
}

public class NodeForList
{
   public String name;
      
    @JsonBackReference public NodeList parent;

    public NodeForList() { this(null); }
    public NodeForList(String n) { name = n; }
}


and it is possible to use multiple references, by specifying distinct names:(通过指定不同的名称,可以使用多个引用:)

public class FullTreeNode
{
    public String name;

    // parent-child links
    @JsonBackReference("parent")
    public FullTreeNode parent;
    @JsonManagedReference("parent")
    public FullTreeNode firstChild;

    // sibling-links
    @JsonManagedReference("sibling")
    public FullTreeNode next;
    @JsonBackReference("sibling")
    protected FullTreeNode prev;
        
    public FullTreeNode() { this(null); }
    public FullTreeNode(String name) {
        this.name = name;
    }
}


One final note: if using getter and setter methods instead of fields, you will may to add reference annotations on both methods (you will always need them in setters which are used for deserialization; getters for forward references are handled correctly without annotations, but getters for serializing back links do need to be annotated). 



2)@JsonIgnore注解

只说父子引用关系的。父子两边都加@JsonIgnore打印字符串为:

{"name":"chris","createDate":"2012-04-18"},{"title":"title"}

 

单向User加该注解

@JsonIgnore

public Set<Article> getArticles() {

   return articles;

}

 

打印结果为:

{"name":"chris","createDate":"2012-04-18"}

{"title":"title","user":{"name":"chris","createDate":"2012-04-18"}}

 

单向Article 加该注解


@JsonIgnore

public User getUser() {

   return user;

}

 

打印结果:

{"name":"chris","createDate":"2012-04-18","articles":[{"title":"title"}]}

{"title":"title"}


6.属性过滤

@JsonIgnoreProperties

这个加在类级别上, 用法很简单@JsonIgnoreProperties({"property1", "property2"})

动态过滤属性,这个比较麻烦。

有两种方法:

1)使用@JsonFilter注解

使用方法为先给ObjectMapper添加一个filter,然后还要在需要过滤的类上加@JsonFilter("filterName")
注解

比如说要过滤User 上的name属性,先

Jacksons.me().filter("myFilter""name").readAsString(user)具体看Jacksons代码。并在User类上加@JsonFilter("myFilter")

有点不爽的是如果用另外一个没有添加该filter的ObjectMapper解析的话会报错。

如果这个User类已经添加了@JsonFilter("myFilter")注解,但在另外一个地方又要解析它并不想过滤name 属性,那只能是Jacksons.me().filter("myFilter"""),然后在读出来。

2)添加混合式注解(暂时这么翻译)

定义一个接口或类先, 在该类上添加@JsonIgnoreProperties("name"), 然后在ObjectMapper的配置项上添加混入注解

输出为:

String mixInUser = Jacksons.me().addMixInAnnotations(User.class, MixInUser.class).readAsString(user);

System.out.println(mixInUser);

可以参考:http://www.cowtowncoder.com/blog/archives/2009/08/entry_305.html

7.其它annotation(注解)

① @JsonAutoDetect (class)这是作用于类的annotation,主要用于指明该类使用annotation,并且可以自动侦测gettersetter,构造方法,以便生成json对象

 @JsonIgnore (method/field):作用于方法或字段,用来表明,当生成json的时候忽略有该annotation的方法或字段

③ @JsonIgnoreProperties (value = { "hibernateLazyInitializer" ,  "password" }) ,主要用于过滤掉一些不需要的属性

④ @JsonPropertyOrder({ "id", "name" }) // ensure that 'id' and 'name' are always serialized before other properties(确保'id''name'的被序列总是在其他属性之前)

可以用来指示明确(但可以是部分的)序列化属性的顺序。

 @ JsonFilterclass):表示这BeanPropertyFilter使用注解的类的属性的动态过滤。此外,一个有定义PropertyFilterProvider ObjectWriter(要么在使用ObjectMapper.filteredWriter(),或ObjectWriter.withFilters()),当序列化用于动态解决实际使用中的过滤器。

 @ JsonIgnoreTypeclass):indicates that properties with annotated type are never to be serialized; this is useful for ignoring metadata accessors used by proxy types or generated classes.

指示,注释类型的物业从来没有被序列化,忽略代理类型或生成的类所使用的元数据存取,这是有用的。

还有些注解,那你就要参考官方的文档了,就看官方文档:


 

你可能感兴趣的:(Jackson 框架 用例详解)