JSON简介
JSON 是一种与开发语言无关的、轻量级的数据格式 - JavaScript Object Notation
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。 易于人阅读和编写。同时也易于机器解析和生成。 它基于JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999的一个子集。 JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C, C++, C#, Java, JavaScript, Perl, Python等)。 这些特性使JSON成为理想的数据交换语言。
优点:易于人的阅读和编写,易于程序的解析和生产
基本格式:{key:value}
标准的json数据表示
数据结构:Object、Array
基本类型:String、number、true、false、null
因此如果需要表示时间类型的时候需要使用约定格式的字符串如"YYYY-MM-DD"
然后在后台对数据进行解析
数据结构——object
使用花括号{}包含的键值对结构,key必须是String类型,value为任何基本类型或数据结构
数据结构——Array
使用中括号[]来起始,并用逗号来分割元素
下面这个网站可以帮助你解析json字符串,并生成文件:
JSON Editor Online
{
"array": [
1,
2,
3
],
"boolean": true,
"null": null,
"number": 123,
"object": {
"a": "b",
"c": "d",
"e": "f"
},
"string": "Hello World"
}
注意,JSON文件里不允许注释
具体资料可以查阅-->JSON中文官方网站
这里还有所有语言的示例代码以及相关工具等等内容,十分详尽,如
Java:
JSON-java.
JSONUtil.
jsonp.
Json-lib.
Stringtree.
SOJO.
json-taglib.
Flexjson.
JON tools.
Argo.
jsonij.
fastjson.
mjson.
jjson.
json-simple.
json-io.
JsonMarshaller.
google-gson.
Json-smart.
FOSS Nova JSON.
Corn CONVERTER.
Apache johnzon.
Genson.
JSONUtil.
cookjson.
JavaScript:
JSON.
json2.js.
clarinet.
Oboe.js.
利用org.Json构建json数据
利用org.Json在Java中使用JSONObject对象
Json是Android SDK的官方库
适合移动端开发
例子 JSON和对象的转换,在pom.xml中添加依赖包
<!--JAVA ASON-->
<dependency> <groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20090211</version>
</dependency>
测试类
@Test
public void testJSONObject(){
BasicConfigurator.configure();
JSONObject jsonObject = new JSONObject();
Object nullObject= null;//使编译器跳过对null类型对检查
try {
jsonObject.put("name","张全蛋");
jsonObject.put("age","25.2");
jsonObject.put("birthday","1990-01-01");
jsonObject.put("school","富土康");
jsonObject.put("major", new String[]{"理发", "挖掘机"});
jsonObject.put("hasGirlFriend",false);
jsonObject.put("hascar",nullObject);
jsonObject.put("comment","这是一个注释,因为json格式里是不能使用常规注释手段的");
System.out.println(jsonObject.toString());
} catch (JSONException e) {
e.printStackTrace();
}
//output
//{"birthday":"1990-01-01","major":["理发","挖掘机"],"school":"富土康","name":"张全蛋","comment":"这是一个注释,因为json格式里是不能使用常规注释手段的","hasGirlFriend":false,"age":"25.2"}
}
}
输出
{
"birthday": "1990-01-01",
"major": [
"理发",
"挖掘机"
],
"school": "富土康",
"name": "张全蛋",
"comment": "这是一个注释,因为json格式里是不能使用常规注释手段的",
"hasGirlFriend": false,
"age": "25.2"
}
Json在Java中使用字符串生成JSONObject对象
@Test
public void createJSONObjectByString(){
JSONObject jsonObject = null;
String jsonStr ="{\"errno\":0,\"data\":true,\"errmsg\":\"success\"}";
try {
jsonObject = new JSONObject(jsonStr);
} catch (JSONException e) {
e.printStackTrace();
}
if(jsonObject != null){
System.out.println(jsonObject.toString());
//out:
// {"errno":0,"data":true,"errmsg":"success"}
}
}
Json在Java中使用MAP生成JSONObject对象
@Test
public void createJSONObjectByMap() {
Object nullObject = null;//使编译器跳过对null类型对检查
Map<String, Object> jsonObject = new HashMap<String, Object>();
jsonObject.put("name", "张全蛋");
jsonObject.put("age", "25.2");
jsonObject.put("birthday", "1990-01-01");
jsonObject.put("school", "富土康");
jsonObject.put("major", new String[]{"理发", "挖掘机"});
jsonObject.put("hasGirlFriend", false);
jsonObject.put("hascar", nullObject);
jsonObject.put("comment", "这是一个注释,因为json格式里是不能使用常规注释手段的");
System.out.println(new JSONObject(jsonObject).toString());
//out:{"birthday":"1990-01-01","major":["理发","挖掘机"],"school":"富土康","name":"张全蛋","comment":"这是一个注释,因为json格式里是不能使用常规注释手段的","hasGirlFriend":false,"age":"25.2","hascar":null}
}
Json在Java中使用JavaBean对象来生成JSONObject对象
@Test
public void createJSONObjectbyJavaBean() {
//常用
Message msg = new Message();
msg.errno = 0;
msg.errmsg = "success";
msg.data = true;
System.out.println(new JSONObject(msg).toString());
//out:
//{"errno":0,"data":true,"errmsg":"success"}
}
从文件读取JSON数据
依赖
<!--org.apache.commons.io.FileUtils-->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
测试文件的内容 与测试类文件同级 名为success_message.json
{
"errno": 0,
"errmsg":["智商余额不足","需发红包给刘老师@95820608进行充值!"],
"data":true
}
测试类中的测试方法
@Test
public void readJSONFile() throws IOException, JSONException {
//从当前类的同源文件中查找特定路径的文件
File file = new File(ReadJSONFileSample.class.getResource("/success_message.json").getFile());
String content = FileUtils.readFileToString(file);
JSONObject jsonObject = new JSONObject(content);
if(!jsonObject.isNull("errno")){
System.out.println("错误代码 --> " + jsonObject.getInt("errno"));
}
if(!jsonObject.isNull("errmsg")){
System.out.println("错误信息 --> " + jsonObject.getString("errmsg").toString());
}
if(!jsonObject.isNull("data")){
System.out.println("错误内容 --> " + jsonObject.getBoolean("data"));
}
//out
//错误代码 --> 0
//错误信息 --> ["智商余额不足","需发红包给刘老师@95820608进行充值!"]
//错误内容 --> true
//将JSONObject中的属性值为数组的值读取出来遍历
//如果值不是数组则会导致报错!
if(!jsonObject.isNull("errmsg")){
JSONArray jsonArray = jsonObject.getJSONArray("errmsg");
for (int i = 0; i < jsonArray.length(); i++) {
String m = (String)jsonArray.get(i);
System.out.println(m);
}
}
//out
//智商余额不足
//需发红包给刘老师@95820608进行充值!
}
}
使用Gson 来更加灵活的构建json数据
gson是google提供的开源api
Gson功能更强大可以在json格式和javaObject之间通过反射灵活转换
更适合服务端后台的开发
- 优点:
- 1.轻量, 支持将json字符串反向生成指定类的对象
- 2.支持日期格式
使用Gson生成json
pom.xml 添加依赖
<!--GOOGLE GSON--> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.4</version> </dependency>测试类和测试方法
//使用GSON注解更改序列化后JSON的属性名称
protected class Message{
@SerializedName("ERRNO")
int errno;
String errmsg;
boolean data;
}
@Test
public void gsonCreate(){
Message msg = new Message();
msg.errno = 0;
msg.errmsg = "success";msg.data = true;
Gson gson = new Gson();
String jsonStr = gson.toJson(msg);
System.out.println(jsonStr);
//out:{"ERRNO":0,"errmsg":"success","data":true}
}
使用gsonBuilder定制json的转换规则
protected class FailMessage{
private int errno;
private String errmsg;
private boolean data;
private transient String ignor;//transient 声明的属性不会被序列化
}
@Test
public void gsonCreateByGsonBuilder(){
FailMessage msg = new FailMessage();
msg.errno = -1;
msg.errmsg = "fail";msg.data = false;
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setPrettyPrinting();//美化格式后输出!方便调试
gsonBuilder.setFieldNamingStrategy(new FieldNamingStrategy() {
//通过回调函数修改反射得到的属性值
@Override
public String translateName(Field field) {
if(field.getName().equals("errno")){
return ("error-code");
}else{
return field.getName();
}
}
});
Gson gsonNew = gsonBuilder.create();
System.out.println(gsonNew.toJson(msg));////美化格式后输出!方便调试
//out:
// {
// "error-code": -1, //errno被修改为error-code
// "errmsg": "fail",
// "data": false
// }
}
使用gson反向将json字串转换成指定类
message.json文件内容如下:
{
"errno": 0,
"errmsg":"智商余额不足,需发红包给刘老师@95820608进行充值!",
"data":true
}
测试类
public class Message {
public int errno;
public String errmsg;
public boolean data;
public int getErrno() {
return errno;
}
public void setErrno(int errno) {
this.errno = errno;
}
public String getErrmsg() {
return errmsg;
}
public void setErrmsg(String errmsg) {
this.errmsg = errmsg;
}
public boolean getData() {
return data;
}
public void setData(boolean data) {
this.data = data;
}
@Override
public String toString() {
return "Message{" +
"errno=" + errno +
", errmsg='" + errmsg + '\'' +
", data=" + data +
'}';
}
}
测试方法
@Test
public void GsonReadTest() throws IOException {
File file = new File(GsonSample.class.getResource("/message.json").getFile());
String content = FileUtils.readFileToString(file);
Gson gson = new Gson();
//将json文件转换成指定类
Message msg = gson.fromJson(content, com.niit.mvcdemo.model.Message.class);
System.out.println(msg.toString());
//out:
//Message{errno=0, errmsg='智商余额不足,需发红包给刘老师@95820608进行充值!', data=true}
}
反向将json字串转换成指定带有时间属性的类
class Logger{
private String content;
private Date createtime;
@Override
public String toString() {
return "Logger{content='" + content + '\'' + ", createtime=" + createtime.toString() +'}';
}
}
@Test
public void GsonFromJsonToObject() throws IOException {
Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
//使用gsonBuilder指定时间类型格式将json文件转换成指定类
Logger logger = gson.fromJson("{\"content\":\"Application started...\",\"createtime\":\"1970-01-01 00:00:00\"}", json.GsonSample.Logger.class);
System.out.println(logger.toLocalString());
//out:Logger{content='Application started...', createtime=1970-1-1 0:00:00}
}
小知识
yyyy-MM-dd HH:mm:ss
年-月-日 时:分:秒
大写是为了区分“月”与“分”
顺便说下HH为什么大写,是为了区分12小时制与24小时制。
小写的h是12小时制,大写的H是24小时制。
书写格式和语言规定有关,上述写法是Windows系统中的我们常见的写法,包括日期设置于办公软件在内。在其他语言中有类似的但使用符号或格式不同的写法。
有的时候我们会看到这样的格式:yyyy-M-d H:m:s
mm与m等,它们的区别为是否有前导零:H,m,s表示非零开始,HH,mm,ss表示从零开始。
比如凌晨1点2分,HH:mm显示为01:02,H:m显示为1:2。
以2014年1月1日凌晨1点1分1秒(当天是星期三)为例子介绍一下其他的:
yyyy/yyy/yy/y 显示为 2014/2014/14/4
(3个y与4个y是一样的,为了便于理解多写成4个y)
MMMM/MMM/MM/M 显示为 一月/一月/01/1
(4个M显示全称,3个M显示缩写,不过中文显示是一样的,英文就是January和J)
dddd/ddd/dd/d 显示为 星期三/周三(有的语言显示为“三”)/01/1
(在英文中同M一样,4个d是全称,3个是简称;
dddd/ddd表示星期几,dd/d表示几号)
HH/H/hh/h 显示为 01/1/01 AM/1 AM
剩下的mm/m/ss/s只是前导零的问题了。
yyyy/M/d/dddd H:mm:ss 就是 2014年1月1日星期三 1:01:01
gson转换会自动将数组值映射成实体类对应的集合属性
注意Map会被映射成google自定义的Map类型..
class Product{
private String title;
private String[] array;
private List list;
private Set set;
private Map map;
}
@Test
public void GsonMappingForCollection(){
String jsonStr= "" +
"{\n" +
" \"title\": \"product_id_1\",\n" +
" \"array\": [\n" +
" \"array1\",\n" +
" \"array2\"\n" +
" ],\n" +
" \"list\": [\n" +
" \"list1\",\n" +
" \"list2\"\n" +
" ],\n" +
" \"set\": [\n" +
" \"set2\",\n" +
" \"set1\"\n" +
" ],\n" +
" \"map\": {\n" +
" \"1\": \"map1\",\n" +
" \"2\": \"map2\"\n" +
" }\n" +
"}"
;
//通过gson将制定类的实例转化成json字符串
Product product = new Gson().fromJson(jsonStr,GsonSample.Product.class);
System.out.println(product.title.toString() + "\t\t" + product.title.getClass());
//out: product_id_1 class java.lang.String
System.out.println(Arrays.toString(product.array) + "\t\t" + product.array.getClass());
//out: [array1, array2] class [Ljava.lang.String;
System.out.println(product.set.toString() + "\t\t" + product.set.getClass());
//out: [set2, set1] class java.util.LinkedHashSet
System.out.println(product.list.toString() + "\t\t" + product.list.getClass());
//out: [list1, list2] class java.util.ArrayList
System.out.println(product.map.toString() + "\t\t" + product.map.getClass());
//out: {1=map1, 2=map2} class com.google.gson.internal.LinkedTreeMap
}
jackson实现Json序列化和反序列化
利用fasterxml.jackson实现JSON序列化和反序列化
Gradle依赖
fasterxml.jackson依赖jackson-core, jackson-databind和jackson-annotations.
示例如下:
compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.9.5'
compile group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.9.5'
compile group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: '2.9.5'
序列化和反序列化实现
JSON工具类
我们构造一个JSON工具类,实现JSON序列化和反序列化, 主要用到的类为com.fasterxml.jackson.databind.ObjectMapper, 代码示例如下:
package com.notepad.util;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.HashMap;
import java.util.Map;
public class JsonSerializer {
/**
* JSON序列化
*
* @param object 对象
* @return JSON字符串
*/
public static String serialize(Object object) {
ObjectMapper mapper = new ObjectMapper();
try {
return mapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
e.printStackTrace();
return "";
}
}
/**
* JSON字符串反序列化
*
* @param jsonStr JSON字符串
* @return a Map
*/
public static Map deserialize(String jsonStr) {
try {
return deserialize(jsonStr, Map.class);
} catch (Exception e) {
e.printStackTrace();
return new HashMap();
}
}
public static <T> T deserialize(String jsonStr, Class<T> classType) throws Exception {
return new ObjectMapper().readValue(jsonStr, classType);
}
}
Entity
为测试我们编写的JSON工具类, 定义一个Entity对象。
为了构建的Entity对象被JSON工具类操作, 关于Entity有几点说明:
- Entity对象必须有默认构造函数
- 成员变量必须有对应的Setter方法
- 可选: 可通过@JsonProperty自定义序列化和反序列化对应的字符的名称,如@JsonProperty(“UID”),则序列化时uid字段显示为UID,同理反序列化时找到字符串中UID对应的值,复制给uid。
- 可选:可通过@JsonIgnore注解,过滤掉不需要进行序列化的成员变量。
示例如下:
package com.notepad.thinkingnote.domain;
import com.fasterxml.jackson.annotation.JsonProperty;
public class Entity {
public Entity() {}
public Entity(String uid, String name) {
this.uid = uid;
this.name = name;
}
/** 实体标识符 */
@JsonProperty("UID")
private String uid;
@JsonProperty("name")
private String name;
public void setUid(String uid) {
this.uid = uid;
}
public String getUid() {
return uid;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
单元测试
编写单元测试,测试Entity的序列化和反序列化, 示例如下:
package com.notepad.thinkingnote.domain;
import com.notepad.util.JsonSerializer;
import org.junit.Test;
import static org.junit.Assert.*;
public class EntityTest {
@Test
public void testSerialize() throws Exception {
Entity entity = new Entity("James", "James");
System.out.println(JsonSerializer.serialize(entity));
}
@Test
public void testDeserialize() throws Exception {
String test = "{\"UID\":\"James\",\"name\":\"James\"}";
Entity entity = JsonSerializer.deserialize(test, Entity.class);
System.out.println(entity.getUid() + ":" + entity.getName());
}
}
输出结果如下:
entity的序列化结果, 显示字段UID
{"UID":"James","name":"James"}
entity的序列化结果
James:James
UnrecognizedPropertyException异常解决
通过上面的介绍, 我们基本了解了JSON的序列化和反序列化,不过有时我们会遇到一种问题。
考虑这样一种情况,我们针对Http接口返回的JSON字符串,构建了一个具体的Entity对象,但是当Http接口中突然增加了一个字段type,如果还是按照原来方式解析会如何呢?
@Test
public void testDeserialize() throws Exception {
String test = "{\"UID\":\"James\",\"name\":\"James\", \"type\":\"entity\"}";
Entity entity = JsonSerializer.deserialize(test, Entity.class);
System.out.println(entity.getUid() + ":" + entity.getName());
}
出现UnrecognizedPropertyException异常:
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "type" ....
即对于新添加的type字符无法识别。如何解决这个问题呢?我们这里提供2种方法。
- 方法1 JsonIgnoreProperties注解
利用fasterxml.jackson提供的@JsonIgnoreProperties注解,针对无法识别的属性进行过滤。这里主要是修改需要进行反序列化的对象Entity,示例如下:
针对无法识别的属性进行过滤@JsonIgnoreProperties(ignoreUnknown = true) public class Entity {...} - 方法2 DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
方法1的修改需要对每一个需要进行反序列化的类进行修改, 不太方便。
方法2通过修改JSON工具类的反序列化方法,设置DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES的值为false, 可以仅一次修改就适用全部对象。
示例如下:public static <T> T deserialize(String jsonStr, Class<T> classType) throws Exception { // 添加configure, 设置DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES为false // 则对于无法识别的属性直接过滤 return new ObjectMapper() .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) .readValue(jsonStr, classType); }
Views: 19
