Skip to content

Commit 862bd49

Browse files
authored
Box primitive casts in Whitebox getInternalState/invokeMethod reflection (#1024)
Field.get and Method.invoke return Object, so a primitive-typed result declaration emitted a `(int) object` cast, which does not compile. Cast to the wrapper type instead; the surrounding assignment auto-unboxes.
1 parent 9e86af9 commit 862bd49

5 files changed

Lines changed: 104 additions & 2 deletions

File tree

src/main/java/org/openrewrite/java/testing/mockito/PowerMockWhiteboxGetInternalStateToJavaReflection.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ private static class GetInternalStateVisitor extends WhiteboxToReflectionVisitor
6767
String prefix = fieldLookupPrefix(varName);
6868
if (sink.varName != null) {
6969
if (isNonObjectCast(sink.castType)) {
70-
return prefix + sink.castType + " " + sink.varName + " = (" + sink.castType + ") " + varName + ".get(#{any(java.lang.Object)});";
70+
return prefix + sink.castType + " " + sink.varName + " = (" + boxedCastType(sink.castType) + ") " + varName + ".get(#{any(java.lang.Object)});";
7171
}
7272
return prefix + "Object " + sink.varName + " = " + varName + ".get(#{any(java.lang.Object)});";
7373
}

src/main/java/org/openrewrite/java/testing/mockito/PowerMockWhiteboxInvokeMethodToJavaReflection.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ private static class InvokeMethodVisitor extends WhiteboxToReflectionVisitor {
9090
// invoke line
9191
if (sink.varName != null) {
9292
if (isNonObjectCast(sink.castType)) {
93-
sb.append(sink.castType).append(" ").append(sink.varName).append(" = (").append(sink.castType).append(") ");
93+
sb.append(sink.castType).append(" ").append(sink.varName).append(" = (").append(boxedCastType(sink.castType)).append(") ");
9494
} else {
9595
sb.append("Object ").append(sink.varName).append(" = ");
9696
}

src/main/java/org/openrewrite/java/testing/mockito/WhiteboxToReflectionVisitor.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@
3131

3232
import java.util.ArrayList;
3333
import java.util.Arrays;
34+
import java.util.HashMap;
3435
import java.util.List;
36+
import java.util.Map;
3537

3638
import static java.util.Collections.emptyList;
3739
import static org.openrewrite.Tree.randomId;
@@ -50,6 +52,19 @@ abstract class WhiteboxToReflectionVisitor extends JavaIsoVisitor<ExecutionConte
5052

5153
private static final String WHITEBOX_REPLACED = "whiteboxReplaced";
5254

55+
private static final Map<String, String> BOXED_TYPES = new HashMap<>();
56+
57+
static {
58+
BOXED_TYPES.put("int", "Integer");
59+
BOXED_TYPES.put("long", "Long");
60+
BOXED_TYPES.put("double", "Double");
61+
BOXED_TYPES.put("float", "Float");
62+
BOXED_TYPES.put("boolean", "Boolean");
63+
BOXED_TYPES.put("byte", "Byte");
64+
BOXED_TYPES.put("short", "Short");
65+
BOXED_TYPES.put("char", "Character");
66+
}
67+
5368
private final String reflectiveImport;
5469
private final List<MethodMatcher> matchers;
5570

@@ -264,6 +279,15 @@ boolean isNonObjectCast(@Nullable String castType) {
264279
return null;
265280
}
266281

282+
/**
283+
* {@code Field.get}/{@code Method.invoke} return {@code Object} (boxing primitives), so a primitive
284+
* declared type must be cast to its wrapper (a direct {@code (int) object} cast does not compile);
285+
* the surrounding assignment then auto-unboxes.
286+
*/
287+
String boxedCastType(String castType) {
288+
return BOXED_TYPES.getOrDefault(castType, castType);
289+
}
290+
267291
private J.MethodDeclaration addThrowsExceptionIfAbsent(J.MethodDeclaration md) {
268292
if (md.getThrows() != null && md.getThrows().stream()
269293
.anyMatch(j -> TypeUtils.isOfClassType(j.getType(), "java.lang.Exception") ||

src/test/java/org/openrewrite/java/testing/mockito/PowerMockWhiteboxGetInternalStateToJavaReflectionTest.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,4 +75,42 @@ void testGetField() throws Exception {
7575
)
7676
);
7777
}
78+
79+
@Test
80+
void primitiveResultUsesBoxedCast() {
81+
//language=java
82+
rewriteRun(
83+
java(
84+
"""
85+
class MyService {
86+
private int count = 3;
87+
}
88+
"""
89+
),
90+
java(
91+
"""
92+
import org.powermock.reflect.Whitebox;
93+
94+
class MyServiceTest {
95+
void test() {
96+
MyService service = new MyService();
97+
int count = Whitebox.getInternalState(service, "count");
98+
}
99+
}
100+
""",
101+
"""
102+
import java.lang.reflect.Field;
103+
104+
class MyServiceTest {
105+
void test() throws Exception {
106+
MyService service = new MyService();
107+
Field countField = service.getClass().getDeclaredField("count");
108+
countField.setAccessible(true);
109+
int count = (Integer) countField.get(service);
110+
}
111+
}
112+
"""
113+
)
114+
);
115+
}
78116
}

src/test/java/org/openrewrite/java/testing/mockito/PowerMockWhiteboxInvokeMethodToJavaReflectionTest.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,4 +280,44 @@ void testInvokeWithInterfaceArg() throws Exception {
280280
)
281281
);
282282
}
283+
284+
@Test
285+
void primitiveResultUsesBoxedCast() {
286+
//language=java
287+
rewriteRun(
288+
java(
289+
"""
290+
class MyService {
291+
private int compute() {
292+
return 42;
293+
}
294+
}
295+
"""
296+
),
297+
java(
298+
"""
299+
import org.powermock.reflect.Whitebox;
300+
301+
class MyServiceTest {
302+
void test() {
303+
MyService service = new MyService();
304+
int r = Whitebox.invokeMethod(service, "compute");
305+
}
306+
}
307+
""",
308+
"""
309+
import java.lang.reflect.Method;
310+
311+
class MyServiceTest {
312+
void test() throws Exception {
313+
MyService service = new MyService();
314+
Method computeMethod = service.getClass().getDeclaredMethod("compute");
315+
computeMethod.setAccessible(true);
316+
int r = (Integer) computeMethod.invoke(service);
317+
}
318+
}
319+
"""
320+
)
321+
);
322+
}
283323
}

0 commit comments

Comments
 (0)