Skip to content
核心力量 edited this page May 10, 2013 · 9 revisions

使用JSON

JSON 是JavaScript Object Notation的缩写,用轻量级的文本形式描述对象的结构与取值。
一个最典型的JSON文本类似于{"id":1,“name”:"King"}
JSON在Java中的实现继承了Map接口,并且可以解析/生成JSON文本。

代码范例

如果字符串变量String str的值为{"id":1,“name”:"King"},可以通过JSON.Parse(CharSequence)方法来解析该字符串,以得到JSON对象。

// 解析JSON文本
JSON json = JSON.Parse(str);

通过调用JSON对象的toString()方法,可以将JSON对象还原成JSON文本。

// 输出JSON文本 {"id":1,"name":"King"}
System.out.println("输出JSON文本:" + json.toString());

如果想格式化JSON文本,则可以调用toString(int)方法,其参数表示缩进字符的个数,通常指定为0。

/* 以0缩进字符输出JSON文本
{
	"id":1,
	"name":"King"
}
*/
System.out.println("格式化输出文本:" + json.toString(0));

JSON对象的attr(String)方法用以读取某个键对应的属性值(类似于Map的get方法)。

System.out.println("读取id属性:" + json.attr("id"));

设置属性的方法则为attr(String,Object),第一个参数为键名,第二个为属性值(类似于Map的put方法)。

json.attr("id", 2);
System.out.println("设置id属性后:" + json.attr("id"));

attr(String,Object)方法支持链式调用。

System.out.println("链式调用attr方法:" + json.attr("id", 3).attr("name", "Quene").toString(0));

值得注意的是,attr系列方法本质上就是基于Map的get/put方法。但考虑到JSON对象之间的引用特性,而这种情况下,get/put方法操作的是“引用”,而非被引用的值本身,因此会导致意想不到的问题,而attr系列方法则始终操作的是值本身。类似地,entrySet()方法返回的键值对中的值也未必是值本身,因此建议使用pairs()方法来遍历键值对。

for(Pair pair: json.pairs()) {
	System.out.println(pair.getKey() + "\t" + pair.getValue());
}

attr还有一个语法糖,那就是会将Map(或者Iterable)值自动转换为JSON(或者JSAN)存放。

Map<String, Object> map = new LinkedHashMap<String, Object>();
map.put("fst", 1);
map.put("sec", 2);
json.attr("map", map);
System.out.println("设置map属性:" + json.toString(0));

此外val方法也同样能获取属性值。

System.out.println("另一种读取属性的方法:" + json.val("id"));

虽然该方法与attr(String)别无二致,但val(String,Object)则允许为null值设置默认值。

// 带默认值的读取方式,如果键对应的值为null,则返回默认值。
System.out.println("带默认值读取type属性:" + json.val("type", "default"));

attr和val系列方法还对Java基本类型进行了支持,当不能进行正确转换时,attr系列方法返回null,val系列方法则可以通过设定额外的默认值防止返回null。

Integer id = json.attrInteger("id");
System.out.println("以整数类型进行读取:" + id);
id = json.attrInteger("map");
System.out.println("对于不能转换类型的返回null:" + id);
id = json.valInteger("map", 123);
System.out.println("对于不能转换类型的设置默认值:" + id);

JSON可以通过反射特性读取POJO,POJO中所有通过getter开放的属性都可以被读取。
假如有下面的POJO类

public class DemoPOJO
{
	private int				id;
	private String				name;
	private double				value;
	private Map<String, Object>		dict;
	private float				income;

	public DemoPOJO()
	{
		this.id = 1;
		this.name = "Joke";
		this.value = 1.23;
		this.dict = new LinkedHashMap<String, Object>();
		this.dict.put("one", 1);
		this.dict.put("two", 2);
		this.income = 100.1f;
	}

	// JSON在反射时,会将Map类对象反射为JSON。
	public Map<String, Object> getDict()
	{
		return dict;
	}

	public int getId()
	{
		return id;
	}

	// 不开放此属性,JSON将不会反射该数据。
	protected float getIncome()
	{
		return income;
	}

	public String getName()
	{
		return name;
	}

	public double getValue()
	{
		return value;
	}
}
DemoPOJO pojo = new DemoPOJO();

JSON.Reflect(Object)方法用来反射读取POJO对象。
这里,由于income属性没有开放对应的getter方法,故不会被反射读取。

JSON reflect = JSON.Reflect(pojo);
System.out.println("反射读取pojo:" + reflect.toString(0));

当然也可以反射读取部分属性,这里仍然不会反射到income数据。

reflect = JSON.Reflect(pojo, "name", "value", "income");
System.out.println("反射读取部分属性:" + reflect.toString(0));

反射部分属性,并对属性名进行映射。

Map<String, String> memMap = new LinkedHashMap<String, String>();
memMap.put("名称", "name");
memMap.put("数值", "value");
reflect = JSON.Reflect(pojo, memMap);
System.out.println("反射读取并映射部分属性:" + reflect.toString(0));

对于后续增加的数据,可以通过预先对JSON对象指定反射模板来进行统一反射。

reflect = new JSON().templateJSAN(DemoPOJO.class, "name", "id", "value");
reflect.attr("demo", pojo);
System.out.println("通过模板对后续加入的数据进行反射:" + reflect.toString(0));
Clone this wiki locally