mirror of
https://github.com/alibaba/testable-mock.git
synced 2025-01-25 11:51:15 +08:00
complete get and set by path of common class
This commit is contained in:
parent
a5038320b4
commit
328296ae3a
@ -1,6 +1,7 @@
|
||||
package com.alibaba.testable.core.tool;
|
||||
|
||||
import com.alibaba.testable.core.util.FixSizeMap;
|
||||
import com.alibaba.testable.core.util.TypeUtil;
|
||||
import com.sun.deploy.util.StringUtils;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
@ -17,6 +18,13 @@ public class OmniAccessor {
|
||||
|
||||
private static final FixSizeMap<Class<?>, List<String>> MEMBER_INDEXES = new FixSizeMap<Class<?>, List<String>>(30);
|
||||
private static final String THIS_REF_PREFIX = "this$";
|
||||
private static final String REGEX_ANY_CLASS = "\\{[^}]+\\}";
|
||||
private static final String REGEX_ANY_NAME = "[^{]+";
|
||||
private static final String BRACE_START = "{";
|
||||
private static final String ESCAPE = "\\";
|
||||
private static final String BRACE_END = "}";
|
||||
private static final String BRACKET_START = "[";
|
||||
private static final String BRACKET_END = "]";
|
||||
|
||||
/**
|
||||
* 获取第一个符合搜索路径的成员
|
||||
@ -41,9 +49,15 @@ public class OmniAccessor {
|
||||
List<T> values = new ArrayList<T>();
|
||||
for (String memberPath : MEMBER_INDEXES.getOrElse(target.getClass(), generateMemberIndex(target.getClass()))) {
|
||||
if (memberPath.matches(toPattern(queryPath))) {
|
||||
T val = (T)getByPath(target, memberPath);
|
||||
if (val != null) {
|
||||
values.add(val);
|
||||
try {
|
||||
T val = (T)getByPath(target, memberPath, queryPath);
|
||||
if (val != null) {
|
||||
values.add(val);
|
||||
}
|
||||
} catch (NoSuchFieldException e) {
|
||||
// continue
|
||||
} catch (IllegalAccessException e) {
|
||||
// continue
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -61,9 +75,16 @@ public class OmniAccessor {
|
||||
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)) {
|
||||
count++;
|
||||
try {
|
||||
Object parent = getByPath(target, toParent(memberPath), toParent(queryPath));
|
||||
if (parent != null) {
|
||||
setByPathSegment(parent, toChild(memberPath), toChild(queryPath), value);
|
||||
count++;
|
||||
}
|
||||
} catch (NoSuchFieldException e) {
|
||||
// continue
|
||||
} catch (IllegalAccessException e) {
|
||||
// continue
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -97,7 +118,7 @@ public class OmniAccessor {
|
||||
}
|
||||
|
||||
private static String toPath(Field field) {
|
||||
return field.getName() + "{" + field.getType().getSimpleName() + "}";
|
||||
return field.getName() + BRACE_START + field.getType().getSimpleName() + BRACE_END;
|
||||
}
|
||||
|
||||
private static String toPattern(String queryPath) {
|
||||
@ -110,13 +131,18 @@ public class OmniAccessor {
|
||||
}
|
||||
|
||||
private static String toSinglePattern(String querySegment) {
|
||||
if (querySegment.endsWith(BRACKET_END)) {
|
||||
querySegment = querySegment.substring(0, querySegment.lastIndexOf(BRACKET_START));
|
||||
}
|
||||
if (querySegment.isEmpty()) {
|
||||
return "";
|
||||
} else if (querySegment.startsWith("{")) {
|
||||
return "[^{]+" + querySegment.replace("{", "\\{").replace("}", "\\}")
|
||||
.replace("[", "\\[").replace("]", "\\]");
|
||||
} else if (querySegment.startsWith(BRACE_START)) {
|
||||
return REGEX_ANY_NAME + querySegment.replace(BRACE_START, ESCAPE + BRACE_START)
|
||||
.replace(BRACE_END, ESCAPE + BRACE_END)
|
||||
.replace(BRACKET_START, ESCAPE + BRACKET_START)
|
||||
.replace(BRACKET_END, ESCAPE + BRACKET_END);
|
||||
} else {
|
||||
return querySegment + "\\{[^}]+\\}";
|
||||
return querySegment + REGEX_ANY_CLASS;
|
||||
}
|
||||
}
|
||||
|
||||
@ -128,12 +154,38 @@ public class OmniAccessor {
|
||||
return memberPath.contains(SLASH) ? memberPath.substring(0, memberPath.lastIndexOf(SLASH)) : "";
|
||||
}
|
||||
|
||||
private static Object getByPath(Object target, String memberPath) {
|
||||
return null;
|
||||
private static int extraIndexFromQuery(String query) {
|
||||
return query.endsWith(BRACKET_END)
|
||||
? Integer.parseInt(query.substring(query.lastIndexOf(BRACKET_START) + 1), query.length() - 1)
|
||||
: -1;
|
||||
}
|
||||
|
||||
private static boolean setByPath(Object target, String memberPath, Object value) {
|
||||
return true;
|
||||
private static Object getByPath(Object target, String memberPath, String queryPath)
|
||||
throws NoSuchFieldException, IllegalAccessException {
|
||||
String[] memberSegments = memberPath.split(SLASH);
|
||||
String[] querySegments = queryPath.split(SLASH);
|
||||
Object obj = target;
|
||||
String name;
|
||||
int nth;
|
||||
Field field;
|
||||
assert memberSegments.length == querySegments.length;
|
||||
for (int i = 0; i < memberSegments.length; i++) {
|
||||
name = memberSegments[i].substring(0, memberSegments[i].indexOf(BRACE_START));
|
||||
nth = extraIndexFromQuery(querySegments[i]);
|
||||
field = TypeUtil.getFieldByName(obj.getClass(), name);
|
||||
field.setAccessible(true);
|
||||
obj = field.get(obj);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
private static void setByPathSegment(Object target, String memberSegment, String querySegment, Object value)
|
||||
throws IllegalAccessException {
|
||||
String name = memberSegment.substring(0, memberSegment.indexOf(BRACE_START));
|
||||
int nth = extraIndexFromQuery(querySegment);
|
||||
Field field = TypeUtil.getFieldByName(target.getClass(), name);
|
||||
field.setAccessible(true);
|
||||
field.set(target, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,4 +1,10 @@
|
||||
package com.alibaba.testable.core.tool;
|
||||
|
||||
public class DemoGrandChild {
|
||||
|
||||
private int i;
|
||||
|
||||
public DemoGrandChild(int i) {
|
||||
this.i = i;
|
||||
}
|
||||
}
|
||||
|
@ -2,9 +2,9 @@ package com.alibaba.testable.core.tool;
|
||||
|
||||
public class DemoParent {
|
||||
|
||||
private DemoChild c;
|
||||
public DemoChild c;
|
||||
|
||||
public DemoChild[] cs;
|
||||
private DemoChild[] cs;
|
||||
|
||||
public DemoChild.SubChild sc;
|
||||
|
||||
|
@ -12,17 +12,23 @@ class OmniAccessorTest {
|
||||
@Test
|
||||
void should_generate_member_index() {
|
||||
List<String> index = PrivateAccessor.invokeStatic(OmniAccessor.class, "generateMemberIndex", DemoParent.class);
|
||||
assertEquals(10, index.size());
|
||||
assertEquals(16, index.size());
|
||||
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));
|
||||
assertEquals("/ssc{StaticSubChild}/gc{DemoGrandChild}", index.get(9));
|
||||
assertEquals("/c{DemoChild}/gc{DemoGrandChild}/i{int}", index.get(2));
|
||||
assertEquals("/c{DemoChild}/gcs{DemoGrandChild[]}", index.get(3));
|
||||
assertEquals("/c{DemoChild}/gcs{DemoGrandChild[]}/i{int}", index.get(4));
|
||||
assertEquals("/cs{DemoChild[]}", index.get(5));
|
||||
assertEquals("/cs{DemoChild[]}/gc{DemoGrandChild}", index.get(6));
|
||||
assertEquals("/cs{DemoChild[]}/gc{DemoGrandChild}/i{int}", index.get(7));
|
||||
assertEquals("/cs{DemoChild[]}/gcs{DemoGrandChild[]}", index.get(8));
|
||||
assertEquals("/cs{DemoChild[]}/gcs{DemoGrandChild[]}/i{int}", index.get(9));
|
||||
assertEquals("/sc{SubChild}", index.get(10));
|
||||
assertEquals("/sc{SubChild}/gc{DemoGrandChild}", index.get(11));
|
||||
assertEquals("/sc{SubChild}/gc{DemoGrandChild}/i{int}", index.get(12));
|
||||
assertEquals("/ssc{StaticSubChild}", index.get(13));
|
||||
assertEquals("/ssc{StaticSubChild}/gc{DemoGrandChild}", index.get(14));
|
||||
assertEquals("/ssc{StaticSubChild}/gc{DemoGrandChild}/i{int}", index.get(15));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -43,6 +49,7 @@ class OmniAccessorTest {
|
||||
assertEquals("abc\\{[^}]+\\}/[^{]+\\{Xyz\\}", PrivateAccessor.<String>invokeStatic(OmniAccessor.class, "toPattern", "abc/{Xyz}"));
|
||||
assertEquals("[^{]+\\{Abc\\}/[^{]+\\{Xyz\\}", PrivateAccessor.<String>invokeStatic(OmniAccessor.class, "toPattern", "{Abc}/{Xyz}"));
|
||||
assertEquals("[^{]+\\{Abc\\[\\]\\}/[^{]+\\{Xyz\\[\\]\\}", PrivateAccessor.<String>invokeStatic(OmniAccessor.class, "toPattern", "{Abc[]}/{Xyz[]}"));
|
||||
assertEquals("abc\\{[^}]+\\}/[^{]+\\{Xyz\\[\\]\\}", PrivateAccessor.<String>invokeStatic(OmniAccessor.class, "toPattern", "abc[1]/{Xyz[]}[2]"));
|
||||
assertEquals("abc\\{[^}]+\\}/[^{]+\\{Xyz\\}/demo\\{[^}]+\\}", PrivateAccessor.<String>invokeStatic(OmniAccessor.class, "toPattern", "abc/{Xyz}/demo"));
|
||||
}
|
||||
|
||||
@ -66,12 +73,26 @@ class OmniAccessorTest {
|
||||
|
||||
@Test
|
||||
void should_get_by_path() {
|
||||
|
||||
DemoParent parent = prepareDemoObject();
|
||||
Object obj = PrivateAccessor.<String>invokeStatic(OmniAccessor.class, "getByPath", parent, "c{DemoChild}/gc{DemoGrandChild}", "c/gc");
|
||||
assertTrue(obj instanceof DemoGrandChild);
|
||||
assertEquals(1, PrivateAccessor.<Integer>get(obj, "i"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_set_by_path() {
|
||||
void should_set_by_path_segment() {
|
||||
DemoParent parent = prepareDemoObject();
|
||||
PrivateAccessor.<String>invokeStatic(OmniAccessor.class, "setByPathSegment", parent.c, "gc{DemoGrandChild}", "gc", new DemoGrandChild(2));
|
||||
assertEquals(2, PrivateAccessor.<Integer>get(parent.c.gc, "i"));
|
||||
}
|
||||
|
||||
private DemoParent prepareDemoObject() {
|
||||
DemoParent parent = new DemoParent();
|
||||
DemoChild child = new DemoChild();
|
||||
DemoGrandChild grandChild = new DemoGrandChild(1);
|
||||
PrivateAccessor.set(parent, "c", child);
|
||||
PrivateAccessor.set(child, "gc", grandChild);
|
||||
return parent;
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user