diff --git a/src/org/redkale/convert/ConvertFactory.java b/src/org/redkale/convert/ConvertFactory.java index 73397a929..4df7e7968 100644 --- a/src/org/redkale/convert/ConvertFactory.java +++ b/src/org/redkale/convert/ConvertFactory.java @@ -45,6 +45,8 @@ public abstract class ConvertFactory { private final ConcurrentHashMap entitys = new ConcurrentHashMap(); + private final ConcurrentHashMap>> fieldCoders = new ConcurrentHashMap(); + private final ConcurrentHashMap> decoders = new ConcurrentHashMap(); private final ConcurrentHashMap> encoders = new ConcurrentHashMap(); @@ -495,6 +497,29 @@ public abstract class ConvertFactory { encoders.put(clazz, encoder); } + //coder = null表示删除该字段的指定SimpledCoder + public final void register(final Class clazz, final String field, final SimpledCoder coder) { + if (field == null || clazz == null) return; + try { + clazz.getDeclaredField(field); + } catch (Exception e) { + throw new RuntimeException(clazz + " not found field(" + field + ")"); + } + if (coder == null) { + Map map = this.fieldCoders.get(clazz); + if (map != null) map.remove(field); + } else { + this.fieldCoders.computeIfAbsent(clazz, c -> new ConcurrentHashMap<>()).put(field, coder); + } + } + + public final SimpledCoder findFieldCoder(final Type clazz, final String field) { + if (field == null) return null; + Map> map = this.fieldCoders.get(clazz); + if (map == null) return parent == null ? null : parent.findFieldCoder(clazz, field); + return (SimpledCoder) map.get(field); + } + public final Decodeable findDecoder(final Type type) { Decodeable rs = (Decodeable) decoders.get(type); if (rs != null) return rs; diff --git a/src/org/redkale/convert/ObjectDecoder.java b/src/org/redkale/convert/ObjectDecoder.java index 13faa47f7..a09236c33 100644 --- a/src/org/redkale/convert/ObjectDecoder.java +++ b/src/org/redkale/convert/ObjectDecoder.java @@ -93,8 +93,12 @@ public class ObjectDecoder implements Decodeable { if (factory.isConvertDisabled(field)) continue; ref = factory.findRef(field); if (ref != null && ref.ignore()) continue; - Type t = TypeToken.createClassType(TypeToken.getGenericType(field.getGenericType(), this.type), this.type); - DeMember member = new DeMember(ObjectEncoder.createAttribute(factory, clazz, field, null, null), factory.loadDecoder(t)); + Decodeable fieldCoder = factory.findFieldCoder(clazz, field.getName()); + if (fieldCoder == null) { + Type t = TypeToken.createClassType(TypeToken.getGenericType(field.getGenericType(), this.type), this.type); + fieldCoder = factory.loadDecoder(t); + } + DeMember member = new DeMember(ObjectEncoder.createAttribute(factory, clazz, field, null, null), fieldCoder); if (ref != null) member.index = ref.getIndex(); list.add(member); } @@ -118,8 +122,13 @@ public class ObjectDecoder implements Decodeable { } ref = factory.findRef(method); if (ref != null && ref.ignore()) continue; - Type t = TypeToken.createClassType(TypeToken.getGenericType(method.getGenericParameterTypes()[0], this.type), this.type); - DeMember member = new DeMember(ObjectEncoder.createAttribute(factory, clazz, null, null, method), factory.loadDecoder(t)); + + Decodeable fieldCoder = factory.findFieldCoder(clazz, ConvertFactory.readGetSetFieldName(method)); + if (fieldCoder == null) { + Type t = TypeToken.createClassType(TypeToken.getGenericType(method.getGenericParameterTypes()[0], this.type), this.type); + fieldCoder = factory.loadDecoder(t); + } + DeMember member = new DeMember(ObjectEncoder.createAttribute(factory, clazz, null, null, method), fieldCoder); if (ref != null) member.index = ref.getIndex(); list.add(member); } diff --git a/src/org/redkale/convert/ObjectEncoder.java b/src/org/redkale/convert/ObjectEncoder.java index 9166afc19..19d8449f8 100644 --- a/src/org/redkale/convert/ObjectEncoder.java +++ b/src/org/redkale/convert/ObjectEncoder.java @@ -77,8 +77,12 @@ public class ObjectEncoder implements Encodeable { if (factory.isConvertDisabled(field)) continue; ref = factory.findRef(field); if (ref != null && ref.ignore()) continue; - Type t = TypeToken.createClassType(TypeToken.getGenericType(field.getGenericType(), this.type), this.type); - EnMember member = new EnMember(createAttribute(factory, clazz, field, null, null), factory.loadEncoder(t)); + Encodeable fieldCoder = factory.findFieldCoder(clazz, field.getName()); + if (fieldCoder == null) { + Type t = TypeToken.createClassType(TypeToken.getGenericType(field.getGenericType(), this.type), this.type); + fieldCoder = factory.loadEncoder(t); + } + EnMember member = new EnMember(createAttribute(factory, clazz, field, null, null), fieldCoder); if (ref != null) member.index = ref.getIndex(); list.add(member); } @@ -102,8 +106,12 @@ public class ObjectEncoder implements Encodeable { } ref = factory.findRef(method); if (ref != null && ref.ignore()) continue; - Type t = TypeToken.createClassType(TypeToken.getGenericType(method.getGenericReturnType(), this.type), this.type); - EnMember member = new EnMember(createAttribute(factory, clazz, null, method, null), factory.loadEncoder(t)); + Encodeable fieldCoder = factory.findFieldCoder(clazz, ConvertFactory.readGetSetFieldName(method)); + if (fieldCoder == null) { + Type t = TypeToken.createClassType(TypeToken.getGenericType(method.getGenericReturnType(), this.type), this.type); + fieldCoder = factory.loadEncoder(t); + } + EnMember member = new EnMember(createAttribute(factory, clazz, null, method, null), fieldCoder); if (ref != null) member.index = ref.getIndex(); list.add(member); } diff --git a/src/org/redkale/net/http/Rest.java b/src/org/redkale/net/http/Rest.java index 8d11794a4..0c07acb60 100644 --- a/src/org/redkale/net/http/Rest.java +++ b/src/org/redkale/net/http/Rest.java @@ -127,25 +127,37 @@ public final class Rest { } } - static JsonConvert createJsonConvert(RestConvert[] converts) { - if (converts == null || converts.length < 1) return JsonConvert.root(); + static JsonConvert createJsonConvert(RestConvert[] converts, RestConvertCoder[] coders) { + if ((converts == null || converts.length < 1) && (coders == null || coders.length < 1)) return JsonConvert.root(); final JsonFactory childFactory = JsonFactory.create(); List types = new ArrayList<>(); - for (RestConvert rc : converts) { - if (rc.type() == void.class || rc.type() == Void.class) { - return JsonFactory.create().skipAllIgnore(true).getConvert(); + Set reloadTypes = new HashSet<>(); + if (coders != null) { + for (RestConvertCoder rcc : coders) { + reloadTypes.add(rcc.type()); + childFactory.register(rcc.type(), rcc.field(), Creator.create(rcc.coder()).create()); } - if (types.contains(rc.type())) throw new RuntimeException("@RestConvert type(" + rc.type() + ") repeat"); - if (rc.skipIgnore()) { - childFactory.registerSkipIgnore(rc.type()); - childFactory.reloadCoder(rc.type()); - } else { - childFactory.register(rc.type(), false, rc.convertColumns()); - childFactory.register(rc.type(), true, rc.ignoreColumns()); - childFactory.reloadCoder(rc.type()); + } + if (converts != null) { + for (RestConvert rc : converts) { + if (rc.type() == void.class || rc.type() == Void.class) { + return JsonFactory.create().skipAllIgnore(true).getConvert(); + } + if (types.contains(rc.type())) throw new RuntimeException("@RestConvert type(" + rc.type() + ") repeat"); + if (rc.skipIgnore()) { + childFactory.registerSkipIgnore(rc.type()); + childFactory.reloadCoder(rc.type()); + } else { + childFactory.register(rc.type(), false, rc.convertColumns()); + childFactory.register(rc.type(), true, rc.ignoreColumns()); + childFactory.reloadCoder(rc.type()); + } + types.add(rc.type()); + childFactory.tiny(rc.tiny()); } - types.add(rc.type()); - childFactory.tiny(rc.tiny()); + } + for (Class type : reloadTypes) { + childFactory.reloadCoder(type); } return childFactory.getConvert(); } @@ -848,7 +860,7 @@ public final class Rest { final Map> asmParamMap = MethodParamClassVisitor.getMethodParamNames(new HashMap<>(), serviceType); final Map bodyTypes = new HashMap<>(); - final List restConverts = new ArrayList<>(); + final List restConverts = new ArrayList<>(); for (final MappingEntry entry : entrys) { RestUploadFile mupload = null; Class muploadType = null; @@ -858,7 +870,10 @@ public final class Rest { final Parameter[] params = method.getParameters(); final RestConvert[] rcs = method.getAnnotationsByType(RestConvert.class); - if (rcs != null && rcs.length > 0) restConverts.add(rcs); + final RestConvertCoder[] rcc = method.getAnnotationsByType(RestConvertCoder.class); + if ((rcs != null && rcs.length > 0) || (rcc != null && rcc.length > 0)) { + restConverts.add(new Object[]{rcs, rcc}); + } mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, entry.name.replace('/', '$').replace('.', '_'), "(" + reqDesc + respDesc + ")V", null, new String[]{"java/io/IOException"})); //mv.setDebug(true); @@ -1739,7 +1754,9 @@ public final class Rest { for (int i = 0; i < restConverts.size(); i++) { Field genField = newClazz.getDeclaredField(REST_JSONCONVERT_FIELD_PREFIX + (i + 1)); genField.setAccessible(true); - genField.set(obj, createJsonConvert(restConverts.get(i))); + Object[] rc = restConverts.get(i); + + genField.set(obj, createJsonConvert((RestConvert[]) rc[0], (RestConvertCoder[]) rc[1])); } Field typesfield = newClazz.getDeclaredField(REST_PARAMTYPES_FIELD_NAME); typesfield.setAccessible(true); diff --git a/src/org/redkale/net/http/RestConvertCoder.java b/src/org/redkale/net/http/RestConvertCoder.java new file mode 100644 index 000000000..87005ae1e --- /dev/null +++ b/src/org/redkale/net/http/RestConvertCoder.java @@ -0,0 +1,43 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.net.http; + +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import org.redkale.convert.*; + +/** + * 指定class某个字段的自定义序列化和反序列化策略。
+ * 只能依附在Service实现类的public方法上, 当方法的返回值以JSON输出时对指定类型的转换设定。
+ * + *

+ * 详情见: https://redkale.org + * + * @author zhangjx + */ +@Inherited +@Documented +@Target({METHOD}) +@Retention(RUNTIME) +@Repeatable(RestConvertCoder.RestConvertCoders.class) +public @interface RestConvertCoder { + + Class type(); + + String field(); + + Class coder(); + + @Inherited + @Documented + @Target({METHOD}) + @Retention(RUNTIME) + @interface RestConvertCoders { + + RestConvertCoder[] value(); + } +}