Skip to content

Commit 063ef24

Browse files
committed
Support static fields in ReflectionTestUtils
Prior to this commit it was possible to set or get a static field using ReflectionTestUtils but only if an instance of the target class was available. This commit introduces dedicated support for setting and getting static fields in ReflectionTestUtils when only the target class is available. Furthermore, this commit increases the robustness of ReflectionTestUtilsTests regarding expected exceptions and simplifies the Javadoc for ReflectionTestUtils. Issue: SPR-6792
1 parent 444aa4e commit 063ef24

File tree

3 files changed

+334
-52
lines changed

3 files changed

+334
-52
lines changed

spring-test/src/main/java/org/springframework/test/util/ReflectionTestUtils.java

Lines changed: 161 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -51,6 +51,10 @@
5151
* methods.</li>
5252
* </ul>
5353
*
54+
* <p>In addition, several methods in this class provide support for {@code static}
55+
* fields &mdash; for example, {@link #setField(Class, String, Object)},
56+
* {@link #getField(Class, String)}, etc.
57+
*
5458
* @author Sam Brannen
5559
* @author Juergen Hoeller
5660
* @since 2.5
@@ -66,87 +70,204 @@ public class ReflectionTestUtils {
6670

6771

6872
/**
69-
* Set the {@link Field field} with the given {@code name} on the provided
70-
* {@link Object target object} to the supplied {@code value}.
73+
* Set the {@linkplain Field field} with the given {@code name} on the
74+
* provided {@code targetObject} to the supplied {@code value}.
7175
*
72-
* <p>This method traverses the class hierarchy in search of the desired field.
73-
* In addition, an attempt will be made to make non-{@code public} fields
74-
* <em>accessible</em>, thus allowing one to set {@code protected},
75-
* {@code private}, and <em>package-private</em> fields.
76+
* <p>This method delegates to {@link #setField(Object, String, Object, Class)},
77+
* supplying {@code null} for the {@code type} argument.
7678
*
77-
* @param target the target object on which to set the field
78-
* @param name the name of the field to set
79+
* @param targetObject the target object on which to set the field; never {@code null}
80+
* @param name the name of the field to set; never {@code null}
7981
* @param value the value to set
80-
* @see ReflectionUtils#findField(Class, String, Class)
81-
* @see ReflectionUtils#makeAccessible(Field)
82-
* @see ReflectionUtils#setField(Field, Object, Object)
8382
*/
84-
public static void setField(Object target, String name, Object value) {
85-
setField(target, name, value, null);
83+
public static void setField(Object targetObject, String name, Object value) {
84+
setField(targetObject, name, value, null);
85+
}
86+
87+
/**
88+
* Set the {@linkplain Field field} with the given {@code name}/{@code type}
89+
* on the provided {@code targetObject} to the supplied {@code value}.
90+
*
91+
* <p>This method delegates to {@link #setField(Object, Class, String, Object, Class)},
92+
* supplying {@code null} for the {@code targetClass} argument.
93+
*
94+
* @param targetObject the target object on which to set the field; never {@code null}
95+
* @param name the name of the field to set; may be {@code null} if
96+
* {@code type} is specified
97+
* @param value the value to set
98+
* @param type the type of the field to set; may be {@code null} if
99+
* {@code name} is specified
100+
*/
101+
public static void setField(Object targetObject, String name, Object value, Class<?> type) {
102+
setField(targetObject, null, name, value, type);
103+
}
104+
105+
/**
106+
* Set the static {@linkplain Field field} with the given {@code name} on
107+
* the provided {@code targetClass} to the supplied {@code value}.
108+
*
109+
* <p>This method delegates to {@link #setField(Object, Class, String, Object, Class)},
110+
* supplying {@code null} for the {@code targetObject} and {@code type} arguments.
111+
*
112+
* @param targetClass the target class on which to set the static field;
113+
* never {@code null}
114+
* @param name the name of the field to set; never {@code null}
115+
* @param value the value to set
116+
* @since 4.2
117+
*/
118+
public static void setField(Class<?> targetClass, String name, Object value) {
119+
setField(null, targetClass, name, value, null);
120+
}
121+
122+
/**
123+
* Set the static {@linkplain Field field} with the given
124+
* {@code name}/{@code type} on the provided {@code targetClass} to
125+
* the supplied {@code value}.
126+
*
127+
* <p>This method delegates to {@link #setField(Object, Class, String, Object, Class)},
128+
* supplying {@code null} for the {@code targetObject} argument.
129+
*
130+
* @param targetClass the target class on which to set the static field;
131+
* never {@code null}
132+
* @param name the name of the field to set; may be {@code null} if
133+
* {@code type} is specified
134+
* @param value the value to set
135+
* @param type the type of the field to set; may be {@code null} if
136+
* {@code name} is specified
137+
* @since 4.2
138+
*/
139+
public static void setField(Class<?> targetClass, String name, Object value, Class<?> type) {
140+
setField(null, targetClass, name, value, type);
86141
}
87142

88143
/**
89-
* Set the {@link Field field} with the given {@code name} on the provided
90-
* {@link Object target object} to the supplied {@code value}.
144+
* Set the {@linkplain Field field} with the given {@code name}/{@code type}
145+
* on the provided {@code targetObject}/{@code targetClass} to the supplied
146+
* {@code value}.
91147
*
92148
* <p>This method traverses the class hierarchy in search of the desired
93149
* field. In addition, an attempt will be made to make non-{@code public}
94150
* fields <em>accessible</em>, thus allowing one to set {@code protected},
95151
* {@code private}, and <em>package-private</em> fields.
96152
*
97-
* @param target the target object on which to set the field
98-
* @param name the name of the field to set
153+
* @param targetObject the target object on which to set the field; may be
154+
* {@code null} if the field is static
155+
* @param targetClass the target class on which to set the field; may
156+
* be {@code null} if the field is an instance field
157+
* @param name the name of the field to set; may be {@code null} if
158+
* {@code type} is specified
99159
* @param value the value to set
100-
* @param type the type of the field (may be {@code null})
160+
* @param type the type of the field to set; may be {@code null} if
161+
* {@code name} is specified
101162
* @see ReflectionUtils#findField(Class, String, Class)
102163
* @see ReflectionUtils#makeAccessible(Field)
103164
* @see ReflectionUtils#setField(Field, Object, Object)
165+
* @since 4.2
104166
*/
105-
public static void setField(Object target, String name, Object value, Class<?> type) {
106-
Assert.notNull(target, "Target object must not be null");
107-
Field field = ReflectionUtils.findField(target.getClass(), name, type);
167+
public static void setField(Object targetObject, Class<?> targetClass, String name, Object value, Class<?> type) {
168+
Assert.isTrue(targetObject != null || targetClass != null,
169+
"Either targetObject or targetClass for the field must be specified");
170+
171+
if (targetClass == null) {
172+
targetClass = targetObject.getClass();
173+
}
174+
Field field = ReflectionUtils.findField(targetClass, name, type);
108175

109-
// SPR-9571: inline Assert.notNull() in order to avoid accidentally invoking
110-
// toString() on a non-null target.
176+
// Inline Assert.notNull() to avoid invoking toString() on a non-null target.
111177
if (field == null) {
112-
throw new IllegalArgumentException(String.format("Could not find field [%s] of type [%s] on target [%s]",
113-
name, type, target));
178+
throw new IllegalArgumentException(String.format(
179+
"Could not find field [%s] of type [%s] on target object [%s] or target class [%s]", name, type,
180+
targetObject, targetClass));
114181
}
115182

116183
if (logger.isDebugEnabled()) {
117-
logger.debug(String.format("Setting field [%s] of type [%s] on target [%s] to value [%s]", name, type,
118-
target,
119-
value));
184+
logger.debug(String.format(
185+
"Setting field [%s] of type [%s] on target object [%s] or target class [%s] to value [%s]", name, type,
186+
targetObject, targetClass, value));
120187
}
121188
ReflectionUtils.makeAccessible(field);
122-
ReflectionUtils.setField(field, target, value);
189+
ReflectionUtils.setField(field, targetObject, value);
123190
}
124191

125192
/**
126-
* Get the field with the given {@code name} from the provided target object.
193+
* Get the value of the {@linkplain Field field} with the given {@code name}
194+
* from the provided {@code targetObject}.
195+
*
196+
* <p>This method delegates to {@link #getField(Object, Class, String)},
197+
* supplying {@code null} for the {@code targetClass} argument.
198+
*
199+
* @param targetObject the target object from which to get the field;
200+
* never {@code null}
201+
* @param name the name of the field to get; never {@code null}
202+
* @return the field's current value
203+
* @see #getField(Class, String)
204+
*/
205+
public static Object getField(Object targetObject, String name) {
206+
return getField(targetObject, null, name);
207+
}
208+
209+
/**
210+
* Get the value of the static {@linkplain Field field} with the given
211+
* {@code name} from the provided {@code targetClass}.
212+
*
213+
* <p>This method delegates to {@link #getField(Object, Class, String)},
214+
* supplying {@code null} for the {@code targetObject} argument.
215+
*
216+
* @param targetClass the target class from which to get the static field;
217+
* never {@code null}
218+
* @param name the name of the field to get; never {@code null}
219+
* @return the field's current value
220+
* @see #getField(Object, String)
221+
* @since 4.2
222+
*/
223+
public static Object getField(Class<?> targetClass, String name) {
224+
return getField(null, targetClass, name);
225+
}
226+
227+
/**
228+
* Get the value of the {@linkplain Field field} with the given {@code name}
229+
* from the provided {@code targetObject}/{@code targetClass}.
127230
*
128231
* <p>This method traverses the class hierarchy in search of the desired
129232
* field. In addition, an attempt will be made to make non-{@code public}
130233
* fields <em>accessible</em>, thus allowing one to get {@code protected},
131234
* {@code private}, and <em>package-private</em> fields.
132235
*
133-
* @param target the target object on which to set the field
134-
* @param name the name of the field to get
236+
* @param targetObject the target object from which to get the field; may be
237+
* {@code null} if the field is static
238+
* @param targetClass the target class from which to get the field; may
239+
* be {@code null} if the field is an instance field
240+
* @param name the name of the field to get; never {@code null}
135241
* @return the field's current value
242+
* @see #getField(Object, String)
243+
* @see #getField(Class, String)
136244
* @see ReflectionUtils#findField(Class, String, Class)
137245
* @see ReflectionUtils#makeAccessible(Field)
138-
* @see ReflectionUtils#setField(Field, Object, Object)
246+
* @see ReflectionUtils#getField(Field, Object, Object)
247+
* @since 4.2
139248
*/
140-
public static Object getField(Object target, String name) {
141-
Assert.notNull(target, "Target object must not be null");
142-
Field field = ReflectionUtils.findField(target.getClass(), name);
143-
Assert.notNull(field, "Could not find field [" + name + "] on target [" + target + "]");
249+
public static Object getField(Object targetObject, Class<?> targetClass, String name) {
250+
Assert.isTrue(targetObject != null || targetClass != null,
251+
"Either targetObject or targetClass for the field must be specified");
252+
253+
if (targetClass == null) {
254+
targetClass = targetObject.getClass();
255+
}
256+
Field field = ReflectionUtils.findField(targetClass, name);
257+
258+
// Inline Assert.notNull() to avoid invoking toString() on a non-null target.
259+
if (field == null) {
260+
throw new IllegalArgumentException(
261+
String.format("Could not find field [%s] on target object [%s] or target class [%s]", name,
262+
targetObject, targetClass));
263+
}
144264

145265
if (logger.isDebugEnabled()) {
146-
logger.debug("Getting field [" + name + "] from target [" + target + "]");
266+
logger.debug(String.format("Getting field [%s] from target object [%s] or target class [%s]", name,
267+
targetObject, targetClass));
147268
}
148269
ReflectionUtils.makeAccessible(field);
149-
return ReflectionUtils.getField(field, target);
270+
return ReflectionUtils.getField(field, targetObject);
150271
}
151272

152273
/**

0 commit comments

Comments
 (0)