使用Gson的JsonReader解析Json数据
json
适用于现代 C++ 的 JSON。
项目地址:https://gitcode.com/gh_mirrors/js/json
免费下载资源
·
原址:http://blog.csdn.net/jackie_xiaonan/article/details/15026901
自定义解析过程
这里把问题简化一下,比如获得到的json字符串是 [{"name":"Jackie","age":30,"contact":{"email":"email","phoneno":"phoneno"}},{"name":"Jackie Boy","age":1,"contact":{"email":"email","phoneno":"phoneno"}}]。但其中的age字段对我来说没有意义,因而不想在Bean里专门定义一个字段用来承载。
使用JsonReader
依靠gson提供的类JsonReader,用如下一段样例程序来说明如何解决当前的难题。
public class GsonActivity1 extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_text);
parse();
}
private void parse() {
final Gson gson = new Gson();
final Person jack1 = new Person();
jack1.setAge(30);
jack1.setName("Jackie");
jack1.putValue("email", "email");
jack1.putValue("phoneno", "phoneno");
final Person jack2 = new Person();
jack2.setAge(1);
jack2.setName("Jackie Boy");
jack2.putValue("email", "email");
jack2.putValue("phoneno", "phoneno");
final String json = gson.toJson(Arrays.asList(jack1, jack2));
System.out.println(json);
List<Person> jacks = null;
// 自定义解码处理过程,跳过对字段age的处理
JsonReader reader = null;
InputStream in = null;
try {
in = new ByteArrayInputStream(json.getBytes("UTF-8"));
reader = new JsonReader(new InputStreamReader(in, "UTF-8"));
jacks = decode(reader);
for (final Person person : jacks) {
System.out.println("jack = " + person);
}
} catch (final Exception e) {
e.printStackTrace();
}finally {
if (in != null) {
try {
in.close();
}
catch (final IOException e) {
e.printStackTrace();
}
}
if (reader != null) {
try {
reader.close();
}
catch (final IOException e) {
e.printStackTrace();
}
}
}
}
//如下方法是重点,解析操作的处理过程
private List<Person> decode(JsonReader reader) throws IOException {
List<Person> jacks;
jacks = new ArrayList<Person>();
reader.beginArray();// 通知gson框架,这里开始解析的是数组类型
while (reader.hasNext()) {
Person p = new Person();
jacks.add(p);
reader.beginObject();// 通知gson框架,这里开始解析的是对象
while (reader.hasNext()) {
final String name = reader.nextName();// 提到名、值对中的名
if (name.equals("name")) {
final String value = reader.nextString();
p.setName(value);
} else if (name.equals("contact")) {
reader.beginObject();// 通知gson框架,这里开始解析的是对象
while (reader.hasNext()) {
final String key = reader.nextName();
final String value = reader.nextString();
p.putValue(key, value);
}
reader.endObject();// 通知gson框架,对对象的解析完成
} else {
reader.skipValue();// 跳过不必要的字段,根据之前的设定,这里只能是age
}
}
reader.endObject();// 通知gson框架,对对象的解析完成
}
reader.endArray();// 通知gson框架,数组对象的解析完成
return jacks;
}
class Person {
private String name;
private int age;
private Map<String, Object> contact;
public Person() {
contact = new HashMap<String, Object>();
}
public void putValue(final String key, final Object value) {
contact.put(key, value);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Map<String, Object> getContact() {
return contact;
}
public void setContact(Map<String, Object> contact) {
this.contact = contact;
}
@Override
public String toString() {
return "Person(name="+name + ", age="+age +", contact="+contact.toString() + ")";
}
}
上述代码执行后的输出如下。从输出可以看出,age字段没有赋值,说明上述代码功能正确。
[{"age":30,"contact":{"phoneno":"phoneno","email":"email"},"name":"Jackie"},{"age":1,"contact":{"phoneno":"phoneno","email":"email"},"name":"Jackie Boy"}]
jack = Person(name=Jackie, age=0, contact={email=email, phoneno=phoneno})
jack = Person(name=Jackie Boy, age=0, contact={email=email, phoneno=phoneno})
问题虽然得到了解决,但代价有点高,代码有点多。上述代码用来练练手、学习一下gson的基本原理还行,但如果在项目里也这么应用,一方面太复杂,另一方面gson的能力也没发挥出来。假如缩小问题范围,增加一些约束,比如在定义Java Bean时成员名称和待解析的json串中的字段名相同,并且各字段的值在解析时不需要做复杂的处理,那么依赖强大的gson,上述代码可以做一些简化
public class JsonTest {
public static void main(final String[] args) {
final Gson gson = new Gson();
final Person jack1 = new Person();
jack1.setAge(30);
jack1.setName("Jackie");
jack1.putValue("email", "email");
jack1.putValue("phoneno", "phoneno");
final Person jack2 = new Person();
jack2.setAge(1);
jack2.setName("Jackie Boy");
jack2.putValue("email", "email");
jack2.putValue("phoneno", "phoneno");
final String json = gson.toJson(new <span style="color:#FF0000;">Person[] </span>{ jack1, jack2 });
System.out.println(json);
final Person2[] persons = gson.fromJson(json, <span style="color:#FF0000;">Person2[]</span>.class);
for (final Person2 p : persons) {
System.out.println(p);
}
}
}
@Data
class Person {
private String name;
private int age;
private Map<String, Object> contact;
public Person() {
contact = new HashMap<String, Object>();
}
public void putValue(final String key, final Object value) {
contact.put(key, value);
}
}
// 删除age成员
@Data
class Person2 {
private String name;
private Map<String, Object> contact;
public Person2() {
contact = new HashMap<String, Object>();
}
public void putValue(final String key, final Object value) {
contact.put(key, value);
}
}
输出结果:
[{"age":30,"contact":{"phoneno":"phoneno","email":"email"},"name":"Jackie"},{"age":40,"contact":{"phoneno":"phoneno","email":"email"},"name":"Jackie Boy"}]
Person(name=Jackie, contact={phoneno=phoneno, email=email})
Person(name=Jackie Boy, contact={phoneno=phoneno, email=email})
依赖gson的能力,可以定义一个相同的Java Bean,同时忽略掉不必要的字段age,使用常规的方法即可以完成解析操作。不爽之处在于需要定义一个新的Java Bean。
使用注解
gson的注解Expose是一个有趣的特性,可以在上前述简化方案的基础上少定义一个Java Bean类,但也引入了新的约束,如下是完整的样例。
// 表示通过注解来控制json的解析和生成
Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()//不导出实体中没有用@Expose注解的属性
.create();
Person3 jack1 = new Person3();
jack1.setAge(30);
jack1.setName("Jackie");
jack1.putValue("email", "email");
jack1.putValue("phoneno", "phoneno");
Person3 jack2 = new Person3();
jack2.setAge(1);
jack2.setName("Jackie Boy");
jack2.putValue("email", "email");
jack2.putValue("phoneno", "phoneno");
String json = gson.toJson(new Person3[] { jack1, jack2 });
System.out.println(json);
Person3[] persons = gson.fromJson(json, Person3[].class);
for (Person3 p : persons) {
System.out.println(p);
}
class Person3 {
@Expose
private String name;
@Expose(serialize = true, deserialize = false)// 表示在生成json字符串时输出age成员,但由字符串解析得到对象时,不去获取age字段的值
private int age;// 对于没有使用@Expose标记的字段,则不会在json字符串中出现,同样也不会被解析</span>
@Expose
private Map<String, Object> contact;
public Person3() {
contact = new HashMap<String, Object>();
}
public void putValue(final String key, final Object value) {
contact.put(key, value);
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
}
项目里遇到的场景比较奇葩,待解析的json格式的字符串中还存在一些不必要的字段,但是提供数据的部件为了实现简单,以及所谓的数据完整性,并没有把我当前不关心的数据过滤掉;而我需要的数据格式和对方提供的格式存在较大的差异,这样就不能通过直接对照结构定义Java Bean来直接完成解析操作。现实问题摆在眼前,必须对json解析的过程进行某种控制,使其生成我需要的数据,同时忽略不关心的字段。但是gson很强大,控制解析过程的想法完全是多余的,只要在Java Bean的定义中忽略不必要的字段,然后把类型传递给gson对象来解析输入的字符串,直接就可以得到对应的Java Bean,不需要做特别的处理。
GitHub 加速计划 / js / json
41.72 K
6.61 K
下载
适用于现代 C++ 的 JSON。
最近提交(Master分支:1 个月前 )
960b763e
4 个月前
8c391e04
6 个月前
更多推荐
已为社区贡献2条内容
所有评论(0)