Skip to content

Commit

Permalink
add MethodFilter
Browse files Browse the repository at this point in the history
  • Loading branch information
leaderli committed Mar 3, 2024
1 parent 8d4984f commit 72445e2
Show file tree
Hide file tree
Showing 15 changed files with 266 additions and 68 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package io.leaderli.litool.core.function;

public interface Chain<T> {

Chain<T> addHead(T filter);

Chain<T> add(T filter);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package io.leaderli.litool.core.lang;

import io.leaderli.litool.core.function.Chain;
import io.leaderli.litool.core.function.Filter;

import java.util.ArrayList;
import java.util.List;

public class FilterChain<T> implements Filter<T>, Chain<Filter<T>> {

private final List<Filter<T>> chain = new ArrayList<>();

public FilterChain() {

}

public FilterChain(Filter<T> filter) {
add(filter);
}

@Override
public Boolean apply(T t) {
for (Filter<T> filter : chain) {
if (!filter.apply(t)) {
return false;
}
}
return true;
}

@SuppressWarnings("unchecked")
public FilterChain<T> addHead(Filter<T> filter) {
if (filter instanceof FilterChain) {
((FilterChain<Object>) filter).chain.forEach(f -> addHead((Filter<T>) f));
} else {
chain.add(0, filter);
}
return this;
}

@SuppressWarnings("unchecked")
public FilterChain<T> add(Filter<T> filter) {
if (filter instanceof FilterChain) {
((FilterChain<Object>) filter).chain.forEach(f -> add((Filter<T>) f));
} else {
chain.add(filter);
}
return this;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package io.leaderli.litool.core.type;

import io.leaderli.litool.core.function.Chain;
import io.leaderli.litool.core.function.Filter;
import io.leaderli.litool.core.lang.FilterChain;

import java.lang.reflect.Method;
import java.util.Objects;

public class MethodFilter implements Filter<Method>, Chain<Filter<Method>> {

private final FilterChain<Method> filter = new FilterChain<>();


@Override
public Boolean apply(Method method) {
return filter.apply(method);
}


// public static class Builder {
//
//
public static MethodFilter isMethod() {
return new MethodFilter().add(Objects::nonNull);
}

public static MethodFilter name(String name) {
return new MethodFilter().add(m -> m.getName().equals(name));
}

public static MethodFilter isPublic() {
return new MethodFilter().add(ModifierUtil::isPublic);
}

public static MethodFilter of(Filter<Method> filter) {
return new MethodFilter().add(filter);
}

// public MethodFilter name(String name) {
// return new MethodFilter().add(m -> m.getName().equals(name));
// }
//
// public void returnType(Class<?> returnType) {
// this.returnType = returnType;
// }
//
// public void parameterType(Class<?>[] parameterType) {
// this.parameterType = parameterType;
// }
//
// public void parameterlenth(Class<?>[] parameterlenth) {
// this.parameterlenth = parameterlenth;
// }
//
// public void annotated(Class<? extends Annotation> annotated) {
// this.annotated = annotated;
// }
//
public void modifiers(int modifiers) {
}

@Override
public MethodFilter addHead(Filter<Method> filter) {
this.filter.addHead(filter);
return this;
}

@Override
public MethodFilter add(Filter<Method> filter) {
this.filter.add(filter);
return this;
}


// public void isAbstract() {
// this.modifiers |= Modifier.ABSTRACT;
// }
//
// public void isStatic() {
// this.modifiers |= Modifier.STATIC;
// }


// }


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package io.leaderli.litool.core.lang;

import io.leaderli.litool.core.meta.LiBox;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

class FilterChainTest {

@Test
void test() {

FilterChain<Integer> filter = new FilterChain<>();
filter.add(i -> i > 10);

Assertions.assertTrue(filter.apply(11));
Assertions.assertFalse(filter.apply(9));
filter.add(i -> i < 100);
Assertions.assertTrue(filter.apply(11));
Assertions.assertFalse(filter.apply(101));

FilterChain<Integer> filter2 = new FilterChain<>();
filter2.add(filter);
Assertions.assertFalse(filter2.apply(9));
Assertions.assertTrue(filter2.apply(11));
Assertions.assertFalse(filter2.apply(101));

FilterChain<Integer> filter3 = new FilterChain<>();
filter3.add(filter2);
filter3.add(i -> i % 2 == 0);
Assertions.assertFalse(filter3.apply(9));
Assertions.assertTrue(filter3.apply(12));
Assertions.assertFalse(filter3.apply(11));
Assertions.assertFalse(filter3.apply(101));

FilterChain<Integer> filter4 = new FilterChain<>();
LiBox<Integer> box = LiBox.of(0);
filter4.add(i -> {
box.value(1);
return true;
});
filter4.add(i -> {
box.value(2);
return false;
});
filter4.apply(1);

Assertions.assertEquals(2, box.value());
box.value(0);
filter4.addHead(i -> false);
filter4.apply(1);
Assertions.assertEquals(0, box.value());

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import io.leaderli.litool.core.collection.ArrayEqual;
import io.leaderli.litool.core.meta.Either;
import io.leaderli.litool.core.type.MethodFilter;
import io.leaderli.litool.core.type.PrimitiveEnum;

@SuppressWarnings({"rawtypes"})
Expand All @@ -13,7 +14,7 @@ public AbstractMocker(Class<?> mockClass, boolean detach) {
super(mockClass);
this.detach = detach;
// 仅在build过程中生效,用于记录方法的调用
LiMock.mock(mockClass, m -> true, (method, args) -> {
LiMock.mock(mockClass, MethodFilter.isMethod(), (method, args) -> {
if (build) {
return Either.none();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import io.leaderli.litool.core.meta.Either;
import io.leaderli.litool.core.type.ClassUtil;
import io.leaderli.litool.core.type.MethodFilter;
import io.leaderli.litool.core.type.PrimitiveEnum;
import org.junit.jupiter.api.Assertions;

Expand All @@ -22,7 +23,7 @@ public class AbstractRecorder<T> {
public AbstractRecorder(Class<?> mockClass) {
this.mockClass = mockClass;
// 仅在build过程中生效,用于记录方法的调用
LiMock.mock(mockClass, m -> true, (method, args) -> {
LiMock.mock(mockClass, MethodFilter.isMethod(), (method, args) -> {
if (build) {
return Either.none();
}
Expand Down
50 changes: 22 additions & 28 deletions litool-test/src/main/java/io/leaderli/litool/test/LiMock.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,12 @@

import io.leaderli.litool.core.collection.ArrayUtils;
import io.leaderli.litool.core.exception.LiAssertUtil;
import io.leaderli.litool.core.function.Filter;
import io.leaderli.litool.core.meta.Either;
import io.leaderli.litool.core.meta.LiTuple;
import io.leaderli.litool.core.meta.Lira;
import io.leaderli.litool.core.text.StrSubstitution;
import io.leaderli.litool.core.text.StringUtils;
import io.leaderli.litool.core.type.LiTypeToken;
import io.leaderli.litool.core.type.MethodUtil;
import io.leaderli.litool.core.type.ModifierUtil;
import io.leaderli.litool.core.type.PrimitiveEnum;
import io.leaderli.litool.core.type.*;
import javassist.*;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.agent.ByteBuddyAgent;
Expand All @@ -29,7 +25,6 @@
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.function.Function;

public class LiMock {
public static final Map<Class<?>, byte[]> originClasses = new HashMap<>();
Expand Down Expand Up @@ -117,11 +112,10 @@ private static CtMethod getCtMethod(Method method, CtClass ct) throws NotFoundEx
}


private static Method[] findDeclaredMethods(Class<?> clazz, Function<Method, Boolean> methodFilter) {
private static Method[] findDeclaredMethods(Class<?> clazz, MethodFilter methodFilter) {
methodFilter.addHead(m -> !(m.isSynthetic() || ModifierUtil.isAbstract(m)));
return Lira.of(clazz.getDeclaredMethods())
.filter(methodFilter)
.filter(m -> !m.isSynthetic())
.filter(m -> !ModifierUtil.isAbstract(m))
.toArray(Method.class);
}

Expand Down Expand Up @@ -191,24 +185,24 @@ public static void skipClassConstructors(Class<?> mockClass, boolean detach) {
}

/**
* @param mockClass 代理类,仅代理属于该类的方法,不涉及其他方法
* @param mockMethodFilter 代理方法的过滤类,用于筛选需要代理的方法
* @param methodProxy 代理函数
* @param detach 是否先重置类
* @param mockClass 代理类,仅代理属于该类的方法,不涉及其他方法
* @param methodFilter 代理方法的过滤类,用于筛选需要代理的方法
* @param methodProxy 代理函数
* @param detach 是否先重置类
* @see MockMethodInvoker#invoke(String, Class, String, Class[], Object[])
* @see MethodProxy#apply(Method, Object[]) 根据返回值来判断是否需要真正拦截,如果返回的是 判断是否有右值,
* 如果有则返回右值,否则不进行拦截。
* 函数如果判断不需要拦截直接返回{@link Either#none()}即可。如果方法本身返回的是{@link Either}需要额外对在函数中额外包一层{@link Either}。
*/
public static void mock(Class<?> mockClass, Function<Method, Boolean> mockMethodFilter, MethodProxy methodProxy, boolean detach) {
public static void mock(Class<?> mockClass, MethodFilter methodFilter, MethodProxy methodProxy, boolean detach) {
try {
backup(mockClass);
if (detach) {
detach(mockClass);
}
CtClass ct = getCtClass(mockClass);

for (Method method : findDeclaredMethods(mockClass, mockMethodFilter)) {
for (Method method : findDeclaredMethods(mockClass, methodFilter)) {

CtMethod ctMethod = getCtMethod(method, ct);
String uuid = method.getName() + " " + UUID.randomUUID();
Expand All @@ -234,28 +228,28 @@ public static void mock(Class<?> mockClass, Function<Method, Boolean> mockMethod
/**
* 重置类并拦截方法
*
* @see #mock(Class, Function, MethodProxy, boolean)
* @see #mock(Class, MethodFilter, MethodProxy, boolean)
*/
public static void mock(Class<?> mockClass, Filter<Method> mockMethodFilter, MethodProxy methodProxy) {
mock(mockClass, mockMethodFilter, methodProxy, true);
public static void mock(Class<?> mockClass, MethodFilter methodFilter, MethodProxy methodProxy) {
mock(mockClass, methodFilter, methodProxy, true);
}

/**
* 重置类并拦截静态方法
*
* @see #mockStatic(Class, Function, MethodProxy, boolean)
* @see #mockStatic(Class, MethodFilter, MethodProxy, boolean)
*/
public static void mockStatic(Class<?> mockClass, Filter<Method> mockMethodFilter, MethodProxy methodProxy) {
mock(mockClass, m -> ModifierUtil.isStatic(m) && mockMethodFilter.apply(m), methodProxy);
public static void mockStatic(Class<?> mockClass, MethodFilter methodFilter, MethodProxy methodProxy) {
mock(mockClass, methodFilter.addHead(ModifierUtil::isStatic), methodProxy);
}

/**
* 拦截静态方法
*
* @see #mock(Class, Function, MethodProxy, boolean)
* @see #mock(Class, MethodFilter, MethodProxy, boolean)
*/
public static void mockStatic(Class<?> mockClass, Function<Method, Boolean> mockMethodFilter, MethodProxy methodProxy, boolean detach) {
mock(mockClass, m -> ModifierUtil.isStatic(m) && mockMethodFilter.apply(m), methodProxy, detach);
public static void mockStatic(Class<?> mockClass, MethodFilter methodFilter, MethodProxy methodProxy, boolean detach) {
mock(mockClass, methodFilter.addHead(ModifierUtil::isStatic), methodProxy, detach);
}


Expand All @@ -267,7 +261,7 @@ public static void mockStatic(Class<?> mockClass, Function<Method, Boolean> mock
* @param methodAssert 断言函数
* @see MockMethodInvoker#record(String, Object, Object[], Object)
*/
public static void record(Class<?> mockClass, Function<Method, Boolean> mockMethodFilter, MethodAssert methodAssert) {
public static void record(Class<?> mockClass, MethodFilter mockMethodFilter, MethodAssert methodAssert) {

CtClass ct = getCtClass(mockClass);

Expand All @@ -292,10 +286,10 @@ public static void record(Class<?> mockClass, Function<Method, Boolean> mockMeth
/**
* 拦截静态方法
*
* @see #record(Class, Function, MethodAssert)
* @see #record(Class, MethodFilter, MethodAssert)
*/
public static void recordStatic(Class<?> mockClass, Function<Method, Boolean> mockMethodFilter, MethodAssert methodAssert) {
record(mockClass, m -> ModifierUtil.isStatic(m) && mockMethodFilter.apply(m), methodAssert);
public static void recordStatic(Class<?> mockClass, MethodFilter methodFilter, MethodAssert methodAssert) {
record(mockClass, methodFilter.addHead(ModifierUtil::isStatic), methodAssert);
}

/**
Expand Down

This file was deleted.

Loading

0 comments on commit 72445e2

Please sign in to comment.