From a5038320b4c64c60e5b617198a5e1f5096d800f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=87=91=E6=88=9F?= Date: Tue, 16 Mar 2021 11:50:22 +0800 Subject: [PATCH] convert query path to match pattern --- .../testable/core/tool/OmniAccessor.java | 43 +++++++++++++----- .../testable/core/util/FixSizeMap.java | 45 +++++++++++++++++++ .../alibaba/testable/core/tool/DemoChild.java | 4 +- .../testable/core/tool/DemoParent.java | 4 +- .../testable/core/tool/OmniAccessorTest.java | 30 ++++++++++--- 5 files changed, 104 insertions(+), 22 deletions(-) create mode 100644 testable-core/src/main/java/com/alibaba/testable/core/util/FixSizeMap.java diff --git a/testable-core/src/main/java/com/alibaba/testable/core/tool/OmniAccessor.java b/testable-core/src/main/java/com/alibaba/testable/core/tool/OmniAccessor.java index f40e389..5f49b84 100644 --- a/testable-core/src/main/java/com/alibaba/testable/core/tool/OmniAccessor.java +++ b/testable-core/src/main/java/com/alibaba/testable/core/tool/OmniAccessor.java @@ -1,6 +1,7 @@ package com.alibaba.testable.core.tool; -import com.alibaba.testable.core.util.UnnullableMap; +import com.alibaba.testable.core.util.FixSizeMap; +import com.sun.deploy.util.StringUtils; import java.lang.reflect.Field; import java.util.ArrayList; @@ -14,7 +15,7 @@ import static com.alibaba.testable.core.constant.ConstPool.SLASH; */ public class OmniAccessor { - private static final UnnullableMap, List> MEMBER_INDEXES = UnnullableMap.of(new ArrayList()); + private static final FixSizeMap, List> MEMBER_INDEXES = new FixSizeMap, List>(30); private static final String THIS_REF_PREFIX = "this$"; /** @@ -54,16 +55,19 @@ public class OmniAccessor { * @param target 目标对象 * @param queryPath 搜索路径 * @param value 新的值 + * @return 实际影响的成员个数 */ - public static void set(Object target, String queryPath, Object value) { + public static int set(Object target, String queryPath, Object value) { + int count = 0; for (String memberPath : MEMBER_INDEXES.getOrElse(target.getClass(), generateMemberIndex(target.getClass()))) { if (memberPath.matches(toPattern(queryPath))) { Object parent = getByPath(target, toParent(memberPath)); - if (parent != null) { - setByPath(parent, toChild(memberPath), value); + if (parent != null && setByPath(parent, toChild(memberPath), value)) { + count++; } } } + return count; } private static List generateMemberIndex(Class clazz) { @@ -84,9 +88,10 @@ public class OmniAccessor { } private static List getAllFields(Class clazz) { - List fields = new ArrayList(Arrays.asList(clazz.getDeclaredFields())); - if (clazz.getSuperclass() != null) { - fields.addAll(getAllFields(clazz.getSuperclass())); + Class rawClass = clazz.isArray() ? clazz.getComponentType() : clazz; + List fields = new ArrayList(Arrays.asList(rawClass.getDeclaredFields())); + if (rawClass.getSuperclass() != null) { + fields.addAll(getAllFields(rawClass.getSuperclass())); } return fields; } @@ -96,7 +101,23 @@ public class OmniAccessor { } private static String toPattern(String queryPath) { - return ""; + String[] querySegments = queryPath.split(SLASH); + String[] patternSegments = new String[querySegments.length]; + for (int i = 0; i < querySegments.length; i++) { + patternSegments[i] = toSinglePattern(querySegments[i]); + } + return StringUtils.join(Arrays.asList(patternSegments), SLASH); + } + + private static String toSinglePattern(String querySegment) { + if (querySegment.isEmpty()) { + return ""; + } else if (querySegment.startsWith("{")) { + return "[^{]+" + querySegment.replace("{", "\\{").replace("}", "\\}") + .replace("[", "\\[").replace("]", "\\]"); + } else { + return querySegment + "\\{[^}]+\\}"; + } } private static String toChild(String memberPath) { @@ -111,8 +132,8 @@ public class OmniAccessor { return null; } - private static void setByPath(Object target, String memberPath, Object value) { - + private static boolean setByPath(Object target, String memberPath, Object value) { + return true; } } diff --git a/testable-core/src/main/java/com/alibaba/testable/core/util/FixSizeMap.java b/testable-core/src/main/java/com/alibaba/testable/core/util/FixSizeMap.java new file mode 100644 index 0000000..6574816 --- /dev/null +++ b/testable-core/src/main/java/com/alibaba/testable/core/util/FixSizeMap.java @@ -0,0 +1,45 @@ +package com.alibaba.testable.core.util; + +import com.sun.tools.javac.util.ListBuffer; + +import java.util.HashMap; +import java.util.Map; +import java.util.Queue; + +/** + * @author flin + */ +public class FixSizeMap { + + private final int capacity; + private final Map content; + private final Queue order; + + public FixSizeMap(int size) { + this.capacity = size; + this.content = new HashMap(size); + this.order = new ListBuffer(); + } + + public V get(K key) { + return content.get(key); + } + + public void put(K key, V value) { + if (order.size() >= capacity) { + content.remove(order.poll()); + } + order.add(key); + content.put(key, value); + } + + public V getOrElse(K key, V elseValue) { + V value = get(key); + if (value == null) { + value = elseValue; + put(key, value); + } + return value; + } + +} diff --git a/testable-core/src/test/java/com/alibaba/testable/core/tool/DemoChild.java b/testable-core/src/test/java/com/alibaba/testable/core/tool/DemoChild.java index 2fdaca2..6784377 100644 --- a/testable-core/src/test/java/com/alibaba/testable/core/tool/DemoChild.java +++ b/testable-core/src/test/java/com/alibaba/testable/core/tool/DemoChild.java @@ -2,9 +2,9 @@ package com.alibaba.testable.core.tool; public class DemoChild { - public DemoGrandChild gc1; + public DemoGrandChild gc; - private DemoGrandChild gc2; + private DemoGrandChild[] gcs; public class SubChild { private DemoGrandChild gc; diff --git a/testable-core/src/test/java/com/alibaba/testable/core/tool/DemoParent.java b/testable-core/src/test/java/com/alibaba/testable/core/tool/DemoParent.java index 2e3cec2..873fb48 100644 --- a/testable-core/src/test/java/com/alibaba/testable/core/tool/DemoParent.java +++ b/testable-core/src/test/java/com/alibaba/testable/core/tool/DemoParent.java @@ -2,9 +2,9 @@ package com.alibaba.testable.core.tool; public class DemoParent { - private DemoChild c1; + private DemoChild c; - public DemoChild c2; + public DemoChild[] cs; public DemoChild.SubChild sc; diff --git a/testable-core/src/test/java/com/alibaba/testable/core/tool/OmniAccessorTest.java b/testable-core/src/test/java/com/alibaba/testable/core/tool/OmniAccessorTest.java index f63b4f1..5005802 100644 --- a/testable-core/src/test/java/com/alibaba/testable/core/tool/OmniAccessorTest.java +++ b/testable-core/src/test/java/com/alibaba/testable/core/tool/OmniAccessorTest.java @@ -13,12 +13,12 @@ class OmniAccessorTest { void should_generate_member_index() { List index = PrivateAccessor.invokeStatic(OmniAccessor.class, "generateMemberIndex", DemoParent.class); assertEquals(10, index.size()); - assertEquals("/c1{DemoChild}", index.get(0)); - assertEquals("/c1{DemoChild}/gc1{DemoGrandChild}", index.get(1)); - assertEquals("/c1{DemoChild}/gc2{DemoGrandChild}", index.get(2)); - assertEquals("/c2{DemoChild}", index.get(3)); - assertEquals("/c2{DemoChild}/gc1{DemoGrandChild}", index.get(4)); - assertEquals("/c2{DemoChild}/gc2{DemoGrandChild}", index.get(5)); + assertEquals("/c{DemoChild}", index.get(0)); + assertEquals("/c{DemoChild}/gc{DemoGrandChild}", index.get(1)); + assertEquals("/c{DemoChild}/gcs{DemoGrandChild[]}", index.get(2)); + assertEquals("/cs{DemoChild[]}", index.get(3)); + assertEquals("/cs{DemoChild[]}/gc{DemoGrandChild}", index.get(4)); + assertEquals("/cs{DemoChild[]}/gcs{DemoGrandChild[]}", index.get(5)); assertEquals("/sc{SubChild}", index.get(6)); assertEquals("/sc{SubChild}/gc{DemoGrandChild}", index.get(7)); assertEquals("/ssc{StaticSubChild}", index.get(8)); @@ -26,8 +26,24 @@ class OmniAccessorTest { } @Test - void should_to_pattern() { + void should_match_pattern() { + assertTrue("abc{Abc}".matches("abc\\{[^}]+\\}")); + assertTrue("abc{Abc}".matches("[^{]+\\{Abc\\}")); + assertTrue("abc{Abc[]}/xyz{Xyz[]}".matches("[^{]+\\{Abc\\[\\]\\}/[^{]+\\{Xyz\\[\\]\\}")); + assertTrue("abc{Abc}/xyz{Xyz}/demo{Demo}".matches("abc\\{[^}]+\\}/[^{]+\\{Xyz\\}/demo\\{[^}]+\\}")); + } + @Test + void should_to_pattern() { + assertEquals("", PrivateAccessor.invokeStatic(OmniAccessor.class, "toPattern", "")); + assertEquals("abc\\{[^}]+\\}", PrivateAccessor.invokeStatic(OmniAccessor.class, "toPattern", "abc")); + assertEquals("[^{]+\\{Abc\\}", PrivateAccessor.invokeStatic(OmniAccessor.class, "toPattern", "{Abc}")); + assertEquals("abc\\{[^}]+\\}/xyz\\{[^}]+\\}", PrivateAccessor.invokeStatic(OmniAccessor.class, "toPattern", "abc/xyz")); + assertEquals("[^{]+\\{Abc\\}/xyz\\{[^}]+\\}", PrivateAccessor.invokeStatic(OmniAccessor.class, "toPattern", "{Abc}/xyz")); + assertEquals("abc\\{[^}]+\\}/[^{]+\\{Xyz\\}", PrivateAccessor.invokeStatic(OmniAccessor.class, "toPattern", "abc/{Xyz}")); + assertEquals("[^{]+\\{Abc\\}/[^{]+\\{Xyz\\}", PrivateAccessor.invokeStatic(OmniAccessor.class, "toPattern", "{Abc}/{Xyz}")); + assertEquals("[^{]+\\{Abc\\[\\]\\}/[^{]+\\{Xyz\\[\\]\\}", PrivateAccessor.invokeStatic(OmniAccessor.class, "toPattern", "{Abc[]}/{Xyz[]}")); + assertEquals("abc\\{[^}]+\\}/[^{]+\\{Xyz\\}/demo\\{[^}]+\\}", PrivateAccessor.invokeStatic(OmniAccessor.class, "toPattern", "abc/{Xyz}/demo")); } @Test