简单说一下Jackson

如果想要详细了解一下Jackson,可以去其github上的​​项目主页​​查看其版本情况以及各项功能。除此以外,需要格外提一下Jackson的版本问题。Jackson目前主流版本有两种,1.x和2.x,而这二者的核心包是不同的。在2.0以后的Jackson版本中,groupId从原来的org.codehaus.jackson.core转而变成了com.fasterxml.jackson.core。所以如果希望用到新性能的Jackson,请将原来的maven依赖改为以下的依赖。

下文中的jackson-2-version是指特定的版本,当前的稳定版本为2.8.9。想要了解最新的版本情况还请去项目主页或是maven官网上查看。但是如果是要和spring mvc配合使用的话,还要注意一下他们之间的兼容问题。目前我采用的是4.2.6版本的springmvc和2.6.6版本的jackson


<!-- the core, which includes Streaming API, shared low-level abstractions (but NOT data-binding) -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson-2-version}</version>
</dependency>

​<!-- Just the annotations; use this dependency if you want to
attach annotations to classes without connecting them to the code. -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson-2-version}</version>
</dependency>​

​<!-- databinding; ObjectMapper, JsonNode and related classes are here -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson-2-version}</version>
</dependency>​

​<!-- smile (binary JSON). Other artifacts in this group do other formats. -->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-smile</artifactId>
<version>${jackson-2-version}</version>
</dependency>
<!-- JAX-RS provider -->
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>${jackson-2-version}</version>
</dependency>
<!-- Support for JAX-B annotations as additional configuration -->
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-jaxb-annotations</artifactId>
<version>${jackson-2-version}</version>
</dependency>​

如果是在springmvc中配置maven依赖,则需要的依赖包为​​core,annotation和databind​

从一个bug说起

刚开始上手springmvc的时候并没有详细去了解更多的JSON操作,只是简单的了解了一下如何将对象转化为JSON数据传送回前端。但是在这时出现了一个问题,就是当两个entity之间存在双向依赖时,传回的JSON数据会出现无限的读取情况。也就是说,因为两个实体中都存在着指向对方的指针,导致序列化的时候会出现二者之间不断相互访问的情况。hibernate这种实体设计方式一直让我有些困惑,毕竟在一般代码的设计模式中是应当尽量避免出现双向依赖的。


这里举一个具体的例子说明这个情况。

假设我有一个订单,订单中有多个商品。也就是订单和商品之间是一对多的关系。订单和商品的实体类如下:

订单实体类


​import javax.persistence.*;​

​/**​

​Created by rale on 7/15/17.​


​销售清单中的单品和数量
*/
@Entity
@Table(name = "sales_order_item")
public class SalesOrderItem {
@Id
@GeneratedValue
@Column(name = "order_item_id")
private Long salesOrderItemId;​

​@Column(name = "order_item_quantity")
private int quantity;​

​@Column(name = "order_item_price")
private double salesPrice;​

​//对应的销售单实体类
@ManyToOne
@JoinColumn(name = "order_id")
private SalesOrder salesOrder;​

​public SalesOrderItem() {
}​

​public SalesOrderItem(Long salesOrderItemId){
this.salesOrderItemId = salesOrderItemId;
}​

​public Long getSalesOrderItemId() {
return salesOrderItemId;
}​

​public void setSalesOrderItemId(Long salesOrderItemId) {
this.salesOrderItemId = salesOrderItemId;
}​

​public int getQuantity() {
return quantity;
}​

​public void setQuantity(int quantity) {
this.quantity = quantity;
}​

​public double getSalesPrice() {
return salesPrice;
}​

​public void setSalesPrice(double salesPrice) {
this.salesPrice = salesPrice;
}​

​public SalesOrder getSalesOrder() {
return salesOrder;
}​

​public void setSalesOrder(SalesOrder salesOrder) {
this.salesOrder = salesOrder;
}
}

解决双向依赖的方法如下:

@JsonIgnore

在不希望被序列化的field或property上使用​​@JsonIgnore​​标记,即可使该属性在序列化和解序列化的过程中不被访问。


​@Entity
@Table(name="sales_order")
public class SalesOrder {​


...

<span >/**订单中商品列表清单**/</span>
<span >@OneToMany(mappedBy = <span >"salesOrder"</span>, cascade = CascadeType.ALL, orphanRemoval = true)</span>
<span >@OrderBy(value = <span >"order_item_id"</span>)</span>
<span >@Fetch(FetchMode.JOIN)</span>
<span >@JsonManagedReference</span>
<span >private</span> List<SalesOrderItem> salesOrderItems;

...
<span >//getters and setters</span>

​}​

​@Entity
@Table(name = "sales_order_item")
public class SalesOrderItem {​

...

<span >//对应的销售单实体类</span>
<span >@ManyToOne</span>
<span >@JoinColumn(name = <span >"order_id"</span>)</span>
<span >@JsonBackReference</span>
<span >private</span> SalesOrder salesOrder;

...
<span >//getters and setters</span>

​}​

通过这种方式确保在双向关系中只有单个反向的实例被序列化

@JsonIdentityInfo

该annotation用于标注在entity上。当entity被标注后,jackson在每一次序列化的时候都会为该实例生成专门的ID(也可以是实例自带的属性),通过这种方式辨别实例。这种方式适用于存在一个​​实体关联链的场景​​。比如Order -> OrderLine -> User -> Order


​@Entity
@Table(name="sales_order")
public class SalesOrder {​


...

<span >/**订单中商品列表清单**/</span>
<span >@OneToMany(mappedBy = <span >"salesOrder"</span>, cascade = CascadeType.ALL, orphanRemoval = true)</span>
<span >@OrderBy(value = <span >"order_item_id"</span>)</span>
<span >@Fetch(FetchMode.JOIN)</span>
<span >@JsonIgnoreProperties(<span >"salesOrder"</span>)</span>
<span >private</span> List<SalesOrderItem> salesOrderItems;

...
<span >//getters and setters</span>

​}​

​@Entity
@Table(name = "sales_order_item")
public class SalesOrderItem {​

...

<span >//对应的销售单实体类</span>
<span >@ManyToOne</span>
<span >@JoinColumn(name = <span >"order_id"</span>)</span>
<span >@JsonIgnoreProperties(<span >"salesOrderItems"</span>)</span>
<span >private</span> SalesOrder salesOrder;

...
<span >//getters and setters</span>

​}​

半场小结

其实jackson中还有很多很实用的功能,例如如何将Date类序列化成界面展示的格式等,将在下一次更新中说明。有兴趣的可以收藏加关注哦。