From 897eb97d4662ee48778125e6fb232a8feb1efb7e Mon Sep 17 00:00:00 2001 From: redkale Date: Tue, 4 Jun 2024 11:05:38 +0800 Subject: [PATCH] =?UTF-8?q?ConvertColumnTransfer=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 3 - .../java/org/redkale/boot/Application.java | 5 ++ .../redkale/convert/ConvertColumnEntry.java | 26 ++++++- .../convert/ConvertColumnTransfer.java | 17 ++++- .../org/redkale/convert/ConvertFactory.java | 62 +++++++++++++--- .../java/org/redkale/convert/DeMember.java | 15 +--- .../java/org/redkale/convert/EnMember.java | 41 ++++++----- .../org/redkale/convert/ObjectEncoder.java | 21 ++++-- .../redkale/convert/json/JsonDynEncoder.java | 8 ++- .../test/convert/ConvertTransferTest.java | 72 +++++++++++++++++++ .../test/convert/CustMessage2Test.java | 4 +- .../redkale/test/convert/CustMessageTest.java | 5 +- .../convert/proto/PBCustMessage2Test.java | 4 +- .../test/convert/proto/PBCustMessageTest.java | 5 +- 14 files changed, 224 insertions(+), 64 deletions(-) create mode 100644 src/test/java/org/redkale/test/convert/ConvertTransferTest.java diff --git a/pom.xml b/pom.xml index c7b353794..93a0050f2 100644 --- a/pom.xml +++ b/pom.xml @@ -173,9 +173,6 @@ bc - false - false - true diff --git a/src/main/java/org/redkale/boot/Application.java b/src/main/java/org/redkale/boot/Application.java index 089e2e83e..1f200dd3d 100644 --- a/src/main/java/org/redkale/boot/Application.java +++ b/src/main/java/org/redkale/boot/Application.java @@ -29,6 +29,7 @@ import org.redkale.cluster.spi.ClusterModuleEngine; import org.redkale.cluster.spi.HttpClusterRpcClient; import org.redkale.cluster.spi.HttpLocalRpcClient; import org.redkale.convert.Convert; +import org.redkale.convert.ConvertColumnTransfer; import org.redkale.convert.bson.BsonFactory; import org.redkale.convert.json.*; import org.redkale.convert.proto.ProtobufFactory; @@ -303,6 +304,10 @@ public final class Application { "jsonconvert", Convert.class, JsonFactory.root().getConvert()); this.resourceFactory.register( "protobufconvert", Convert.class, ProtobufFactory.root().getConvert()); + Consumer transferConsumer = resourceFactory::inject; + BsonFactory.root().registerTransferConsumer(transferConsumer); + JsonFactory.root().registerTransferConsumer(transferConsumer); + ProtobufFactory.root().registerTransferConsumer(transferConsumer); // 系统内部模块组件 moduleEngines.add(this.sourceModule); // 放第一,很多module依赖于source diff --git a/src/main/java/org/redkale/convert/ConvertColumnEntry.java b/src/main/java/org/redkale/convert/ConvertColumnEntry.java index 25d3dcd37..e73666868 100644 --- a/src/main/java/org/redkale/convert/ConvertColumnEntry.java +++ b/src/main/java/org/redkale/convert/ConvertColumnEntry.java @@ -22,14 +22,17 @@ public final class ConvertColumnEntry { private ConvertType convertType; + private ConvertColumnTransfer transfer; + public ConvertColumnEntry() {} - public ConvertColumnEntry(ConvertColumn column) { + public ConvertColumnEntry(ConvertColumn column, ConvertColumnTransfer transfer) { if (column == null) return; this.name = column.name(); this.index = column.index(); this.ignore = column.ignore(); this.convertType = column.type(); + this.transfer = transfer; } public ConvertColumnEntry(String name) { @@ -55,6 +58,19 @@ public final class ConvertColumnEntry { this.convertType = convertType; } + public ConvertColumnEntry( + String name, int index, boolean ignore, ConvertType convertType, ConvertColumnTransfer transfer) { + this.name = name; + this.index = index; + this.ignore = ignore; + this.convertType = convertType; + this.transfer = transfer; + } + + public ConvertColumnTransfer transfer() { + return transfer; + } + public String name() { return name == null ? "" : name; } @@ -89,7 +105,11 @@ public final class ConvertColumnEntry { @Override public String toString() { - return "ConvertColumnEntry{" + "index=" + index + ", name=" + name + ", ignore=" + ignore + ", convertType=" - + convertType + '}'; + return "ConvertColumnEntry{" + + "index=" + index + + ", name=" + name + + ", ignore=" + ignore + + ", convertType=" + convertType + + '}'; } } diff --git a/src/main/java/org/redkale/convert/ConvertColumnTransfer.java b/src/main/java/org/redkale/convert/ConvertColumnTransfer.java index 7b7d70da5..1711cb1bf 100644 --- a/src/main/java/org/redkale/convert/ConvertColumnTransfer.java +++ b/src/main/java/org/redkale/convert/ConvertColumnTransfer.java @@ -7,10 +7,25 @@ package org.redkale.convert; import org.redkale.util.Attribute; /** + * 字段值转换器,常见于脱敏操作 + * + *

详情见: https://redkale.org * * @author zhangjx + * @since 2.8.0 + * * @param 字段类型 */ public interface ConvertColumnTransfer { - public A transfer(Object obj, Attribute attribute, F value); + + /** + * 字段值转换 + * + * @param obj 父对象 + * @param attribute 属性对象 + * @param value 字段值 + * + * @return Object + */ + public Object transfer(Object obj, Attribute attribute, F value); } diff --git a/src/main/java/org/redkale/convert/ConvertFactory.java b/src/main/java/org/redkale/convert/ConvertFactory.java index ec8707226..ee42e2ff8 100644 --- a/src/main/java/org/redkale/convert/ConvertFactory.java +++ b/src/main/java/org/redkale/convert/ConvertFactory.java @@ -15,6 +15,7 @@ import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.*; import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Consumer; import java.util.regex.Pattern; import java.util.stream.*; import org.redkale.annotation.ConstructorParameters; @@ -59,6 +60,8 @@ public abstract class ConvertFactory { private final ConcurrentHashMap columnEntrys = new ConcurrentHashMap(); + private final ConcurrentHashMap transfers = new ConcurrentHashMap(); + private final Set skipIgnores = new HashSet(); final Set ignoreMapColumns = new HashSet(); @@ -70,6 +73,8 @@ public abstract class ConvertFactory { private boolean skipAllIgnore = false; + private Consumer transferConsumer; + protected ConvertFactory(ConvertFactory parent, int features) { this.features = features; this.parent = parent; @@ -445,7 +450,24 @@ public abstract class ConvertFactory { return new ConvertColumnEntry(realName, true); } } - ConvertColumnEntry entry = new ConvertColumnEntry(ref); + ConvertColumnTransfer transfer = null; + Class transferClass = ref.tranfer(); + if (transferClass != ConvertColumnTransfer.class) { + transfer = findTransfer(transferClass); + if (transfer == null) { + try { + transfer = transferClass.getConstructor().newInstance(); + } catch (Exception e) { + throw new ConvertException(e); + } + Consumer consumer = findTransferConsumer(); + if (consumer != null) { + consumer.accept(transfer); + } + register((Class) transferClass, transfer); + } + } + ConvertColumnEntry entry = new ConvertColumnEntry(ref, transfer); if (skipAllIgnore) { entry.setIgnore(false); return entry; @@ -868,11 +890,27 @@ public abstract class ConvertFactory { return child; } + private Consumer findTransferConsumer() { + if (transferConsumer != null) { + return transferConsumer; + } + return parent == null ? null : parent.findTransferConsumer(); + } + private Class findEntityAlias(String name) { Class clazz = entitys.get(name); return parent == null ? clazz : parent.findEntityAlias(name); } + /** + * 设置ConvertColumnTransfer初始化的处理函数 + * + * @param consumer ConvertColumnTransfer处理函数 + */ + public final void registerTransferConsumer(Consumer consumer) { + this.transferConsumer = consumer; + } + /** * 使所有类的所有被声明为ConvertColumn.ignore = true 的字段或方法变为ConvertColumn.ignore = false * @@ -922,9 +960,7 @@ public abstract class ConvertFactory { ignoreMapColumnLock.lock(); try { if (ignore) { - for (String column : columns) { - ignoreMapColumns.add(column); - } + ignoreMapColumns.addAll(List.of(columns)); } else { for (String column : columns) { ignoreMapColumns.remove(column); @@ -945,9 +981,7 @@ public abstract class ConvertFactory { ignoreMapColumnLock.lock(); try { if (ignore) { - for (String column : columns) { - ignoreMapColumns.add(column); - } + ignoreMapColumns.addAll(columns); } else { for (String column : columns) { ignoreMapColumns.remove(column); @@ -1007,7 +1041,7 @@ public abstract class ConvertFactory { return field == null || register(field, entry); } - public final boolean register(final AccessibleObject field, final ConvertColumnEntry entry) { + public final boolean register(final AccessibleObject field, final ConvertColumnEntry entry) { if (field == null || entry == null) { return false; } @@ -1048,11 +1082,23 @@ public abstract class ConvertFactory { return result; } + public final ConvertColumnTransfer findTransfer(Class type) { + ConvertColumnTransfer transfer = transfers.get(type); + if (transfer != null) { + return transfer; + } + return this.parent == null ? null : this.parent.findTransfer(type); + } + // ---------------------------------------------------------------------- public final Encodeable getAnyEncoder() { return (Encodeable) anyEncoder; } + public final void register(final Class clazz, final C transfer) { + transfers.put(Objects.requireNonNull(clazz), Objects.requireNonNull(transfer)); + } + public final void register(final Type clazz, final SimpledCoder coder) { decoders.put(clazz, coder); encoders.put(clazz, coder); diff --git a/src/main/java/org/redkale/convert/DeMember.java b/src/main/java/org/redkale/convert/DeMember.java index c62608a1b..b3f428a3e 100644 --- a/src/main/java/org/redkale/convert/DeMember.java +++ b/src/main/java/org/redkale/convert/DeMember.java @@ -7,7 +7,6 @@ package org.redkale.convert; import java.lang.reflect.*; import org.redkale.annotation.Comment; -import org.redkale.persistence.Column; import org.redkale.util.Attribute; /** @@ -45,20 +44,10 @@ public final class DeMember { this.method = method; if (field != null) { Comment ct = field.getAnnotation(Comment.class); - if (ct == null) { - Column col = field.getAnnotation(Column.class); - this.comment = col == null ? "" : col.comment(); - } else { - this.comment = ct.value(); - } + this.comment = ct == null ? "" : ct.value(); } else if (method != null) { Comment ct = method.getAnnotation(Comment.class); - if (ct == null) { - Column col = method.getAnnotation(Column.class); - this.comment = col == null ? "" : col.comment(); - } else { - this.comment = ct.value(); - } + this.comment = ct == null ? "" : ct.value(); } else { this.comment = ""; } diff --git a/src/main/java/org/redkale/convert/EnMember.java b/src/main/java/org/redkale/convert/EnMember.java index 1f1303095..67eb4c63e 100644 --- a/src/main/java/org/redkale/convert/EnMember.java +++ b/src/main/java/org/redkale/convert/EnMember.java @@ -7,7 +7,6 @@ package org.redkale.convert; import java.lang.reflect.*; import org.redkale.annotation.Comment; -import org.redkale.persistence.Column; import org.redkale.util.Attribute; /** @@ -42,17 +41,25 @@ public final class EnMember { final Method method; // 对应类成员的Method也可能为null + final ConvertColumnTransfer transfer; // 一般为null + int index; int position; // 从1开始 int tag; // 主要给protobuf使用 - public EnMember(Attribute attribute, Encodeable encoder, Field field, Method method) { + public EnMember( + Attribute attribute, + Encodeable encoder, + Field field, + Method method, + ConvertColumnTransfer transfer) { this.attribute = attribute; this.encoder = encoder; this.field = field; this.method = method; + this.transfer = transfer; Class t = attribute.type(); this.string = CharSequence.class.isAssignableFrom(t); this.bool = t == Boolean.class || t == boolean.class; @@ -60,20 +67,10 @@ public final class EnMember { this.jsonFieldNameBytes = ('"' + attribute.field() + "\":").getBytes(); if (field != null) { Comment ct = field.getAnnotation(Comment.class); - if (ct == null) { - Column col = field.getAnnotation(Column.class); - this.comment = col == null ? "" : col.comment(); - } else { - this.comment = ct.value(); - } + this.comment = ct == null ? "" : ct.value(); } else if (method != null) { Comment ct = method.getAnnotation(Comment.class); - if (ct == null) { - Column col = method.getAnnotation(Column.class); - this.comment = col == null ? "" : col.comment(); - } else { - this.comment = ct.value(); - } + this.comment = ct == null ? "" : ct.value(); } else { this.comment = ""; } @@ -84,7 +81,8 @@ public final class EnMember { final ConvertFactory factory, final Class clazz, final String fieldname) { try { Field field = clazz.getDeclaredField(fieldname); - return new EnMember<>(Attribute.create(field), factory.loadEncoder(field.getGenericType()), field, null); + return new EnMember<>( + Attribute.create(field), factory.loadEncoder(field.getGenericType()), field, null, null); } catch (Exception e) { throw new ConvertException(e); } @@ -95,7 +93,7 @@ public final class EnMember { try { Field field = clazz.getDeclaredField(fieldname); return new EnMember<>( - Attribute.create(clazz, fieldname, fieldtype), factory.loadEncoder(fieldtype), field, null); + Attribute.create(clazz, fieldname, fieldtype), factory.loadEncoder(fieldtype), field, null, null); } catch (Exception e) { throw new ConvertException(e); } @@ -103,11 +101,16 @@ public final class EnMember { public static EnMember create( final Attribute attribute, final ConvertFactory factory, final Class fieldtype) { - return new EnMember<>(attribute, factory.loadEncoder(fieldtype), null, null); + return new EnMember<>(attribute, factory.loadEncoder(fieldtype), null, null, null); } - public F getFieldValue(T obj) { - return attribute.get(obj); + public Object getFieldValue(T obj) { + F val = attribute.get(obj); + if (transfer != null) { + return transfer.transfer(obj, attribute, val); + } else { + return val; + } } public final boolean accepts(String name) { diff --git a/src/main/java/org/redkale/convert/ObjectEncoder.java b/src/main/java/org/redkale/convert/ObjectEncoder.java index f93514d42..4fadcfc7a 100644 --- a/src/main/java/org/redkale/convert/ObjectEncoder.java +++ b/src/main/java/org/redkale/convert/ObjectEncoder.java @@ -106,7 +106,11 @@ public class ObjectEncoder implements Encodeable { fieldCoder = colFactory.loadEncoder(t); } EnMember member = new EnMember( - createAttribute(colFactory, type, clazz, field, null, null), fieldCoder, field, null); + createAttribute(colFactory, type, clazz, field, null, null), + fieldCoder, + field, + null, + ref == null ? null : ref.transfer()); if (ref != null) { member.index = ref.getIndex(); } @@ -189,7 +193,8 @@ public class ObjectEncoder implements Encodeable { createAttribute(colFactory, type, clazz, null, method, null), fieldCoder, maybeField, - method); + method, + ref == null ? null : ref.transfer()); if (Utility.contains(list, m -> m.attribute.field().equals(member.attribute.field()))) { continue; } @@ -214,7 +219,11 @@ public class ObjectEncoder implements Encodeable { // Type t = TypeToken.createClassType(f.getGenericType(), this.type); try { EnMember member = new EnMember( - createAttribute(factory, type, clazz, f, null, null), null, f, null); + createAttribute(factory, type, clazz, f, null, null), + null, + f, + null, + ref2 == null ? null : ref2.transfer()); if (ref2 != null) { member.index = ref2.getIndex(); } @@ -238,7 +247,11 @@ public class ObjectEncoder implements Encodeable { // this.type), this.type); try { EnMember member = new EnMember( - createAttribute(factory, type, clazz, null, getter, null), null, null, null); + createAttribute(factory, type, clazz, null, getter, null), + null, + null, + null, + ref2 == null ? null : ref2.transfer()); if (ref2 != null) { member.index = ref2.getIndex(); } diff --git a/src/main/java/org/redkale/convert/json/JsonDynEncoder.java b/src/main/java/org/redkale/convert/json/JsonDynEncoder.java index ac75bccc9..cb92a24bb 100644 --- a/src/main/java/org/redkale/convert/json/JsonDynEncoder.java +++ b/src/main/java/org/redkale/convert/json/JsonDynEncoder.java @@ -5,13 +5,12 @@ */ package org.redkale.convert.json; -import static org.redkale.asm.ClassWriter.COMPUTE_FRAMES; -import static org.redkale.asm.Opcodes.*; - import java.lang.reflect.*; import java.lang.reflect.Type; import java.util.*; import org.redkale.asm.*; +import static org.redkale.asm.ClassWriter.COMPUTE_FRAMES; +import static org.redkale.asm.Opcodes.*; import org.redkale.convert.*; import org.redkale.convert.ext.*; import org.redkale.util.*; @@ -258,6 +257,9 @@ public abstract class JsonDynEncoder implements Encodeable { if (ref != null && ref.ignore()) { continue; } + if (ref != null && ref.transfer() != null) { + return null; + } if (!(checkMemberType(factory, clazz, method.getGenericReturnType(), method.getReturnType()))) { return null; } diff --git a/src/test/java/org/redkale/test/convert/ConvertTransferTest.java b/src/test/java/org/redkale/test/convert/ConvertTransferTest.java new file mode 100644 index 000000000..8f1e80bc4 --- /dev/null +++ b/src/test/java/org/redkale/test/convert/ConvertTransferTest.java @@ -0,0 +1,72 @@ +/* + +*/ + +package org.redkale.test.convert; + +import org.junit.jupiter.api.*; +import org.redkale.convert.ConvertColumn; +import org.redkale.convert.ConvertColumnTransfer; +import org.redkale.convert.json.JsonConvert; +import org.redkale.util.Attribute; + +/** + * + * @author zhangjx + */ +public class ConvertTransferTest { + + public static void main(String[] args) throws Throwable { + ConvertTransferTest test = new ConvertTransferTest(); + test.run1(); + } + + @Test + public void run1() throws Throwable { + ParamRequest param = new ParamRequest(); + param.setName("haha"); + param.setPhone("1381234500"); + Assertions.assertEquals("{\"name\":\"haha\",\"phone\":\"138****00\"}", param.toString()); + } + + public static class ParamRequest { + + private String name; + + @ConvertColumn(tranfer = ParamTransfer.class) + private String phone; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + } + + public static class ParamTransfer implements ConvertColumnTransfer { + + @Override + public Object transfer(Object obj, Attribute attribute, String value) { + if (value == null || value.length() < 5) { + return value; + } else { + return value.substring(0, 3) + "****" + value.substring(value.length() - 2); + } + } + } +} diff --git a/src/test/java/org/redkale/test/convert/CustMessage2Test.java b/src/test/java/org/redkale/test/convert/CustMessage2Test.java index d7c8a0e93..d59d0fe0a 100644 --- a/src/test/java/org/redkale/test/convert/CustMessage2Test.java +++ b/src/test/java/org/redkale/test/convert/CustMessage2Test.java @@ -77,14 +77,14 @@ public class CustMessage2Test { protected void afterInitEnMember(ConvertFactory factory) { Function func1 = t -> eventName; Attribute attribute1 = Attribute.create(clazz, "event", String.class, func1, null); - EnMember member1 = new EnMember(attribute1, factory.loadEncoder(String.class), null, null); + EnMember member1 = new EnMember(attribute1, factory.loadEncoder(String.class), null, null, null); setIndex(member1, 1); setPosition(member1, 1); initForEachEnMember(factory, member1); Function func2 = t -> t; Attribute attribute2 = Attribute.create(clazz, "result", clazz, func2, null); - EnMember member2 = new EnMember(attribute2, valEncoder, null, null); + EnMember member2 = new EnMember(attribute2, valEncoder, null, null, null); setIndex(member2, 2); setPosition(member2, 2); initForEachEnMember(factory, member2); diff --git a/src/test/java/org/redkale/test/convert/CustMessageTest.java b/src/test/java/org/redkale/test/convert/CustMessageTest.java index cc9c93d63..161e3a0e9 100644 --- a/src/test/java/org/redkale/test/convert/CustMessageTest.java +++ b/src/test/java/org/redkale/test/convert/CustMessageTest.java @@ -2,10 +2,9 @@ */ package org.redkale.test.convert; +import java.lang.annotation.*; import static java.lang.annotation.ElementType.*; import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.*; import java.util.function.*; import org.junit.jupiter.api.*; import org.redkale.convert.*; @@ -73,7 +72,7 @@ public class CustMessageTest { protected void afterInitEnMember(ConvertFactory factory) { Function func = t -> t; Attribute attribute = Attribute.create(clazz, getMessageName(clazz), clazz, func, null); - EnMember member = new EnMember(attribute, valEncoder, null, null); + EnMember member = new EnMember(attribute, valEncoder, null, null, null); setIndex(member, 1); setPosition(member, 1); initForEachEnMember(factory, member); diff --git a/src/test/java/org/redkale/test/convert/proto/PBCustMessage2Test.java b/src/test/java/org/redkale/test/convert/proto/PBCustMessage2Test.java index 15efff1cb..4e1ebb82d 100644 --- a/src/test/java/org/redkale/test/convert/proto/PBCustMessage2Test.java +++ b/src/test/java/org/redkale/test/convert/proto/PBCustMessage2Test.java @@ -97,14 +97,14 @@ public class PBCustMessage2Test { protected void afterInitEnMember(ConvertFactory factory) { Function func1 = t -> eventName; Attribute attribute1 = Attribute.create(clazz, "event", String.class, func1, null); - EnMember member1 = new EnMember(attribute1, factory.loadEncoder(String.class), null, null); + EnMember member1 = new EnMember(attribute1, factory.loadEncoder(String.class), null, null, null); setIndex(member1, 1); setPosition(member1, 1); initForEachEnMember(factory, member1); Function func2 = t -> t; Attribute attribute2 = Attribute.create(clazz, "data", clazz, func2, null); - EnMember member2 = new EnMember(attribute2, valEncoder, null, null); + EnMember member2 = new EnMember(attribute2, valEncoder, null, null, null); setIndex(member2, 2); setPosition(member2, 2); initForEachEnMember(factory, member2); diff --git a/src/test/java/org/redkale/test/convert/proto/PBCustMessageTest.java b/src/test/java/org/redkale/test/convert/proto/PBCustMessageTest.java index 5b35a6f6b..b1dabe002 100644 --- a/src/test/java/org/redkale/test/convert/proto/PBCustMessageTest.java +++ b/src/test/java/org/redkale/test/convert/proto/PBCustMessageTest.java @@ -2,10 +2,9 @@ */ package org.redkale.test.convert.proto; +import java.lang.annotation.*; import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.*; import java.util.*; import java.util.function.*; import org.junit.jupiter.api.*; @@ -84,7 +83,7 @@ public class PBCustMessageTest { protected void afterInitEnMember(ConvertFactory factory) { Function func = t -> t; Attribute attribute = Attribute.create(clazz, getMessageName(clazz), clazz, func, null); - EnMember member = new EnMember(attribute, valEncoder, null, null); + EnMember member = new EnMember(attribute, valEncoder, null, null, null); setIndex(member, 1); setPosition(member, 1); initForEachEnMember(factory, member);