[原创][Annation、范型跟反射的具体应用]属性获取器
[原创][Annation、范型和反射的具体应用]属性获取器
范型和Annation是JDK 1.5的新特性,好多朋友对他感到非常陌生,只是在应用层面上使用它们。下面我们会对一个特定需求,分三个部分来写一个自己的范型和Annation。
需求如下:有两个Annotaion:@Id,@Content,它可以应用在任何JavaBean的属性(Field)上,我们要写一个小程序,来获取指定JavaBean的标注了@Id类型的属性的值,接口如下:
输入一个JavaBean,获取JavaBean中标注了@Id的属性的值,部分实现如下:
首先,我们获取标注了@Id的那个属性:
拼写getter方法:
得到getter方法:
通过反射,得到值:
上面只列出了程序片段,具体大家参见的附件中的project
上面的确实现的我们需求,但有两个限制:
* 1.只能处理Annotaiton为 @Id 类型的
* 2.只能处理Annotation返回值为String类型的
如果属性的值值不为String类型,比如:是Integer或是其它类型的呢,上面的程序就不能胜任了,针对这种情况,我们再做如下修改:
下面是方法实现:
请注意上面的方法,对返回值做了范型,可以返回任意值
上面的改动只是解决了返回值的问题,但目前只支持@Id一种Annotaion,能不能对Annotaion也做范型呢,我输入什么Annotaion,就给我返回标注了Annotaion的属性的值,回答当然是可以的。
我们对接口修改如下:
下面是方法中有改动的地方:
以下是测试:
好了,上面就是范型和注解的具体应用,具体代码大家请参见附件中的代码,欢迎与我一起讨论。
第一个版本就是这样设计的,如下:
但是这样只能获取指定的annotation,且返回值不能指定。
这个签名可能获取任意的annation的属性值,且可以指定返回值的类型:
有问题欢迎与我讨论。
主流语言里泛型最早是在Ada里出现的吧,C++还没见影
这里的String和Id只是定义返回类型和annatation类型的模板,非具体化。声明Id的类型只是让这个方法能应用于更多的annation,如@Id、@Content
范型和Annation是JDK 1.5的新特性,好多朋友对他感到非常陌生,只是在应用层面上使用它们。下面我们会对一个特定需求,分三个部分来写一个自己的范型和Annation。
需求如下:有两个Annotaion:@Id,@Content,它可以应用在任何JavaBean的属性(Field)上,我们要写一个小程序,来获取指定JavaBean的标注了@Id类型的属性的值,接口如下:
public interface IdRetriever<T> { /** * 获取实体的属性值 * * @param entity 实体 * @return * @throws Exception * @author jakoes.wu <br> * @mail wujianchao@hongguaninfo.com <br> * @create 2009-7-24 <br> * @update 2009-7-24 <br> * @version 1.0<br> * @desc <br> */ public String getId(T entity) throws Exception; }
输入一个JavaBean,获取JavaBean中标注了@Id的属性的值,部分实现如下:
首先,我们获取标注了@Id的那个属性:
private Field getIdField(Class clazz) throws Exception{ Field result = null; Field[] fields = clazz.getDeclaredFields(); for(Field field:fields){ if(field.isAnnotationPresent(Id.class)){ Id id = field.getAnnotation(Id.class); result = field; } } if(result == null){ logger.error("该实体类中未找到任何标注@Id的属性"); throw new Exception("该实体类中未找到任何标注@Id的属性"); } return result; }
拼写getter方法:
String fieldName = field.getName(); String methodName = "get" + fieldName.substring(0,1).toUpperCase() + fieldName.substring(1);
得到getter方法:
private Method getMethod(String methodName) throws NoSuchMethodException{ Method getterMethod; try { getterMethod = entityClass.getMethod(methodName); } catch (SecurityException e) { logger.error("方法[" + methodName + "]映射出出现安全错误",e); throw e; } catch (NoSuchMethodException e) { logger.error("没有这个方法[" + methodName + "]",e); throw e; } return getterMethod; }
通过反射,得到值:
String result = (String) getterMethod.invoke(entity, null);
上面只列出了程序片段,具体大家参见的附件中的project
上面的确实现的我们需求,但有两个限制:
* 1.只能处理Annotaiton为 @Id 类型的
* 2.只能处理Annotation返回值为String类型的
如果属性的值值不为String类型,比如:是Integer或是其它类型的呢,上面的程序就不能胜任了,针对这种情况,我们再做如下修改:
package com.jak.generics.getAnnotationValue; /** * * @author jakoes.wu <br> * @create 2009-7-24 <br> * @project java.util <br> * @email wujianchao@hongguaninfo.com * @msn jakoes.wu@hotmail.com * @copyright 2009 HongGuan Information. All rights reserved * @desc <br> * 优化:<br> * 1.对Annotion的返回值进行了范型,可以获取返回值为任意类型的 * 限制:<br> * 1.只能处理Annotaiton为 @Id 类型的 */ public interface IdRetriever2<T,S> { /** * 获取实体的属性值 * * @param entity 实体 * @param resultType 返回值类型 * @return * @throws Exception * @author jakoes.wu <br> * @mail wujianchao@hongguaninfo.com <br> * @create 2009-7-24 <br> * @update 2009-7-24 <br> * @version 1.0<br> * @desc <br> */ public S getId(T entity,Class<S> resultType) throws Exception; }
下面是方法实现:
public S getId(T entity,Class<S> resultType) throws Exception { init(entity,resultType); Field field = getIdField(entityClass); String fieldName = field.getName(); //属性名称 String methodName = "get" + fieldName.substring(0,1).toUpperCase() + fieldName.substring(1); //属性的getter方法 Method getterMethod = getMethod(methodName); S result = (S)getterMethod.invoke(this.entity, null); //通过反射获取属性的值 return result; }
请注意上面的方法,对返回值做了范型,可以返回任意值
上面的改动只是解决了返回值的问题,但目前只支持@Id一种Annotaion,能不能对Annotaion也做范型呢,我输入什么Annotaion,就给我返回标注了Annotaion的属性的值,回答当然是可以的。
我们对接口修改如下:
package com.jak.generics.getAnnotationValue; /** * * @author jakoes.wu <br> * @create 2009-7-24 <br> * @project java.util <br> * @email wujianchao@hongguaninfo.com * @msn jakoes.wu@hotmail.com * @copyright 2009 HongGuan Information. All rights reserved * @desc <br> * 优化: * 1.可以处理任意Annotaiton类型 * 2.可以处理Annotation返回值为任意类型的 */ public interface IdRetriever3<T,R,A> { /** * 获取实体的属性值 * * @param entity 实体 * @param resultType 返回值类型 * @param annotationType Annotation类型 * @return * @throws Exception * @author jakoes.wu <br> * @mail wujianchao@hongguaninfo.com <br> * @create 2009-7-24 <br> * @update 2009-7-24 <br> * @version 1.0<br> * @desc <br> */ public R getValue(T entity,Class<R> resultType,Class<A> annotationType) throws Exception; }
下面是方法中有改动的地方:
if(field.isAnnotationPresent((Class<? extends Annotation>) this.annotationClass)){ A id = (A) field.getAnnotation(Id.class); result = field; }
以下是测试:
User u = new User(); u.setUserId("u-123"); //User的主键的类型为String类型 u.setUserName("jakoes"); Role r = new Role(); r.setRoldId(2323); //Role的主键的类型为Integer类型 r.setRoleName("manager"); //获取标注@Id的值 IdRetriever3<User,String,Id> ui = new IdRetrieverImpl3<User,String,Id>(); String userId = ui.getValue(u,String.class,Id.class); System.out.println(userId); IdRetriever3<Role,Integer,Id> ri = new IdRetrieverImpl3<Role,Integer,Id>(); Integer roleId = ri.getValue(r,Integer.class,Id.class); System.out.println(roleId); //获取标注为@Content的值 IdRetriever3<User, String, Content> ui2 = new IdRetrieverImpl3<User, String, Content>(); String userName = ui2.getValue(u, String.class, Content.class); System.out.println(userName); IdRetriever3<Role, String, Content> ri2 = new IdRetrieverImpl3<Role, String, Content>(); String roleName = ri2.getValue(r, String.class, Content.class); System.out.println(roleName);
好了,上面就是范型和注解的具体应用,具体代码大家请参见附件中的代码,欢迎与我一起讨论。
1 楼
summeryhrb
2009-07-27
泛型用的不是太好,
IdRetriever3<User,String,Id> ui = new IdRetrieverImpl3<User,String,Id>();
String userId = ui.getValue(u,String.class,Id.class);
System.out.println(userId);
ui.getValue(u,String.class,Id.class);
这个方法应该设计为ui.getValue(u);
IdRetriever3<User,String,Id> ui = new IdRetrieverImpl3<User,String,Id>();
String userId = ui.getValue(u,String.class,Id.class);
System.out.println(userId);
ui.getValue(u,String.class,Id.class);
这个方法应该设计为ui.getValue(u);
2 楼
jakoes
2009-07-27
summeryhrb 写道
泛型用的不是太好,
IdRetriever3<User,String,Id> ui = new IdRetrieverImpl3<User,String,Id>();
String userId = ui.getValue(u,String.class,Id.class);
System.out.println(userId);
ui.getValue(u,String.class,Id.class);
这个方法应该设计为ui.getValue(u);
IdRetriever3<User,String,Id> ui = new IdRetrieverImpl3<User,String,Id>();
String userId = ui.getValue(u,String.class,Id.class);
System.out.println(userId);
ui.getValue(u,String.class,Id.class);
这个方法应该设计为ui.getValue(u);
第一个版本就是这样设计的,如下:
public String getId(T entity) throws Exception;
但是这样只能获取指定的annotation,且返回值不能指定。
这个签名可能获取任意的annation的属性值,且可以指定返回值的类型:
public R getValue(T entity,Class<R> resultType,Class<A> annotationType) throws Exception;
有问题欢迎与我讨论。
3 楼
summeryhrb
2009-07-29
我的意思是
IdRetriever3<User,String,Id> ui = new IdRetrieverImpl3<User,String,Id>();
这句话,已经把String和Id这两个类型具体化了,
IdRetriever3<User,String,Id> ui = new IdRetrieverImpl3<User,String,Id>();
这句话,已经把String和Id这两个类型具体化了,
4 楼
summeryhrb
2009-07-29
泛型只是在定义的时候定义成模板,
泛型最开始出现在c++里,在c++里叫模板
泛型最开始出现在c++里,在c++里叫模板
5 楼
ravenex
2009-07-29
summeryhrb 写道
泛型只是在定义的时候定义成模板,
泛型最开始出现在c++里,在c++里叫模板
泛型最开始出现在c++里,在c++里叫模板
主流语言里泛型最早是在Ada里出现的吧,C++还没见影
6 楼
jakoes
2009-08-03
summeryhrb 写道
我的意思是
IdRetriever3<User,String,Id> ui = new IdRetrieverImpl3<User,String,Id>();
这句话,已经把String和Id这两个类型具体化了,
IdRetriever3<User,String,Id> ui = new IdRetrieverImpl3<User,String,Id>();
这句话,已经把String和Id这两个类型具体化了,
这里的String和Id只是定义返回类型和annatation类型的模板,非具体化。声明Id的类型只是让这个方法能应用于更多的annation,如@Id、@Content