Jackson JSON 序列化 反序列化

什麼是 Jackson ? https://github.com/FasterXML/jackson

Jackson 主要由如下幾個包組成html

1. Jackson Databind 數據綁定包, 提供基於"對象綁定" 解析的相關 API ( ObjectMapper ) 和"樹模型" 解析的相關 API (JsonNode);基於"對象綁定" 解析的 API 和"樹模型"解析的 API 依賴基於"流模式"解析的 API
2. Jackson Core 核心包,提供基於"流模式"解析的相關 API,它包括 JsonPaser 和 JsonGenerator。 Jackson 內部實現正是經過高性能的流模式 API 的 JsonGenerator 和 JsonParser 來生成和解析 json
3. Jackson Annotations 註解包,提供標準註解功能

Kotlin 插件 -- jackson-module-kotlin https://github.com/FasterXML/jackson-module-kotlin

該模塊增長了對Kotlin類和數據類的序列化/反序列化的支持。 Jackson的附加模塊,用於支持Kotlin語言,特別是方法/構造函數參數名稱的自省,而無需添加顯式的屬性名稱註釋。 該模塊增長了對Kotlin類和數據類的序列化/反序列化的支持。之前,必須在Kotlin對象上存在默認構造函數,以便Jackson能夠反序列化到該對象中。 使用此模塊,能夠自動使用單個構造函數類,還支持具備輔助構造函數或靜態工廠的類。java

快速開始 -> ObjectMapper

databind.ObjectMapper 是 Jackson 提供序列化和反序列化的主要的類, 其繼承關係 public class ObjectMapper extends ObjectCodec implements Versionedgit

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.SerializationFeature

data class User(val name: String = "Unknown", val age: Int = 0)

var mapper = ObjectMapper()

fun main(args: Array<String>) {
	usage()
	mapper.enable(SerializationFeature.INDENT_OUTPUT) // 應用縮進, 加強可讀性
	usage()
}

fun usage() {
	var json = """{"name":"諸葛孔明"}"""
	val syokaku = mapper.readValue(json, User::class.java)
	println("反序列化 $json ->\n$syokaku")

	val ryubi = User("劉備", 38)
	json = mapper.writeValueAsString(ryubi)
	println("序列化 $ryubi ->\n$json")
}

/*
反序列化 {"name":"諸葛孔明"} ->
User(name=諸葛孔明, age=0)
序列化 User(name=劉備, age=38) ->
{"name":"劉備","age":38}
反序列化 {"name":"諸葛孔明"} ->
User(name=諸葛孔明, age=0)
序列化 User(name=劉備, age=38) ->
{
  "name" : "劉備",
  "age" : 38
}
*/

SerializationFeature DeserializationFeature

(反)序列化枚舉,定義了簡單的開/關功能,這些功能影響Java對象的(反)序列化方式

ObjectMapper#enable(SerializationFeature.INDENT_OUTPUT)
等價於
ObjectMapper#configure(SerializationFeature.INDENT_OUTPUT, ture)

ObjectMapper#configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) // 反序列化時忽略多餘的Java類不存在的字段
ObjectMapper#configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false) //在序列化時日期格式默認爲 yyyy-MM-dd'T'HH:mm:ss.SSSZ 
ObjectMapper#setSerializationInclusion(Include.NON_NULL); //在序列化時忽略值爲 null 的屬性 
ObjectMapper#setDefaultPropertyInclusion(Include.NON_DEFAULT); //忽略值爲默認值的屬性

如何配置 Spring 中的 ObjectMapper 呢? MappingJackson2HttpMessageConverter 提供了 getter 方法github

@Configuration
@EnableWebMvc
open class ServletConfig : WebMvcConfigurer {
	override fun configureContentNegotiation(configurer: ContentNegotiationConfigurer) {
		configurer.defaultContentType(MediaType.APPLICATION_JSON_UTF8)
	}

	override fun configureDefaultServletHandling(configurer: DefaultServletHandlerConfigurer) {
		global.log("Spring MVC就緒")
		configurer.enable() // MVC未映射的請求交由容器提供的默認Servlet來處理
	}

	override fun configureMessageConverters(converters: MutableList<HttpMessageConverter<*>>) {
		val stringmc = StringHttpMessageConverter(Charsets.UTF_8)
		stringmc.setWriteAcceptCharset(false)
		converters.add(stringmc)
		
		val jsonmc = MappingJackson2HttpMessageConverter()
		val mapper = jsonmc.getObjectMapper()
		mapper.configure(SerializationFeature.INDENT_OUTPUT, true)
		mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
		converters.add(jsonmc)
		global.log("消息轉換器就緒")
	}
}

註解

Jackson 根據它的默認方式序列化和反序列化 java 對象,若根據實際須要,靈活的調整它的默認方式,能夠使用 Jackson 的註解。經常使用的註解及用法以下。json

@JsonProperty	用於屬性,把屬性的名稱序列化時轉換爲另一個名稱。示例:
@JsonProperty("birth_ date")
private Date birthDate;

@JsonFormat	用於屬性或者方法,把屬性的格式序列化時轉換成指定的格式。示例:
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm")
public Date getBirthDate()

@JsonPropertyOrder	用於類, 指定屬性在序列化時 json 中的順序 , 示例:
@JsonPropertyOrder({ "birth_Date", "name" })
public class Person

@JsonCreator	用於構造方法,和 @JsonProperty 配合使用,適用有參數的構造方法。 示例:
@JsonCreator
public Person(@JsonProperty("name")String name) {…}

@JsonAnySetter	用於屬性或者方法,設置未反序列化的屬性名和值做爲鍵值存儲到 map 中
@JsonAnySetter
public void set(String key, Object value) {
map.put(key, value);
}

@JsonAnyGetter	用於方法 ,獲取全部未序列化的屬性
public Map<String, Object> any() { return map; }

注意, Kotlin 如何從構造方法中指定 Field 的註解app

data class User(@field:JsonProperty("姓名") var name: String = "Unknown", val age: Int = 0)

fun usage() {
	val user = mapper.readValue("""{"姓名":"關羽"}""", User::class.java)
	println(user)
	println(mapper.writeValueAsString(user))
}

/*
User(name=關羽, age=0)
{
  "age" : 0,
  "姓名" : "關羽"
}
*/

屬性可見性

對於一個數據類的屬性而言:ide

  • 若該屬性修飾符是 public,該屬性可序列化和反序列化。
  • 若屬性的修飾符不是 public,可是它的 getter 方法和 setter 方法是 public,該屬性可序列化和反序列化。由於 getter 方法用於序列化, 而 setter 方法用於反序列化。
  • 若屬性只有 public 的 setter 方法,而無 public 的 getter 方 法,該屬性只能用於反序列化。

若想更改默認的屬性可視化的規則,須要調用 ObjectMapper 的方法 setVisibility。函數

ObjectMapper#setVisibility(PropertyAccessor.FIELD, Visibility.ANY); 

PropertyAccessor 支持的類型有 ALL,CREATOR,FIELD,GETTER,IS_GETTER,NONE,SETTER
Visibility 支持的類型有 ANY,DEFAULT,NON_PRIVATE,NONE,PROTECTED_AND_PUBLIC,PUBLIC_ONLY

屬性過濾

經過屬性過濾能夠屏蔽隱私屬性, 屬性過濾有多種實現方式性能

  • 註解
// 從 getter 方法屏蔽
@JsonIgnore
public int getAge() 

// 從 class 屏蔽
@JsonIgnoreProperties(value = { "age","birth_date" }) 
public class Person
  • addMixIn 方法加註解方式@JsonIgnoreProperties ?
  • SimpleBeanPropertyFilter 方式 ?
 FilterProvider filterProvider = new SimpleFilterProvider().addFilter("myFilter", newFilter); 
 mapper.setFilterProvider(filterProvider).writeValueAsString(?);

<hr> https://www.ibm.com/developerworks/cn/java/jackson-advanced-application/index.htmlurl

相關文章
相關標籤/搜索