From 00cc5d896ee0680761d3a7c30396a28fd9e4ce13 Mon Sep 17 00:00:00 2001 From: redkale Date: Thu, 29 Jun 2023 08:25:12 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0LambdaFunction=E5=92=8CLambda?= =?UTF-8?q?Supplier=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/redkale/source/ColumnValue.java | 267 ++++++++++++++++ .../java/org/redkale/source/DataSource.java | 130 ++++++++ .../java/org/redkale/source/FilterNode.java | 72 +++++ .../java/org/redkale/util/LambdaFunction.java | 36 +++ .../java/org/redkale/util/LambdaSupplier.java | 26 ++ .../java/org/redkale/util/SelectColumn.java | 30 ++ .../org/redkale/util/SerializedLambda.java | 298 ++++++++++++++++++ .../redkale/test/source/CacheTestBean.java | 5 +- .../redkale/test/source/TestSourceCache.java | 23 +- 9 files changed, 871 insertions(+), 16 deletions(-) create mode 100644 src/main/java/org/redkale/util/LambdaFunction.java create mode 100644 src/main/java/org/redkale/util/LambdaSupplier.java create mode 100644 src/main/java/org/redkale/util/SerializedLambda.java diff --git a/src/main/java/org/redkale/source/ColumnValue.java b/src/main/java/org/redkale/source/ColumnValue.java index 7893e55ba..5237994ce 100644 --- a/src/main/java/org/redkale/source/ColumnValue.java +++ b/src/main/java/org/redkale/source/ColumnValue.java @@ -8,6 +8,7 @@ package org.redkale.source; import java.io.Serializable; import java.util.Objects; import static org.redkale.source.ColumnExpress.*; +import org.redkale.util.*; /** * ColumnValue主要用于多个字段更新的表达式。 @@ -30,6 +31,22 @@ public class ColumnValue { public ColumnValue() { } + public ColumnValue(LambdaSupplier func) { + this(LambdaSupplier.readColumn(func), ColumnExpress.MOV, func.get()); + } + + public ColumnValue(LambdaSupplier func, ColumnExpress express) { + this(LambdaSupplier.readColumn(func), express, func.get()); + } + + public ColumnValue(LambdaFunction func, Serializable value) { + this(LambdaFunction.readColumn(func), ColumnExpress.MOV, value); + } + + public ColumnValue(LambdaFunction func, ColumnExpress express, Serializable value) { + this(LambdaFunction.readColumn(func), express, value); + } + public ColumnValue(String column, Serializable value) { this(column, ColumnExpress.MOV, value); } @@ -175,6 +192,256 @@ public class ColumnValue { return new ColumnValue(column, ORR, value); } + /** + * 同 mov 操作 + * + * @param func 字段名Lambda + * + * + * @return ColumnValue + * + * @since 2.8.0 + */ + public static ColumnValue create(LambdaSupplier func) { + return new ColumnValue(func); + } + + /** + * 返回 {column} = {value} 操作 + * + * @param func 字段名Lambda + * @param 值的泛型 + * + * @return ColumnValue + * + * @since 2.8.0 + */ + public static ColumnValue mov(LambdaSupplier func) { + return new ColumnValue(func, MOV); + } + + /** + * 返回 {column} = {column} + {value} 操作 + * + * @param func 字段名Lambda + * @param 值的泛型 + * + * @return ColumnValue + * + * @since 2.8.0 + */ + public static ColumnValue inc(LambdaSupplier func) { + return new ColumnValue(func, INC); + } + + /** + * 返回 {column} = {column} - {value} 操作 + * + * @param func 字段名Lambda + * @param 值的泛型 + * + * @return ColumnValue + * + * @since 2.8.0 + */ + public static ColumnValue dec(LambdaSupplier func) { + return new ColumnValue(func, DEC); + } + + /** + * 返回 {column} = {column} * {value} 操作 + * + * @param func 字段名Lambda + * @param 值的泛型 + * + * @return ColumnValue + * + * @since 2.8.0 + */ + public static ColumnValue mul(LambdaSupplier func) { + return new ColumnValue(func, MUL); + } + + /** + * 返回 {column} = {column} / {value} 操作 + * + * @param func 字段名Lambda + * @param 值的泛型 + * + * @return ColumnValue + * + * @since 2.8.0 + */ + public static ColumnValue div(LambdaSupplier func) { + return new ColumnValue(func, DIV); + } + + /** + * 返回 {column} = {column} & {value} 操作 + * + * @param func 字段名Lambda + * @param 值的泛型 + * + * @return ColumnValue + * + * @since 2.8.0 + */ + public static ColumnValue and(LambdaSupplier func) { + return new ColumnValue(func, AND); + } + + /** + * 返回 {column} = {column} | {value} 操作 + * + * @param func 字段名Lambda + * @param 值的泛型 + * + * @return ColumnValue + * + * @since 2.8.0 + */ + public static ColumnValue orr(LambdaSupplier func) { + return new ColumnValue(func, ORR); + } + + /** + * 同 mov 操作 + * + * @param func 字段名Lambda + * @param value 字段值 + * + * @return ColumnValue + * + * @since 2.8.0 + */ + public static ColumnValue create(LambdaFunction func, Serializable value) { + return new ColumnValue(func, value); + } + + /** + * 返回 {column} = {value} 操作 + * + * @param func 字段名Lambda + * @param value 字段值 + * + * @return ColumnValue + * + * @since 2.8.0 + */ + public static ColumnValue mov(LambdaFunction func, Serializable value) { + return new ColumnValue(func, MOV, value); + } + + /** + * 返回 {column} = {column} + {value} 操作 + * + * @param func 字段名Lambda + * @param value 字段值 + * + * @return ColumnValue + * + * @since 2.8.0 + */ + public static ColumnValue inc(LambdaFunction func, Serializable value) { + return new ColumnValue(func, INC, value); + } + + /** + * 返回 {column} = {column} + 1 操作 + * + * @param func 字段名Lambda + * + * @return ColumnValue + * + * @since 2.8.0 + */ + public static ColumnValue inc(LambdaFunction func) { + return new ColumnValue(func, INC, 1); + } + + /** + * 返回 {column} = {column} - {value} 操作 + * + * @param func 字段名Lambda + * @param value 字段值 + * + * @return ColumnValue + * + * @since 2.8.0 + */ + public static ColumnValue dec(LambdaFunction func, Serializable value) { + return new ColumnValue(func, DEC, value); + } + + /** + * 返回 {column} = {column} - 1 操作 + * + * @param func 字段名Lambda + * + * @return ColumnValue + * + * @since 2.8.0 + */ + public static ColumnValue dec(LambdaFunction func) { + return new ColumnValue(func, DEC, 1); + } + + /** + * 返回 {column} = {column} * {value} 操作 + * + * @param func 字段名Lambda + * @param value 字段值 + * + * @return ColumnValue + * + * @since 2.8.0 + */ + public static ColumnValue mul(LambdaFunction func, Serializable value) { + return new ColumnValue(func, MUL, value); + } + + /** + * 返回 {column} = {column} / {value} 操作 + * + * @param func 字段名Lambda + * @param value 字段值 + * + * @return ColumnValue + * + * @since 2.8.0 + */ + public static ColumnValue div(LambdaFunction func, Serializable value) { + return new ColumnValue(func, DIV, value); + } + + /** + * 返回 {column} = {column} & {value} 操作 + * + * @param func 字段名Lambda + * @param value 字段值 + * + * @return ColumnValue + * + * @since 2.8.0 + */ + public static ColumnValue and(LambdaFunction func, Serializable value) { + return new ColumnValue(func, AND, value); + } + + /** + * 返回 {column} = {column} | {value} 操作 + * + * @param func 字段名Lambda + * @param value 字段值 + * + * @return ColumnValue + * + * @since 2.8.0 + */ + public static ColumnValue orr(LambdaFunction func, Serializable value) { + return new ColumnValue(func, ORR, value); + } + public String getColumn() { return column; } diff --git a/src/main/java/org/redkale/source/DataSource.java b/src/main/java/org/redkale/source/DataSource.java index 298730c51..fdc0d2a8c 100644 --- a/src/main/java/org/redkale/source/DataSource.java +++ b/src/main/java/org/redkale/source/DataSource.java @@ -574,6 +574,23 @@ public interface DataSource extends Resourcable { */ public int updateColumn(final Class clazz, final Serializable pk, final String column, final Serializable value); + /** + * 更新单个记录的单个字段
+ * 注意:即使字段标记为@Column(updatable=false)也会被更新
+ * 等价SQL: UPDATE {table} SET {column} = {value} WHERE {primary} = {id}
+ * + * @param Entity泛型 + * @param 更新值泛型 + * @param clazz Entity类 + * @param pk 主键 + * @param func 更新值Lambda + * + * @return 影响的记录条数 + */ + default int updateColumn(final Class clazz, final Serializable pk, final LambdaSupplier func) { + return updateColumn(clazz, pk, LambdaSupplier.readColumn(func), func.get()); + } + /** * 更新单个记录的单个字段
* 注意:即使字段标记为@Column(updatable=false)也会被更新
@@ -589,6 +606,23 @@ public interface DataSource extends Resourcable { */ public CompletableFuture updateColumnAsync(final Class clazz, final Serializable pk, final String column, final Serializable value); + /** + * 更新单个记录的单个字段
+ * 注意:即使字段标记为@Column(updatable=false)也会被更新
+ * 等价SQL: UPDATE {table} SET {column} = {value} WHERE {primary} = {id}
+ * + * @param Entity泛型 + * @param 更新值泛型 + * @param clazz Entity类 + * @param pk 主键 + * @param func 更新值Lambda + * + * @return 影响的记录条数 + */ + default CompletableFuture updateColumnAsync(final Class clazz, final Serializable pk, final LambdaSupplier func) { + return updateColumnAsync(clazz, pk, LambdaSupplier.readColumn(func), func.get()); + } + /** * 更新符合过滤条件记录的单个字段
* 注意:即使字段标记为@Column(updatable=false)也会被更新
@@ -604,6 +638,23 @@ public interface DataSource extends Resourcable { */ public int updateColumn(final Class clazz, final String column, final Serializable value, final FilterNode node); + /** + * 更新符合过滤条件记录的单个字段
+ * 注意:即使字段标记为@Column(updatable=false)也会被更新
+ * 等价SQL: UPDATE {table} SET {column} = {value} WHERE {filter node}
+ * + * @param Entity泛型 + * @param 更新值泛型 + * @param clazz Entity类 + * @param func 更新值Lambda + * @param node 过滤条件 + * + * @return 影响的记录条数 + */ + default int updateColumn(final Class clazz, final LambdaSupplier func, final FilterNode node) { + return updateColumn(clazz, LambdaSupplier.readColumn(func), func.get(), node); + } + /** * 更新符合过滤条件记录的单个字段
* 注意:即使字段标记为@Column(updatable=false)也会被更新
@@ -619,6 +670,23 @@ public interface DataSource extends Resourcable { */ public CompletableFuture updateColumnAsync(final Class clazz, final String column, final Serializable value, final FilterNode node); + /** + * 更新符合过滤条件记录的单个字段
+ * 注意:即使字段标记为@Column(updatable=false)也会被更新
+ * 等价SQL: UPDATE {table} SET {column} = {value} WHERE {filter node}
+ * + * @param Entity泛型 + * @param 更新值泛型 + * @param clazz Entity类 + * @param func 更新值Lambda + * @param node 过滤条件 + * + * @return 影响的记录条数 + */ + default CompletableFuture updateColumnAsync(final Class clazz, final LambdaSupplier func, final FilterNode node) { + return updateColumnAsync(clazz, LambdaSupplier.readColumn(func), func.get(), node); + } + /** * 更新指定主键值记录的部分字段
* 字段赋值操作选项见 ColumnExpress
@@ -728,6 +796,21 @@ public interface DataSource extends Resourcable { return updateColumn(entity, (FilterNode) null, columns); } + /** + * 更新单个记录的指定字段
+ * 注意:Entity类中标记为@Column(updatable=false)不会被更新
+ * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· WHERE {primary} = {bean.id}
+ * + * @param Entity泛型 + * @param entity 待更新的Entity对象 + * @param funcs 需更新的字段名Lambda集合 + * + * @return 影响的记录条数 + */ + default int updateColumn(final T entity, final LambdaFunction... funcs) { + return updateColumn(entity, (FilterNode) null, LambdaFunction.readColumns(funcs)); + } + /** * 更新单个记录的指定字段
* 注意:Entity类中标记为@Column(updatable=false)不会被更新
@@ -743,6 +826,21 @@ public interface DataSource extends Resourcable { return updateColumnAsync(entity, (FilterNode) null, columns); } + /** + * 更新单个记录的指定字段
+ * 注意:Entity类中标记为@Column(updatable=false)不会被更新
+ * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· WHERE {primary} = {bean.id}
+ * + * @param Entity泛型 + * @param entity 待更新的Entity对象 + * @param funcs 需更新的字段名Lambda集合 + * + * @return 影响的记录条数CompletableFuture + */ + default CompletableFuture updateColumnAsync(final T entity, final LambdaFunction... funcs) { + return updateColumnAsync(entity, (FilterNode) null, LambdaFunction.readColumns(funcs)); + } + /** * 更新符合过滤条件记录的指定字段
* 注意:Entity类中标记为@Column(updatable=false)不会被更新
@@ -757,6 +855,22 @@ public interface DataSource extends Resourcable { */ public int updateColumn(final T entity, final FilterNode node, final String... columns); + /** + * 更新符合过滤条件记录的指定字段
+ * 注意:Entity类中标记为@Column(updatable=false)不会被更新
+ * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· WHERE {filter node}
+ * + * @param Entity泛型 + * @param entity 待更新的Entity对象 + * @param node 过滤条件 + * @param funcs 需更新的字段名Lambda集合 + * + * @return 影响的记录条数 + */ + default int updateColumn(final T entity, final FilterNode node, final LambdaFunction... funcs) { + return updateColumn(entity, node, LambdaFunction.readColumns(funcs)); + } + /** * 更新符合过滤条件记录的指定字段
* 注意:Entity类中标记为@Column(updatable=false)不会被更新
@@ -771,6 +885,22 @@ public interface DataSource extends Resourcable { */ public CompletableFuture updateColumnAsync(final T entity, final FilterNode node, final String... columns); + /** + * 更新符合过滤条件记录的指定字段
+ * 注意:Entity类中标记为@Column(updatable=false)不会被更新
+ * 等价SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· WHERE {filter node}
+ * + * @param Entity泛型 + * @param entity 待更新的Entity对象 + * @param node 过滤条件 + * @param funcs 需更新的字段名Lambda集合 + * + * @return 影响的记录条数 + */ + default CompletableFuture updateColumnAsync(final T entity, final FilterNode node, final LambdaFunction... funcs) { + return updateColumnAsync(entity, node, LambdaFunction.readColumns(funcs)); + } + /** * 更新单个记录的指定字段
* 注意:Entity类中标记为@Column(updatable=false)不会被更新
diff --git a/src/main/java/org/redkale/source/FilterNode.java b/src/main/java/org/redkale/source/FilterNode.java index f66c6cdda..66ddb3366 100644 --- a/src/main/java/org/redkale/source/FilterNode.java +++ b/src/main/java/org/redkale/source/FilterNode.java @@ -161,6 +161,30 @@ public class FilterNode { //FilterNode 不能实现Serializable接口, 否则 return and(new FilterNode(column, express, itemand, value)); } + public final FilterNode and(LambdaSupplier func) { + return and(func, null); + } + + public final FilterNode and(LambdaSupplier func, FilterExpress express) { + return and(func, express, true); + } + + public final FilterNode and(LambdaSupplier func, FilterExpress express, boolean itemand) { + return and(new FilterNode(LambdaSupplier.readColumn(func), express, itemand, func.get())); + } + + public final FilterNode and(LambdaFunction func, Serializable value) { + return and(func, null, value); + } + + public final FilterNode and(LambdaFunction func, FilterExpress express, Serializable value) { + return and(func, express, true, value); + } + + public final FilterNode and(LambdaFunction func, FilterExpress express, boolean itemand, Serializable value) { + return and(new FilterNode(LambdaFunction.readColumn(func), express, itemand, value)); + } + public final FilterNode or(FilterNode node) { return any(node, true); } @@ -177,6 +201,30 @@ public class FilterNode { //FilterNode 不能实现Serializable接口, 否则 return or(new FilterNode(column, express, itemand, value)); } + public final FilterNode or(LambdaSupplier func) { + return or(func, null); + } + + public final FilterNode or(LambdaSupplier func, FilterExpress express) { + return or(func, express, true); + } + + public final FilterNode or(LambdaSupplier func, FilterExpress express, boolean itemand) { + return or(new FilterNode(LambdaSupplier.readColumn(func), express, itemand, func.get())); + } + + public final FilterNode or(LambdaFunction func, Serializable value) { + return or(func, null, value); + } + + public final FilterNode or(LambdaFunction func, FilterExpress express, Serializable value) { + return or(func, express, true, value); + } + + public final FilterNode or(LambdaFunction func, FilterExpress express, boolean itemand, Serializable value) { + return or(new FilterNode(LambdaFunction.readColumn(func), express, itemand, value)); + } + protected FilterNode any(FilterNode node, boolean signor) { if (this.readOnly) { throw new SourceException("FilterNode(" + this + ") is ReadOnly"); @@ -347,6 +395,30 @@ public class FilterNode { //FilterNode 不能实现Serializable接口, 否则 return new FilterNode(column, express, itemand, value); } + public static FilterNode create(LambdaSupplier func) { + return create(func, null); + } + + public static FilterNode create(LambdaSupplier func, FilterExpress express) { + return create(func, express, true); + } + + public static FilterNode create(LambdaSupplier func, FilterExpress express, boolean itemand) { + return new FilterNode(LambdaSupplier.readColumn(func), express, itemand, func.get()); + } + + public static FilterNode create(LambdaFunction func, Serializable value) { + return create(func, null, value); + } + + public static FilterNode create(LambdaFunction func, FilterExpress express, Serializable value) { + return create(func, express, true, value); + } + + public static FilterNode create(LambdaFunction func, FilterExpress express, boolean itemand, Serializable value) { + return new FilterNode(LambdaFunction.readColumn(func), express, itemand, value); + } + @Deprecated(since = "2.8.0") public static FilterNode filter(String column, Serializable value) { return create(column, null, value); diff --git a/src/main/java/org/redkale/util/LambdaFunction.java b/src/main/java/org/redkale/util/LambdaFunction.java new file mode 100644 index 000000000..e845e920b --- /dev/null +++ b/src/main/java/org/redkale/util/LambdaFunction.java @@ -0,0 +1,36 @@ +/* + * + */ +package org.redkale.util; + +import java.io.Serializable; +import java.util.function.Function; + +/** + * Lambda的Function自定义类 + * + *

+ * 详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + * + * @param 泛型 + * @param 泛型 + */ +@FunctionalInterface +public interface LambdaFunction extends Function, Serializable { + + public static String[] readColumns(LambdaFunction... funcs) { + String[] columns = new String[funcs.length]; + for (int i = 0; i < columns.length; i++) { + columns[i] = readColumn(funcs[i]); + } + return columns; + } + + public static String readColumn(LambdaFunction func) { + return SerializedLambda.readColumn(func); + } + +} diff --git a/src/main/java/org/redkale/util/LambdaSupplier.java b/src/main/java/org/redkale/util/LambdaSupplier.java new file mode 100644 index 000000000..f26d7205f --- /dev/null +++ b/src/main/java/org/redkale/util/LambdaSupplier.java @@ -0,0 +1,26 @@ +/* + * + */ +package org.redkale.util; + +import java.io.Serializable; +import java.util.function.Supplier; + +/** + * Lambda的Supplier自定义类 + * + *

+ * 详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + * + * @param 泛型 + */ +@FunctionalInterface +public interface LambdaSupplier extends Supplier, Serializable { + + public static String readColumn(LambdaSupplier func) { + return SerializedLambda.readColumn(func); + } +} diff --git a/src/main/java/org/redkale/util/SelectColumn.java b/src/main/java/org/redkale/util/SelectColumn.java index 927cb8998..d524d7348 100644 --- a/src/main/java/org/redkale/util/SelectColumn.java +++ b/src/main/java/org/redkale/util/SelectColumn.java @@ -86,6 +86,19 @@ public class SelectColumn implements Predicate { // public static SelectColumn createIncludes(String... columns) { // return new SelectColumn(columns, false); // } +// +// + /** + * class中的字段名 + * + * @param funcs 包含的字段名Lambda集合 + * + * @return SelectColumn + */ + public static SelectColumn includes(LambdaFunction... funcs) { + return includes(LambdaFunction.readColumns(funcs)); + } + /** * class中的字段名 * @@ -109,6 +122,8 @@ public class SelectColumn implements Predicate { // public static SelectColumn createIncludes(String[] cols, String... columns) { // return new SelectColumn(Utility.append(cols, columns), false); // } +// +// /** * class中的字段名 * @@ -133,6 +148,19 @@ public class SelectColumn implements Predicate { // public static SelectColumn createExcludes(String... columns) { // return new SelectColumn(columns, true); // } +// +// + /** + * class中的字段名 + * + * @param funcs 包含的字段名Lambda集合 + * + * @return SelectColumn + */ + public static SelectColumn excludes(LambdaFunction... funcs) { + return excludes(LambdaFunction.readColumns(funcs)); + } + /** * class中的字段名 * @@ -156,6 +184,8 @@ public class SelectColumn implements Predicate { // public static SelectColumn createExcludes(String[] cols, String... columns) { // return new SelectColumn(Utility.append(cols, columns), true); // } +// +// /** * * class中的字段名 diff --git a/src/main/java/org/redkale/util/SerializedLambda.java b/src/main/java/org/redkale/util/SerializedLambda.java new file mode 100644 index 000000000..68d262cbf --- /dev/null +++ b/src/main/java/org/redkale/util/SerializedLambda.java @@ -0,0 +1,298 @@ +/* + * + */ +package org.redkale.util; + +import java.io.*; +import java.lang.invoke.MethodHandleInfo; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 完全复制java.lang.invoke.SerializedLambda类源码,必须保持字段信息一样 + * + *

+ * 详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + * + */ +public class SerializedLambda implements Serializable { + + private static final long serialVersionUID = 8025925345765570181L; + + /** + * The capturing class. + */ + private final Class capturingClass; + + /** + * The functional interface class. + */ + private final String functionalInterfaceClass; + + /** + * The functional interface method name. + */ + private final String functionalInterfaceMethodName; + + /** + * The functional interface method signature. + */ + private final String functionalInterfaceMethodSignature; + + /** + * The implementation class. + */ + private final String implClass; + + /** + * The implementation method name. + */ + private final String implMethodName; + + /** + * The implementation method signature. + */ + private final String implMethodSignature; + + /** + * The implementation method kind. + */ + private final int implMethodKind; + + /** + * The instantiated method type. + */ + private final String instantiatedMethodType; + + /** + * The captured arguments. + */ + @SuppressWarnings("serial") // Not statically typed as Serializable + private final Object[] capturedArgs; + + /** + * Create a {@code SerializedLambda} from the low-level information present + * at the lambda factory site. + * + * @param capturingClass The class in which the lambda expression appears + * @param functionalInterfaceClass Name, in slash-delimited form, of static + * type of the returned lambda object + * @param functionalInterfaceMethodName Name of the functional interface + * method for the present at the + * lambda factory site + * @param functionalInterfaceMethodSignature Signature of the functional + * interface method present at + * the lambda factory site + * @param implMethodKind Method handle kind for the implementation method + * @param implClass Name, in slash-delimited form, for the class holding + * the implementation method + * @param implMethodName Name of the implementation method + * @param implMethodSignature Signature of the implementation method + * @param instantiatedMethodType The signature of the primary functional + * interface method after type variables + * are substituted with their instantiation + * from the capture site + * @param capturedArgs The dynamic arguments to the lambda factory site, + * which represent variables captured by + * the lambda + */ + public SerializedLambda(Class capturingClass, + String functionalInterfaceClass, + String functionalInterfaceMethodName, + String functionalInterfaceMethodSignature, + int implMethodKind, + String implClass, + String implMethodName, + String implMethodSignature, + String instantiatedMethodType, + Object[] capturedArgs) { + this.capturingClass = capturingClass; + this.functionalInterfaceClass = functionalInterfaceClass; + this.functionalInterfaceMethodName = functionalInterfaceMethodName; + this.functionalInterfaceMethodSignature = functionalInterfaceMethodSignature; + this.implMethodKind = implMethodKind; + this.implClass = implClass; + this.implMethodName = implMethodName; + this.implMethodSignature = implMethodSignature; + this.instantiatedMethodType = instantiatedMethodType; + this.capturedArgs = Objects.requireNonNull(capturedArgs).clone(); + } + + /** + * Get the name of the class that captured this lambda. + * + * @return the name of the class that captured this lambda + */ + public String getCapturingClass() { + return capturingClass.getName().replace('.', '/'); + } + + /** + * Get the name of the invoked type to which this + * lambda has been converted + * + * @return the name of the functional interface class to which + * this lambda has been converted + */ + public String getFunctionalInterfaceClass() { + return functionalInterfaceClass; + } + + /** + * Get the name of the primary method for the functional interface + * to which this lambda has been converted. + * + * @return the name of the primary methods of the functional interface + */ + public String getFunctionalInterfaceMethodName() { + return functionalInterfaceMethodName; + } + + /** + * Get the signature of the primary method for the functional + * interface to which this lambda has been converted. + * + * @return the signature of the primary method of the functional + * interface + */ + public String getFunctionalInterfaceMethodSignature() { + return functionalInterfaceMethodSignature; + } + + /** + * Get the name of the class containing the implementation + * method. + * + * @return the name of the class containing the implementation + * method + */ + public String getImplClass() { + return implClass; + } + + /** + * Get the name of the implementation method. + * + * @return the name of the implementation method + */ + public String getImplMethodName() { + return implMethodName; + } + + /** + * Get the signature of the implementation method. + * + * @return the signature of the implementation method + */ + public String getImplMethodSignature() { + return implMethodSignature; + } + + /** + * Get the method handle kind (see {@link MethodHandleInfo}) of + * the implementation method. + * + * @return the method handle kind of the implementation method + */ + public int getImplMethodKind() { + return implMethodKind; + } + + /** + * Get the signature of the primary functional interface method + * after type variables are substituted with their instantiation + * from the capture site. + * + * @return the signature of the primary functional interface method + * after type variable processing + */ + public final String getInstantiatedMethodType() { + return instantiatedMethodType; + } + + /** + * Get the count of dynamic arguments to the lambda capture site. + * + * @return the count of dynamic arguments to the lambda capture site + */ + public int getCapturedArgCount() { + return capturedArgs.length; + } + + /** + * Get a dynamic argument to the lambda capture site. + * + * @param i the argument to capture + * + * @return a dynamic argument to the lambda capture site + */ + public Object getCapturedArg(int i) { + return capturedArgs[i]; + } + + @Override + public String toString() { + String implKind = MethodHandleInfo.referenceKindToString(implMethodKind); + return String.format("SerializedLambda[%s=%s, %s=%s.%s:%s, " + + "%s=%s %s.%s:%s, %s=%s, %s=%d]", + "capturingClass", capturingClass, + "functionalInterfaceMethod", functionalInterfaceClass, + functionalInterfaceMethodName, + functionalInterfaceMethodSignature, + "implementation", + implKind, + implClass, implMethodName, implMethodSignature, + "instantiatedMethodType", instantiatedMethodType, + "numCaptured", capturedArgs.length); + } + + private static final ConcurrentHashMap cache = new ConcurrentHashMap(); + + public static String readColumn(Serializable func) { + return readFieldName(readLambda(func).getImplMethodName()); + } + + public static SerializedLambda readLambda(Serializable func) { + if (!func.getClass().isSynthetic()) { //必须是Lambda表达式的合成类 + throw new RedkaleException("Not a synthetic lambda class"); + } + return cache.computeIfAbsent(func.getClass(), clazz -> { + try { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(out); + oos.writeObject(func); + ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(out.toByteArray())) { + @Override + protected Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { + Class clazz = super.resolveClass(desc); + return clazz == java.lang.invoke.SerializedLambda.class ? SerializedLambda.class : clazz; + } + }; + return (SerializedLambda) in.readObject(); + } catch (Exception e) { + throw new RedkaleException(e); + } + }); + } + + public static String readFieldName(String methodName) { + String name; + if (methodName.startsWith("is")) { + name = methodName.substring(2); + } else if (methodName.startsWith("get") || methodName.startsWith("set")) { + name = methodName.substring(3); + } else { + name = methodName; + } + if (name.length() < 2) { + return name.toLowerCase(Locale.ENGLISH); + } else if (Character.isUpperCase(name.charAt(1))) { + return name; + } else { + return name.substring(0, 1).toLowerCase(Locale.ENGLISH) + name.substring(1); + } + } +} diff --git a/src/test/java/org/redkale/test/source/CacheTestBean.java b/src/test/java/org/redkale/test/source/CacheTestBean.java index 29725f394..aab1d256f 100644 --- a/src/test/java/org/redkale/test/source/CacheTestBean.java +++ b/src/test/java/org/redkale/test/source/CacheTestBean.java @@ -9,8 +9,8 @@ import java.lang.reflect.Method; import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.function.BiFunction; -import org.redkale.persistence.Id; import org.redkale.convert.json.JsonConvert; +import org.redkale.persistence.*; import org.redkale.persistence.VirtualEntity; import org.redkale.source.*; @@ -45,6 +45,9 @@ public class CacheTestBean { System.out.println(cache.find(null, FilterNode.create("name", FilterExpress.EQUAL, "BB"))); System.out.println(cache.find(null, FilterNode.create("name", FilterExpress.IGNORECASEEQUAL, "BB"))); System.out.println(cache.querySheet(null, null, FilterNode.create("name", FilterExpress.IGNORECASENOTLIKE, "B"))); + System.out.println(cache.find(null, FilterNode.create(CacheTestBean::getName, FilterExpress.EQUAL, "BB"))); + System.out.println(cache.find(null, FilterNode.create(CacheTestBean::getName, FilterExpress.IGNORECASEEQUAL, "BB"))); + System.out.println(cache.querySheet(null, null, FilterNode.create(CacheTestBean::getName, FilterExpress.IGNORECASENOTLIKE, "B"))); } public CacheTestBean() { diff --git a/src/test/java/org/redkale/test/source/TestSourceCache.java b/src/test/java/org/redkale/test/source/TestSourceCache.java index 0d30bd3d3..c4af028c9 100644 --- a/src/test/java/org/redkale/test/source/TestSourceCache.java +++ b/src/test/java/org/redkale/test/source/TestSourceCache.java @@ -7,23 +7,14 @@ package org.redkale.test.source; import java.lang.reflect.Method; import java.util.*; - -import org.redkale.persistence.Cacheable; -import org.redkale.persistence.Id; -import org.redkale.persistence.VirtualEntity; -import org.redkale.source.FilterNodeBean; -import org.redkale.source.FilterExpress; -import org.redkale.source.FilterColumn; -import org.redkale.util.Sheet; -import org.redkale.source.FilterBean; -import org.redkale.source.Flipper; -import org.redkale.source.EntityInfo; -import org.redkale.source.FilterNode; -import java.util.concurrent.*; +import java.util.concurrent.CountDownLatch; import java.util.function.BiFunction; - -import org.redkale.convert.json.*; +import org.junit.jupiter.api.Assertions; +import org.redkale.convert.json.JsonConvert; +import org.redkale.persistence.*; +import org.redkale.persistence.VirtualEntity; import org.redkale.source.*; +import org.redkale.util.Sheet; /** * @@ -71,6 +62,8 @@ public class TestSourceCache { flipper.setSort("userid DESC, createtime DESC"); final FilterNode node = FilterNode.create("userid", FilterExpress.GREATERTHAN, 1000).and("username", FilterExpress.LIKE, "用户"); System.out.println("node = " + node); + final FilterNode node2 = FilterNode.create(TestEntity::getUserid, FilterExpress.GREATERTHAN, 1000).and("username", FilterExpress.LIKE, "用户"); + Assertions.assertEquals(node.toString(), node2.toString()); Sheet sheet = info.getCache().querySheet(null, flipper, node); System.out.println(sheet); System.out.println(info.getCache().querySheet(null, flipper, FilterNodeBean.createFilterNode(new TestEntityBean(1000, "用户"))));