使用反射自定义序列化方法

在使用JSONObject和JSONArray的过程中,往往让人惊叹它的神奇之处,能够很方面的把json对象和bean互相转换,一直在思考究竟后台如何实现的,虽然通过看源码可以得出答案,但毕竟源码过于繁复,短时间内难以尽解,不如自己思考:如果这个功能是我设计的,我会怎么实现呢?其实无非就是使用反射而已,加上循环和迭代,把集合类型和嵌套的对象都迭代出来。

被序列化的类详见:http://blog.csdn.net/salerzhang/article/details/41259471

初始化一个对象:

<span style="white-space:pre">	</span>Student student = new Student();
		student.setName("zxl");
		student.setGerder("M");
		//student.setAddress("beijing");
		Classes cs = new Classes();
		cs.setClaName("计算机1");
		cs.setClsNum("07060341");
		cs.setWay("wentaoyuan1");
		List<Student> list = new ArrayList<Student>();
		list.add(student);
		cs.setStudents(list);
		cs.setStudent(student);

被反序列化的数据:

JSONObject jo = JSONObject.fromObject("{'clsNum':'123','claName':'计算机2','student':{'gerder':'F','name':'zxl'},'students':[{'address':'shanghai','gerder':'M','name':'xxx'}],'way':'wentaoyuan1'}");

JsonConfig:

Map<String, Class<?>> clazz = new HashMap<String, Class<?>>();
		clazz.put("student", Student.class);
		clazz.put("students", Student.class);

		JsonConfig jc = new JsonConfig();
		jc.setClassMap(clazz);
private static Object jsonObjectIterator(Object root, JSONObject jo, JsonConfig jc) throws InstantiationException,
			IllegalAccessException, ClassNotFoundException, SecurityException, NoSuchMethodException,
			IllegalArgumentException, InvocationTargetException, NoSuchFieldException {

		Iterator<String> keys = jo.keys();
		Map<String, Class<?>> clazz = jc.getClassMap();
		while (keys.hasNext()) {
			String key = (String) keys.next();
			if (jo.get(key) instanceof JSONObject) {//嵌套对象
				Object o = Class.forName(clazz.get(key).getName()).newInstance();

				String setMethodName = "set" + key.substring(0, 1).toUpperCase() + key.substring(1);
				o = jsonObjectIterator(o, jo.getJSONObject(key), jc);
				Method setMethod = root.getClass().getMethod(setMethodName, clazz.get(key));
				setMethod.invoke(root, o);
			} else if (jo.get(key) instanceof JSONArray) {//嵌套数组
				JSONArray ja = jo.getJSONArray(key);
				List<Object> list = new ArrayList<Object>();
				Method method = list.getClass().getMethod("add", Object.class);
				for (int i = 0; i < ja.size(); i++) {
					Object o = Class.forName(clazz.get(key).getName()).newInstance();
					jsonObjectIterator(o, ja.getJSONObject(i), jc);
					method.invoke(list, o);
				}
				String setMethodName = "set" + key.substring(0, 1).toUpperCase() + key.substring(1);
				Method setMethod = root.getClass().getMethod(setMethodName, List.class);
				setMethod.invoke(root, list);
			} else {//本级属性
				Field field = root.getClass().getDeclaredField(key);
				if (field.getName().equals(key)) {
					Type type = field.getGenericType();
					String fieldName = key.substring(0, 1).toUpperCase() + key.substring(1);
					setObjectByString(root, jo.getString(key), fieldName, type);
				}
			}
		}
		//		root = setObjectByJson(root, jo, false);

		return root;
	}

该方法需要配置三个参数:

* @param root 主类对象 注意参数是对象而不是类的Class

* @param jo 被反序列化的内容 需要转换成JSONObject再传入

* @param jc classMap 包括classMap的配置等

该方法等的大概逻辑:

遍历JSONObject对象,分三个逻辑处理:

1,属性:按类型处理,不同类型的参数要进行转换,使用方法:

private static void setObjectByString(Object o, String valueFromJson, String name, Type type)
			throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
		String t = type.toString();
		if (t.equals("class java.lang.String")) { // 如果type是类类型,则前面包含"class ",后面跟类名
			Method m = o.getClass().getMethod("get" + name);
			String value = (String) m.invoke(o); // 调用getter方法获取属性值
			// if (value == null) {
			m = o.getClass().getMethod("set" + name, String.class);
			m.invoke(o, valueFromJson);
			// }
		}
		if (t.equals("class java.lang.Integer")) {
			Method m = o.getClass().getMethod("get" + name);
			Integer value = (Integer) m.invoke(o);
			if (value == null) {
				m = o.getClass().getMethod("set" + name, Integer.class);
				m.invoke(o, StringParseUtil.parse2Integer(valueFromJson));
			}
		}
		if (t.equals("class java.lang.Boolean")) {
			Method m = o.getClass().getMethod("get" + name);
			Boolean value = (Boolean) m.invoke(o);
			if (value == null) {
				m = o.getClass().getMethod("set" + name, Boolean.class);
				m.invoke(o, StringParseUtil.parse2Boolean(valueFromJson));
			}
		}
		if (t.equals("class java.util.Date")) {
			Method m = o.getClass().getMethod("get" + name);
			Date value = (Date) m.invoke(o);
			if (value == null) {
				m = o.getClass().getMethod("set" + name, Date.class);
				m.invoke(o, StringParseUtil.parse2Date(valueFromJson));
			}
		}
	}

2,JSONObject类型,获取类型迭代

注意:要找到嵌套类的类路径,这个在ClassMap中,迭代完成后,需要把嵌套对象放进主类对象中。

3,JSONArray类型,先遍历数组,然后迭代

注意:要判断集合的类型,本例中只默认使用List类型,在获取setter方法时,一定要传入集合的的类型,这个类型要与声明的集合类一致(不是实际类型),比如:Classes对象中有一个集合类型的成员变量:private List<Student> students; List是一个接口,在实例化的时候,很可能是ArrayList对象,但这里我们只能用List.class标识setter方法的参数类型,而不能用ArrayList.class。

当集合类型是Map或Set到时候,从本质来说没有大的区别,这里不再赘述。

时间: 2024-10-10 06:58:23

使用反射自定义序列化方法的相关文章

反射_IsDefined判断方法上有自定义的标签

在.NET 4.0(当然也包括4.0以前的版本)下,用反射判断某个方法是否运用了自定义Attribute时,可以通过调用MethodInfo的IsDefined()方法进行确认.当然,IsDefined()方法事实上定义在MethodInfo的父类MemberInfo中,但它仅仅被定义为抽象方法,真正的实现是在MethodInfo的子类DynamicMethod中. 详细网址: http://www.jb51.net/article/85786.htm 原文地址:https://www.cnbl

自定义序列化过程

除了使用事件以外,还可以通过自定义序列化来完成这一过程. 自定义序列化只需要实现ISerializable接口就可以了.它位于using System.Runtime.Serialization; SerializationInfo有点儿类似于BinaryWriter和BinaryReader,用于写入和读取对象的属性值.它主要包括一组AddValue()方法和一组Get<Type>()方法,还有其他一些属性用于获得程序集和类型的信息.StreamingContext则极少使用. 得到和前面类

Java Serializable接口(序列化)理解及自定义序列化

  1 Serializable接口 (1)简单地说,就是可以将一个对象(标志对象的类型)及其状态转换为字节码,保存起来(可以保存在数据库,内存,文件等),然后可以在适当的时候再将其状态恢复(也就是反序列化).serialization 不但可以在本机做,而且可以经由网络操作.它自动屏蔽了操作系统的差异,字节顺序等.比如,在 Windows 平台生成一个对象并序列化之,然后通过网络传到一台 Unix 机器上,然后可以在这台Unix机器上正确地重构(deserialization)这个对象. 不必

.Net Core 自定义序列化格式

序列化对大家来说应该都不陌生,特别是现在大量使用WEBAPI,JSON满天飞,序列化操作应该经常出现在我们的代码上. 而我们最常用的序列化工具应该就是Newtonsoft.Json,当然你用其它工具类也是没问题的,我们重点讲的不是这个工具,我们的重点是高效的可自定义控制的序列化操作. 首先我们说一下大致的序列化原理: 一般情况下,我们把一个实体类,或是数据列表传给工具类(这里我拿Newtonsoft.Json做例子,其它的也是类似的)如: class ClassTest{ public stri

自定义序列化

package File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.io.IOException; public class SerializeTest { public static vo

概述反射和序列化

1.概述反射和序列化 反射:程序集包含模块,而模块包含类型,类型又包含成员.反射则提供了封装程序集.模块和类型的对象.您可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型.然后,可以调用类型的方法或访问其字段和属性 序列化:序列化是将对象转换为容易传输的格式的过程.例如,可以序列化一个对象,然后使用 HTTP 通过 Internet 在客户端和服务器之间传输该对象.在另一端,反序列化将从该流重新构造对象. 2.什么是SOAP,有哪些应用? 答:SOAP(Simple

反射和序列化

反射和序列化是不同的: 反射:程序集包含模块,而模块包含类型,类型又包含成员.反射则提供了封装程序集.模块和类型的对象,可以通过反射动态地创建类型的实例,将类型绑定到现有的         对象,或从现有对象中获取类型,然后可以调用类型的方法或访问其字段和熟悉. 序列化: 序列化是将对象转换为容易传输的格式的过程,比如转化为二进制.xml.json从而在网络中传输.与序列化相反的是反序列化,它将流转换为对象,也就是将在序列化过程中所产生的二进制串.XML.Json等转换成数据结构或对象的过程.将

WinForm TextBox自定义扩展方法数据验证

本文转载:http://www.cnblogs.com/gis-crazy/archive/2013/03/17/2964132.html 查看公司项目代码时,存在这样一个问题:winform界面上有很多信息填写,提交后台服务器更新,但数据的合法验证及值的转换却不太敢恭维,一堆的if判断和转换,便想着是否能扩展个方法出来,琢磨出个思路,记录下来与大家共同探讨,有不对的地方还请大家指正. 设计思路: 1. 由于大部分从TextBox控件中获取数据值,可以扩展个泛型方法出来,直接根据转换后的数据类型

黑马程序员——————&gt; 自定义序列化

在一些特殊的场景下,如果一个类里包含的某些实例变量是敏感信息,例如银行账户信息,这时不希望系统将该实例变量值进行实例化:或者某个实例变量的类型是不可序列化的,因此不希望对该实例变量进行递归实例化,以避免引发异常.   通过在实例变量前面使用transient关键字修饰,可以指定java序列化时无须理会该实例变量.如下Person类与前面的Person类几乎完全一样,只是它的age使用了transient关键字修饰. 1 public class Person implements Seriali