在开发Android的时候,用户端与服务端一般是通过传递Json数据的方式进行通信的,目前主流都是使用Gson库对Json数据进行处理但实际开发的时候,Gson库不一定能满足我们的需求。例如,我曾经做过一个项目,服务器以Json的格式发送数据到客户端,而客户端需要以Map类型的数据回传给服务器。所以在这个时候,我们就需要把Bean类以类似Gson库的方式自动转换成Map数据,以达到提高效率的目的。
创建能自动解析数据的基类BaseBean
该类中只有一个方法,就是toMap。toMap方法的作用是通过class.getDeclaredFields()方法获取class对象的所有属性,然后将属性名转化为map对象的key,属性的值转化为map对象的value。
publicclassBaseBean{
privateMap params;
/**
* @Method: toMap()
* @authorcreate by Tang
* @datedate 16/8/23 下午3:20
* @Description: 把实体类转换成Map类
*/
publicMap toMap() {
Class extends Object> clazz = this.getClass();
Class extends Object> superClass = clazz.getSuperclass();
Field[] fields = clazz.getDeclaredFields();
Field[] superFields = superClass.getDeclaredFields();
if(fields ==null|| fields.length ==0){
returnCollections.EMPTY_MAP;
}
params = new HashMap<>();
try{
for(Field field : fields) {
field.setAccessible(true);
if(field.get(this) !=null){
ParamsName paramsName = field.getAnnotation(ParamsName.class);
String key;
if(paramsName ==null){
key = field.getName();
}else{
key = paramsName.value();
}
if(field.get(this) !=null){
params.put(key , String.valueOf(field.get(this)));
}else{
params.put(key, "null");
}
}
}
for(Field superField : superFields){
if(superField.get(this) !=null){
superField.setAccessible(true);
ParamsName superParamsName = superField.getAnnotation(ParamsName.class);
String superKey;
if(superParamsName ==null){
superKey = superField.getName();
}else{
superKey = superParamsName.value();
}
if(superField.get(this) !=null){
params.put(superKey, String.valueOf(superField.get(this)));
}else{
params.put(superKey, "null");
}
}
}
} catch(IllegalAccessException e) {
e.printStackTrace();
}
returnparams;
}
publicString toString(){
if(params ==null) {
return"null";
}
returnparams.toString();
}
}
上面代码中class就是我们传递进来需要转换成map的Bean基类,superClass则是该类的父类。获取class的父类是由于class.getDeclaredFields方法只能获取自身的属性,而无法获得父类的属性,所以需要获取class对象的父类。
从上面的代码可以看出,将java实体类转换成map对象的方法很简单。通过遍历获得的Field对象,并通过Field.getName方法获取属性的命名作为map对象的key,通过Field.get(class)方法获取属性的值即可。
注 : field.setAccessible(true)的作用是允许获取私有变量。
细心读者可能会发现,有时候我们实体类的命名和服务器发给我们的命名规则是不一样的。但是我们又不想修改属性名的情况下怎么办?Gson库提供给我们的方法是通过注解的方式(@SerializedName)实现对属性的重命名。那么如果我们自定义的Gmap类能不能也实现该功能呢?答案当然是可以的。
通过查看Gson的源码,我们发现Gson实现通过注解对属性进行重命名的方法实际是比较简单的。下面我们来详细看下注解是如何实现属性的重命名的。
通过注解实现属性重命名
先看代码:
注解的定义:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
public @interfaceParamsName {
/**
* @Method: value()
* @author create by Tang
* @date date 16/8/23 下午3:55
* @Description:
* 返回Map的key Name,默认为参数名
*/
String value();
}
在Map类中通过获取属性的注解对map的key实现重命名的方法:
ParamsName paramsName = field.getAnnotation(ParamsName.class);
Stringkey;
if(paramsName ==null){
key= field.getName();
}else{
key= paramsName.value();
}
if(field.get(this) !=null){
params.put(key,String.valueOf(field.get(this)));
}else{
params.put(key,"null");
}
注解的定义很简单,就是常规的java注解的定义。代码的实现也比较简单,通过field.getAnnotation(class)方法获得属性的注解,然后对获得的注解进行判断,如果注解值为空,则返回属性的实际名称,如果注解不为空,则返回注解的值。
使用方法
使用方法很简单,在创建bean类(或需要转化为map数据的类)时继承BaseBean即可,然后在需要的时候调用toMap()方法即可。
小结
以上就是我实现的把java bean类自动转化为map数据的方法。这个方法有个缺点,由于使用了反射的方法每次转化的时候会对java类遍历一次,所以这个方法会影响程序运行的性能。在查看Gson库的源码的时候,我发现Gson有更好的实现方法。具体我会在下一篇文章深度剖析Gson是如何在不影响效率的情况下实现数据的转化的。