原址: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 2 个月前
8c391e04 5 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐