Java通过反射设置或者获取字段的值

最近在做项目时使用到了直接使用了 MyBatis 的源码,在获取 BoundSql 这个对象的时候,它这个类中的所有字段全部是私有的。但是我又要动态的设置这个类中的 sql 字段的值。BoundSql的代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class BoundSql {
private String sql; //我需要修改这个字段
private List<ParameterMapping> parameterMappings;
private Object parameterObject;
private Map<String, Object> additionalParameters;
private MetaObject metaParameters;

public BoundSql(Configuration configuration, String sql, List<ParameterMapping> parameterMappings, Object parameterObject) {
this.sql = sql;
this.parameterMappings = parameterMappings;
this.parameterObject = parameterObject;
this.additionalParameters = new HashMap();
this.metaParameters = configuration.newMetaObject(this.additionalParameters);
}

public String getSql() {
return this.sql;
}

public List<ParameterMapping> getParameterMappings() {
return this.parameterMappings;
}

public Object getParameterObject() {
return this.parameterObject;
}

public boolean hasAdditionalParameter(String name) {
String paramName = (new PropertyTokenizer(name)).getName();
return this.additionalParameters.containsKey(paramName);
}

public void setAdditionalParameter(String name, Object value) {
this.metaParameters.setValue(name, value);
}

public Object getAdditionalParameter(String name) {
return this.metaParameters.getValue(name);
}
}

其实解决这个问题最简单的方法就是,我新建一个类也叫 BoundSql ,然后把其中的 sql 字段设置为public的。或者反编译 mybatis 的源码,修改为public的然后打成jar包。
这两种方式都比较麻烦,于是想起来了使用反射来完成这个操作。反射可以动态的设置一个类中的字段,就算这个字段是 private 的。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public static void setFieldValue(Object target, String fname, Class<?> ftype, Object fvalue)
{
if (target == null || fname == null || "".equals(fname)
|| (fvalue != null && !ftype.isAssignableFrom(fvalue.getClass())))
{
return;
}
Class<?> clazz = target.getClass();
try
{
//先看这个类有没有set方法,有的话直接调用就ok
Method method = clazz.getMethod("set" + Character.toUpperCase(fname.charAt(0)) + fname.substring(1), ftype);
if (!Modifier.isPublic(method.getModifiers()))
{
method.setAccessible(true);
}
method.invoke(target, fvalue);
}
catch (Exception me)
{
try
{
// 没有set方法,使用Filed的set方法来完成
Field field = getFieldOfClass(clazz, fname);
if (!Modifier.isPublic(field.getModifiers()))
{
field.setAccessible(true);
}
field.set(target, fvalue);
}
catch (Exception fe)
{
if (logger.isDebugEnabled())
{
logger.debug(fe, fe);
}
}
}
}