This is an automated email from the ASF dual-hosted git repository.

jermy pushed a commit to branch Whitebox-setInternalFinalState
in repository 
https://gitbox.apache.org/repos/asf/incubator-hugegraph-commons.git

commit 6b0d97eb4ee3c291beff944c3996f61172e009c7
Author: Zhangmei Li <[email protected]>
AuthorDate: Sun Apr 24 22:59:40 2022 +0800

    add Whitebox.setInternalFinalState()
    
    Change-Id: I2e2fd25d95dc3033ac1fa332fe6ed56b3c259758
---
 .../com/baidu/hugegraph/testutil/Whitebox.java     | 48 +++++++++++++++++--
 .../com/baidu/hugegraph/testutil/WhiteboxTest.java | 55 ++++++++++++++++++++++
 2 files changed, 100 insertions(+), 3 deletions(-)

diff --git 
a/hugegraph-common/src/main/java/com/baidu/hugegraph/testutil/Whitebox.java 
b/hugegraph-common/src/main/java/com/baidu/hugegraph/testutil/Whitebox.java
index 0d7c7c4..b947314 100644
--- a/hugegraph-common/src/main/java/com/baidu/hugegraph/testutil/Whitebox.java
+++ b/hugegraph-common/src/main/java/com/baidu/hugegraph/testutil/Whitebox.java
@@ -22,6 +22,7 @@ package com.baidu.hugegraph.testutil;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
 import java.util.Arrays;
 import java.util.Objects;
 
@@ -32,13 +33,18 @@ public class Whitebox {
 
     public static final char SEPARATOR = '.';
 
-    public static void setInternalState(Object target, String fieldName,
-                                        Object value) {
+    public static void setInternalState(Object target,
+                                        String fieldName, Object value) {
         assert target != null;
         assert fieldName != null;
         int sep = fieldName.lastIndexOf(SEPARATOR);
         if (sep > 0) {
-            target = getInternalState(target, fieldName.substring(0, sep));
+            String prefix = fieldName.substring(0, sep);
+            Object result = getInternalState(target, prefix);
+            E.checkArgument(result != null,
+                            "Can't set value on null field: `%s.%s`",
+                            target, prefix);
+            target = result;
             fieldName = fieldName.substring(sep + 1);
         }
 
@@ -80,6 +86,42 @@ public class Whitebox {
         }
     }
 
+    public static void setInternalFinalState(Object target,
+                                             String fieldName, Object value) {
+        Class<?> c = target instanceof Class<?> ?
+                     (Class<?>) target : target.getClass();
+        try {
+            Field field = c.getDeclaredField(fieldName);
+
+            // Remove final like FieldUtils.removeFinalModifier()
+            Field modifiersField = Field.class.getDeclaredField("modifiers");
+            modifiersField.setAccessible(true);
+            int oldModifiers = field.getModifiers();
+            int nonFinal = oldModifiers & ~Modifier.FINAL;
+            modifiersField.setInt(field, nonFinal);
+
+            // Reset overrideFieldAccessor
+            Field overrideFAField = 
Field.class.getDeclaredField("overrideFieldAccessor");
+            overrideFAField.setAccessible(true);
+            if (overrideFAField.get(field) != null) {
+                setInternalState(field, "overrideFieldAccessor", null);
+            }
+
+            try {
+                field.setAccessible(true);
+                field.set(target, value);
+            } finally {
+                // Resume old modifiers (final)
+                modifiersField.setInt(field, oldModifiers);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new RuntimeException(String.format(
+                      "Can't set value of '%s' against object '%s'",
+                      fieldName, target), e);
+        }
+    }
+
     private static Field getFieldFromHierarchy(Class<?> clazz, String field) {
         Field f = getField(clazz, field);
         while (f == null && clazz != Object.class) {
diff --git 
a/hugegraph-common/src/test/java/com/baidu/hugegraph/testutil/WhiteboxTest.java 
b/hugegraph-common/src/test/java/com/baidu/hugegraph/testutil/WhiteboxTest.java
index 92ab1af..855c6ad 100644
--- 
a/hugegraph-common/src/test/java/com/baidu/hugegraph/testutil/WhiteboxTest.java
+++ 
b/hugegraph-common/src/test/java/com/baidu/hugegraph/testutil/WhiteboxTest.java
@@ -75,6 +75,7 @@ public class WhiteboxTest {
 
         Whitebox.setInternalState(test1, "ivalue", 11);
         Assert.assertEquals(11, Whitebox.getInternalState(test1, "ivalue"));
+        Assert.assertEquals(11, test1.ivalue);
 
         Whitebox.setInternalState(test1, "test2.fvalue", 22f);
         Assert.assertEquals(22f, Whitebox.getInternalState(test1,
@@ -97,6 +98,52 @@ public class WhiteboxTest {
         });
     }
 
+    @Test
+    public void testSetInternalFinalState() {
+        Test1 test1 = newTest();
+        Assert.assertEquals(1, test1.ivalueFinal);
+
+        Whitebox.setInternalState(test1, "ivalueFinal", 2);
+        Assert.assertEquals(2, Whitebox.getInternalState(test1, 
"ivalueFinal"));
+        // FIXME: seems don't take effect!!!
+        Assert.assertEquals(1, test1.ivalueFinal);
+
+        Whitebox.setInternalFinalState(test1, "ivalueFinal", 3);
+        Assert.assertEquals(3, Whitebox.getInternalState(test1, 
"ivalueFinal"));
+        // FIXME: seems don't take effect!!!
+        Assert.assertEquals(1, test1.ivalueFinal);
+    }
+
+    @Test
+    public void testSetInternalStaticFinalState() {
+//        Assert.assertThrows(RuntimeException.class, () -> {
+//            Whitebox.setInternalState(Test4.class, "staticFinalValue", 11);
+//        }, e -> {
+//            Assert.assertContains("Can't set value of 'staticFinalValue'",
+//                                  e.getMessage());
+//        });
+
+        Assert.assertEquals(1, Test4.staticFinalValue);
+        // Can only call at the first reflect time
+        Whitebox.setInternalFinalState(Test4.class, "staticFinalValue", 11);
+        Assert.assertEquals(11, Whitebox.getInternalState(Test4.class,
+                                                          "staticFinalValue"));
+
+        Whitebox.setInternalFinalState(Test4.class, "staticFinalValue", 12);
+        Assert.assertEquals(12, Whitebox.getInternalState(Test4.class,
+                                                          "staticFinalValue"));
+
+        // FIXME: seems don't take effect!!!
+        Assert.assertEquals(1, Test4.staticFinalValue);
+
+        Assert.assertThrows(RuntimeException.class, () -> {
+            Whitebox.setInternalState(Test4.class, "staticFinalValue", 1);
+        }, e -> {
+            Assert.assertContains("Can't set value of 'staticFinalValue'",
+                                  e.getMessage());
+        });
+    }
+
     @Test
     public void testInvokeStatic() {
         Assert.assertEquals(1, Whitebox.invokeStatic(Test1.class, "svalue"));
@@ -159,7 +206,10 @@ public class WhiteboxTest {
     private static class Test1 {
 
         private static int staticValue = 1;
+
         private int ivalue = 1;
+        private final int ivalueFinal = 1;
+
         private Test2 test2;
         private TestSubClass test4;
 
@@ -218,6 +268,11 @@ public class WhiteboxTest {
         }
     }
 
+    private static class Test4 {
+
+        private static final int staticFinalValue = 1;
+    }
+
     @SuppressWarnings("unused")
     private static class TestSubClass extends Test1 {
 

Reply via email to