欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

浅谈Java的反射(五)对JavaBean的其他反射操作

程序员文章站 2022-05-02 09:53:37
...
        无论是反射调用对象方法属性,还是利用内省的机制来读取属性描述器从而获得对象属性进行操作,都是Java所提供的一种别样的类型操作方式。但是除了Java本身提供的对对象的内省操作方式外,其他机构在此基础上也封装了一些更便于使用的包来实现这样的操作。我们曾经接触过的很多框架,也正是在这些包提供支持的基础上,再封装出来一系列自己的API的。这些包中,比较经典也是大多数人都接触过的,当然还是Apache公司推出的common系列的包。其中commons-beanutils正式Apache推出的使用便捷方式调用JavaBean的API。让我们看看他的神奇之处吧。
        首先,使用beanutils时,官方也告诉我们他还依赖于另一个包才能使用,就是commons-logging。这个包是Apache公司推出用来日志记录的包。如果没有这个包,运行beanutils相关代码的时候们,会报找不到logFactory的错误。不要问我问什么会依赖,感兴趣的朋友可以到Apache官网上查查。
       当以上两个包都导入到了我们的开发环境中后,我们就可以开始使用beanutils了。使用之前,让我们看看beanutils的官方文档中推荐的几个包。
     
引用
org.apache.commons.beanutils

       这个包是beanutils最主要的包,所有对JavaBean进行内省操作的工具应该都在这个包里面。他是在Java API自己的接口上面进行的扩展,是一套遵循JavaBean命名设计模式的用于辅助属性进行getting和setting操作的底层的实用类。它的动态定义和访问JavaBean属性的机制特别棒。 以上就是Apache官方对beanutils包的介绍(翻译的不好,请见谅)。
     
引用
org.apache.commons.beanutils.converters

        这个包是标准实现Converter借口的,他用于在系统启动的时候预注册ConvertUtils
        这里要解释一下,Apache的beanutils默认支持对基本数据类型的封装转换,但是却不支持对复杂类型的封装转换。举个例子。我们同行在Web页面提交表单或其他数据传输,基本上都是用的String的传入。但是我们后台的javaBean里面,却不止String一种类型的属性。所以JavaBean封装的时候,beanUtils的Converter支持了简单数据类型的彼此转换,当然也支持了String类型转换封装到其他的基本数据类型的属性里。但是如果我们的对象属性有除基本类型外的其他类型,例如Date类,或是其他自定义类型。那么我们就要自己来实现Converter借口,并重写他转换的代码。然后再注册进我们要使用的BeanUtils Converter里面。这样,当我们传入一个String类型的变量,Converter也会将其转换成我们支持的其他复杂类型了。
        当然,除以上两个包外,commons-beanutils里面还有其他的包,大多数也是基于这两个宝上面的,有些实现了本地化的一些操作。还有各种官方已经给我们封装好了的转换器,例如日期转换器,URL转换器,本地float转换器等等。但是很多地方建议使用转换器最好自己去实现,因为Apache推荐的转换器还是存在一些缺陷。而且自己实现也很容易,还可根据自己特殊需求来做。
        接下来,我们通过分析下面的代码来学习一些beanutils包常用的方法。
	public void execute1() throws Exception{
		//通过反射获得一个Animal的对象
		Class clazz = Class.forName("com.ncs.tang.Animal");
		Animal a = (Animal) clazz.newInstance();
		//因为需要字符串自动转日期并封装到JavaBean里
		//这里使用ConvertUtils注册一个Converter,注册的Converter是我们自己实现的。
		//new一个Converter,但是要重写他的convert方法。
		ConvertUtils.register(new Converter() {
			
			public <T> T convert(Class<T> arg0, Object value) {
				if (value == null) {
					return null;
				}
				
				if (!(value instanceof String)) {
					return null;
				}
				String values = (String)value;
				if ("".equals(values.trim())) {
					return null;
				}
				SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
				try {
					return (T) (sdf.parse(values));
				} catch (ParseException e) {
					throw new RuntimeException(e);
				}
			}
		},Date.class);
		//利用BeanUtils提供的setProperty方法,为我们的对象的某个属性设置值。
		//参数1是需要设值的对象,参数2是需要设值的属性,参数3是所设的值。
		BeanUtils.setProperty(a, "name", "golden pig");
		BeanUtils.setProperty(a, "age", 18);
		BeanUtils.setProperty(a, "female", false);
		BeanUtils.setProperty(a, "types", "pig");
		//因为我们自己实现了String转日期,所以这里的日期类属性就能够正常完成自动转换和封装
		BeanUtils.setProperty(a, "brithday", "1982-02-25");
		//打印出每个值,检查是否设置成功。
		System.out.println(a.getName());
		System.out.println(a.getAge());
		System.out.println(a.getTypes());
		System.out.println(a.isFemale());
		System.out.println(a.getBrithday());
	}
	
	@Test
	public void execute2() throws Exception{
        //new 一个map,key就是我们需要设值的属性名,value就是该属性所需要设置的值。
		HashMap map = new HashMap();
		map.put("name", "golden fish");
		map.put("age", "32");
		map.put("female", true);
		map.put("types", "dog");
		map.put("brithday", "1992-12-25");
		
		Animal a = new Animal();
		//使用ConvertUtils来注册一个Converter,这个converter是Aache自己提供给我们的
		//第二个参数当然就是我们需要使用到该Converter的数据类型,这里我们要转换的是日期。
		ConvertUtils.register(new DateLocaleConverter(Locale.CHINA), Date.class);
		//populate方法允许我们为一个对象a简单设值。map就是我们设置的所有值的键值对。
		BeanUtils.populate(a, map);
		
		System.out.println(a.getName());
		System.out.println(a.getAge());
		System.out.println(a.getTypes());
		System.out.println(a.isFemale());
		System.out.println(a.getBrithday());
	}

        补充说明一下。我们常用到的就是beanUtils里面的setProperty方法。用他实现单个属性的赋值。我们也可以一次性批量赋值。当我们前段是使用了一个map来获取一个对象的值。而且map的键就是对象属性的名称,值就是对象属性所需要的赋值。那么我们使用populate方法,就能很轻松的将这个map里面的内容给填充到我们对应的对象里面。
        再来说一下Converter,注册一个Converter使用到的是ConvertUtils里面的register方法。传入的第一个参数是我们需要注册的Converter,第二个参数就是这个Converter所准针对的待转换的类型。以上代码我们分别注册了一个我们自己实现的Converter和Apache带给我们的Converter。但是Apache这个Converter没有非空验证(我们自己设置的有),当遇到输入的日期是空的,他会转换失败而报异常。而我们自己实现的不会报。
        在这里多说一句,其实除了对JavaBean进行操作的BeanUtils包而外,Apache还提供了很多便于我们开发使用的包,虽说有些包也一样有某些缺陷,但是我们可以参考它们实现的原理来封装我们业务上需要的逻辑。喜欢研究的童鞋们,不放到他的官网上看看。实用包真不少,好多都是我们主流框架所依赖的包。
        附件是我上传的当前最新的BeanUtils包和logging包,方便大家测试使用。这两个包里面都有API Doc供大家参考,大家也可以到Apache官方网站上去Download。

        后记: 在家里的JDK1.6,使用BeanUtils只需要dependence一个logging包就行了,但是我在公司使用JDK1.5的时候,发现他还需要依赖一个commons-collections的包,其实在Apache官方网站上,他也说了需要依赖这个包。可能1.6有关于这个包的引用所以不导入也行。可是1.5的JDK如果不导入该包,就会报一个ClassNotFoundException。谨记!