1.需求
有时候,在项目开发时候会遇到,特别是Web项目开发,本地工程有一个类A,web工程根据配置文件会自动生成另外一个class B,而A和B除了类名不同,
其他诸如成员变量以及get\set方法都是相同的(就像下面的Objec1和Object2两个类一样),这时候,就会需要一个API将A的对象转换成B的对象在Web上进行消息交互。
public class Object1
{
private int attrInt;
public int getAttrInt()
{
return attrInt;
}
public void setAttrInt(int attrInt)
{
this.attrInt = attrInt;
}
}
public class Object2
{
private int attrInt;
public int getAttrInt()
{
return attrInt;
}
public void setAttrInt(int attrInt)
{
this.attrInt = attrInt;
}
}
2.使用Java语言中的放射技术进行通用转换API实现
默认的转换是进行完整的转换,具体使用可以调用方法toAnotherObj(K oneObj, Class<V> anotherClassObj)
package devin.wu.training.reflect.convertor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class ObjectConvertor
{
public <K,V> V toAnotherObj(K oneObj, Class<V> anotherClassObj)
{
return toAnotherObj(oneObj, anotherClassObj, null);
}
public <K,V> V toAnotherObj(K oneObj, Class<V> anotherClassObj, FieldFilter filter)
{
V anotherObj = null;
try
{
anotherObj = anotherClassObj.newInstance();
Class<?> oneClassObj = oneObj.getClass();
Field[] fields = getMatchedFields(oneClassObj, filter);
for (Field field : fields)
{
String fieldName = field.getName();
String append = Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1);
String getMethodName = "get" + append;
String setMethodName = "set" + append;
Method getMethod = oneClassObj.getDeclaredMethod(getMethodName);
getMethod.setAccessible(true);
Object attrForOneObj = getMethod.invoke(oneObj);
Method setMethod = anotherClassObj.getDeclaredMethod(setMethodName, field.getType());
setMethod.setAccessible(true);
setMethod.invoke(anotherObj, attrForOneObj);
}
}
catch (Exception e)
{
e.printStackTrace();
}
return anotherObj;
}
private Field[] getMatchedFields(Class<?> classObj, FieldFilter filter)
{
List<Field> matchedFields = new ArrayList<Field>();
Field[] fields = classObj.getDeclaredFields();
for (Field field : fields)
{
if (null == filter || filter.accept(field))
{
matchedFields.add(field);
}
}
return matchedFields.toArray(new Field[] {});
}
}
下面的接口设计的引入,是为了满足对类对象转换有特殊需求的场景。可以再accept方法中根据Filed的内容进行设置过滤条件。
package devin.wu.training.reflect.convertor;
import java.lang.reflect.Field;
public interface FieldFilter
{
boolean accept(Field field);
}
3. 上述API的测试代码
package devin.wu.training.reflect.convertor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import junit.framework.TestCase;
public class ObjectConvertorTest extends TestCase
{
private ObjectConvertor convertor;
@Override
protected void setUp() throws Exception
{
convertor = new ObjectConvertor();
}
public void testWithoutField()
{
ObjectWithoutFiled1 obj1 = new ObjectWithoutFiled1();
ObjectWithoutFiled2 obj2 = convertor.toAnotherObj(obj1, ObjectWithoutFiled2.class);
assertNotNull(obj2);
}
public void testWithOneIntField()
{
ObjectWithOneIntFiled1 obj1 = new ObjectWithOneIntFiled1();
obj1.setAttrInt(1);
ObjectWithOneIntFiled2 obj2 = convertor.toAnotherObj(obj1, ObjectWithOneIntFiled2.class);
assertEquals(obj1.getAttrInt(), obj2.getAttrInt());
}
public void testWhenFilterStatic()
{
Object1 obj1 = new Object1();
obj1.setAttrInt(1);
obj1.setAttrDouble(2.0);
obj1.setAttrString("3");
obj1.setAttrArray(new int[]{5, 6});
ObjectConvertor objectConvertor = new ObjectConvertor();
Object2 obj2 = objectConvertor.toAnotherObj(obj1, Object2.class, new FieldFilter()
{
@Override
public boolean accept(Field field)
{
return field.getModifiers() < Modifier.STATIC;
}
});
assertEquals(obj1.getAttrInt(), obj2.getAttrInt());
assertEquals(obj1.getAttrDouble(), obj2.getAttrDouble());
assertEquals(obj1.getAttrString(), obj2.getAttrString());
int[] attrArray = obj2.getAttrArray();
assertNotNull(attrArray);
assertEquals(2, attrArray.length);
assertEquals(5, attrArray[0]);
assertEquals(6, attrArray[1]);
}
}
package devin.wu.training.reflect.convertor;
import java.io.Serializable;
public class Object1 implements Serializable
{
private static final long serialVersionUID = 805500988847131314L;
private int attrInt;
private double attrDouble;
private String attrString;
private int[] attrArray;
private int[] getAttrArray()
{
return attrArray;
}
public void setAttrArray(int[] attrArray)
{
this.attrArray = attrArray;
}
public int getAttrInt()
{
return attrInt;
}
public void setAttrInt(int attrInt)
{
this.attrInt = attrInt;
}
public double getAttrDouble()
{
return attrDouble;
}
public void setAttrDouble(double attrDouble)
{
this.attrDouble = attrDouble;
}
public String getAttrString()
{
return attrString;
}
public void setAttrString(String attrString)
{
this.attrString = attrString;
}
}
package devin.wu.training.reflect.convertor;
public class Object2
{
private int attrInt;
private double attrDouble;
private String attrString;
private int[] attrArray;
public int[] getAttrArray()
{
return attrArray;
}
public void setAttrArray(int[] attrArray)
{
this.attrArray = attrArray;
}
public int getAttrInt()
{
return attrInt;
}
private void setAttrInt(int attrInt)
{
this.attrInt = attrInt;
}
public double getAttrDouble()
{
return attrDouble;
}
public void setAttrDouble(double attrDouble)
{
this.attrDouble = attrDouble;
}
public String getAttrString()
{
return attrString;
}
public void setAttrString(String attrString)
{
this.attrString = attrString;
}
}
package devin.wu.training.reflect.convertor;
public class ObjectWithOneIntFiled1
{
private int attrInt;
public int getAttrInt()
{
return attrInt;
}
public void setAttrInt(int attrInt)
{
this.attrInt = attrInt;
}
}
package devin.wu.training.reflect.convertor;
public class ObjectWithOneIntFiled2
{
private int attrInt;
public int getAttrInt()
{
return attrInt;
}
public void setAttrInt(int attrInt)
{
this.attrInt = attrInt;
}
}
package devin.wu.training.reflect.convertor;
public class ObjectWithoutFiled1
{
}
package devin.wu.training.reflect.convertor;
public class ObjectWithoutFiled2
{
}