From 3e23c9143a6bff5a2f9f53885377876a6d7f745f Mon Sep 17 00:00:00 2001 From: redkale Date: Wed, 25 Sep 2024 13:58:21 +0800 Subject: [PATCH] protobuf --- .../redkale/convert/json/JsonDynEncoder.java | 66 ++- .../convert/pb/ProtobufDynEncoder.java | 456 +++++++++++++---- .../convert/pb/ProtobufMapEncoder.java | 12 +- .../redkale/convert/pb/ProtobufWriter.java | 87 +++- .../org/redkale/test/convert/pb/UserBean.java | 482 ++++++++++++++++++ .../convert/pb/UserBeanProtoDynEncoder.java | 85 +++ .../redkale/test/convert/pb/UserDynTest.java | 30 ++ .../org/redkale/test/convert/pb/UserKind.java | 15 + 8 files changed, 1071 insertions(+), 162 deletions(-) create mode 100644 src/test/java/org/redkale/test/convert/pb/UserBean.java create mode 100644 src/test/java/org/redkale/test/convert/pb/UserBeanProtoDynEncoder.java create mode 100644 src/test/java/org/redkale/test/convert/pb/UserDynTest.java create mode 100644 src/test/java/org/redkale/test/convert/pb/UserKind.java diff --git a/src/main/java/org/redkale/convert/json/JsonDynEncoder.java b/src/main/java/org/redkale/convert/json/JsonDynEncoder.java index dca9a2827..d95ed8a49 100644 --- a/src/main/java/org/redkale/convert/json/JsonDynEncoder.java +++ b/src/main/java/org/redkale/convert/json/JsonDynEncoder.java @@ -7,7 +7,6 @@ package org.redkale.convert.json; import java.lang.reflect.*; import java.util.*; -import org.redkale.asm.AnnotationVisitor; import org.redkale.asm.ClassWriter; import static org.redkale.asm.ClassWriter.COMPUTE_FRAMES; import org.redkale.asm.FieldVisitor; @@ -42,30 +41,18 @@ public abstract class JsonDynEncoder implements Encodeable { } protected static JsonDynEncoder generateDyncEncoder( - final JsonFactory factory, final Class clazz, final List members) { + final JsonFactory factory, final Class clazz, final List elements) { final ObjectEncoder selfObjEncoder = factory.createObjectEncoder(clazz); - selfObjEncoder.init(factory); - if (selfObjEncoder.getMembers().length != members.size()) { + selfObjEncoder.init(factory); // 必须执行,初始化EnMember内部信息 + if (selfObjEncoder.getMembers().length != elements.size()) { return null; // 存在ignore等定制配置 } - final String supDynName = JsonDynEncoder.class.getName().replace('.', '/'); - final String valtypeName = clazz.getName().replace('.', '/'); - final String writerName = JsonWriter.class.getName().replace('.', '/'); - final String encodeableName = Encodeable.class.getName().replace('.', '/'); - final String objEncoderName = ObjectEncoder.class.getName().replace('.', '/'); - final String typeDesc = org.redkale.asm.Type.getDescriptor(Type.class); - final String jsonfactoryDesc = org.redkale.asm.Type.getDescriptor(JsonFactory.class); - final String jsonwriterDesc = org.redkale.asm.Type.getDescriptor(JsonWriter.class); - final String writerDesc = org.redkale.asm.Type.getDescriptor(Writer.class); - final String encodeableDesc = org.redkale.asm.Type.getDescriptor(Encodeable.class); - final String objEncoderDesc = org.redkale.asm.Type.getDescriptor(ObjectEncoder.class); - final String valtypeDesc = org.redkale.asm.Type.getDescriptor(clazz); Map mixedNames0 = null; - StringBuilder memberb = new StringBuilder(); - for (AccessibleObject element : members) { + StringBuilder elementb = new StringBuilder(); + for (AccessibleObject element : elements) { final String fieldName = factory.readConvertFieldName(clazz, element); - memberb.append(fieldName).append(','); + elementb.append(fieldName).append(','); final Class fieldType = readGetSetFieldType(element); if (fieldType != String.class && !fieldType.isPrimitive()) { if (mixedNames0 == null) { @@ -78,7 +65,7 @@ public abstract class JsonDynEncoder implements Encodeable { final ClassLoader loader = Thread.currentThread().getContextClassLoader(); final String newDynName = "org/redkaledyn/json/_Dyn" + JsonDynEncoder.class.getSimpleName() + "__" + clazz.getName().replace('.', '_').replace('$', '_') + "_" + factory.getFeatures() + "_" - + Utility.md5Hex(memberb.toString()); // tiny必须要加上, 同一个类会有多个字段定制Convert + + Utility.md5Hex(elementb.toString()); // tiny必须要加上, 同一个类会有多个字段定制Convert try { Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); Class newClazz = clz == null ? loader.loadClass(newDynName.replace('/', '.')) : clz; @@ -104,12 +91,23 @@ public abstract class JsonDynEncoder implements Encodeable { } catch (Throwable ex) { // do nothing } + + final String supDynName = JsonDynEncoder.class.getName().replace('.', '/'); + final String valtypeName = clazz.getName().replace('.', '/'); + final String writerName = JsonWriter.class.getName().replace('.', '/'); + final String encodeableName = Encodeable.class.getName().replace('.', '/'); + final String objEncoderName = ObjectEncoder.class.getName().replace('.', '/'); + final String typeDesc = org.redkale.asm.Type.getDescriptor(Type.class); + final String jsonfactoryDesc = org.redkale.asm.Type.getDescriptor(JsonFactory.class); + final String jsonwriterDesc = org.redkale.asm.Type.getDescriptor(JsonWriter.class); + final String writerDesc = org.redkale.asm.Type.getDescriptor(Writer.class); + final String encodeableDesc = org.redkale.asm.Type.getDescriptor(Encodeable.class); + final String objEncoderDesc = org.redkale.asm.Type.getDescriptor(ObjectEncoder.class); + final String valtypeDesc = org.redkale.asm.Type.getDescriptor(clazz); // ------------------------------------------------------------------------------ ClassWriter cw = new ClassWriter(COMPUTE_FRAMES); FieldVisitor fv; MethodVisitor mv; - AnnotationVisitor av0; - cw.visit( V11, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, @@ -120,12 +118,12 @@ public abstract class JsonDynEncoder implements Encodeable { fv = cw.visitField(ACC_PROTECTED, "objectEncoderSelf", objEncoderDesc, null, null); fv.visitEnd(); - final int membersSize = members.size(); + final int membersSize = elements.size(); boolean onlyTwoIntFieldObjectFlag = false; // 只包含两个int字段 boolean onlyOneLatin1FieldObjectFlag = false; // 只包含一个Latin1 String字段 boolean onlyShotIntLongLatin1MoreFieldObjectFlag = true; int intFieldCount = 0; - for (AccessibleObject element : members) { + for (AccessibleObject element : elements) { final String fieldName = factory.readConvertFieldName(clazz, element); fv = cw.visitField(ACC_PROTECTED + ACC_FINAL, fieldName + "FieldBytes", "[B", null, null); fv.visitEnd(); @@ -170,7 +168,7 @@ public abstract class JsonDynEncoder implements Encodeable { mv.visitVarInsn(ALOAD, 2); mv.visitMethodInsn(INVOKESPECIAL, supDynName, "", "(" + jsonfactoryDesc + typeDesc + ")V", false); - for (AccessibleObject element : members) { + for (AccessibleObject element : elements) { final String fieldName = factory.readConvertFieldName(clazz, element); // xxxFieldBytes mv.visitVarInsn(ALOAD, 0); @@ -204,11 +202,11 @@ public abstract class JsonDynEncoder implements Encodeable { mv.visitFieldInsn(PUTFIELD, newDynName, fieldName + "FirstFieldChars", "[C"); } mv.visitInsn(RETURN); - mv.visitMaxs(1 + members.size(), 1 + members.size()); + mv.visitMaxs(1 + elements.size(), 1 + elements.size()); mv.visitEnd(); } - { + { // convertTo 方法 mv = (cw.visitMethod(ACC_PUBLIC, "convertTo", "(" + jsonwriterDesc + valtypeDesc + ")V", null, null)); // mv.setDebug(true); { // if (value == null) { out.writeObjectNull(null); return; } @@ -246,14 +244,14 @@ public abstract class JsonDynEncoder implements Encodeable { int elementIndex = -1; final boolean tiny = ConvertFactory.checkTinyFeature(factory.getFeatures()); final boolean nullable = ConvertFactory.checkNullableFeature(factory.getFeatures()); - final Class firstType = readGetSetFieldType(members.get(0)); + final Class firstType = readGetSetFieldType(elements.get(0)); final boolean mustHadComma = firstType.isPrimitive() && (firstType != boolean.class || !tiny || nullable); // byte/short/char/int/float/long/double if (onlyOneLatin1FieldObjectFlag) { // out.writeObjectByOnlyOneLatin1FieldValue(messageFirstFieldBytes, value.getMessage());elementIndex++; elementIndex++; - AccessibleObject element = members.get(elementIndex); + AccessibleObject element = elements.get(elementIndex); final String fieldName = factory.readConvertFieldName(clazz, element); final Class fieldType = readGetSetFieldType(element); @@ -287,12 +285,12 @@ public abstract class JsonDynEncoder implements Encodeable { maxLocals++; } else if (onlyTwoIntFieldObjectFlag) { elementIndex++; - AccessibleObject element1 = members.get(elementIndex); + AccessibleObject element1 = elements.get(elementIndex); final String fieldName1 = factory.readConvertFieldName(clazz, element1); final Class fieldType1 = readGetSetFieldType(element1); elementIndex++; - AccessibleObject element2 = members.get(elementIndex); + AccessibleObject element2 = elements.get(elementIndex); final String fieldName2 = factory.readConvertFieldName(clazz, element2); final Class fieldtype2 = readGetSetFieldType(element2); @@ -346,7 +344,7 @@ public abstract class JsonDynEncoder implements Encodeable { INVOKEVIRTUAL, writerName, "writeObjectByOnlyTwoIntFieldValue", "([B[CI[B[CI)V", false); } else if (onlyShotIntLongLatin1MoreFieldObjectFlag && mustHadComma) { - for (AccessibleObject element : members) { + for (AccessibleObject element : elements) { elementIndex++; final String fieldName = factory.readConvertFieldName(clazz, element); final Class fieldType = readGetSetFieldType(element); @@ -427,7 +425,7 @@ public abstract class JsonDynEncoder implements Encodeable { mv.visitInsn(ICONST_0); mv.visitVarInsn(ISTORE, 3); } - for (AccessibleObject element : members) { + for (AccessibleObject element : elements) { elementIndex++; final String fieldName = factory.readConvertFieldName(clazz, element); final Class fieldType = readGetSetFieldType(element); @@ -655,7 +653,7 @@ public abstract class JsonDynEncoder implements Encodeable { mv.visitMaxs(maxLocals, maxLocals); mv.visitEnd(); } - { + { // convertTo 虚拟方法 mv = (cw.visitMethod( ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "convertTo", diff --git a/src/main/java/org/redkale/convert/pb/ProtobufDynEncoder.java b/src/main/java/org/redkale/convert/pb/ProtobufDynEncoder.java index 5e6745cfe..833ed93cc 100644 --- a/src/main/java/org/redkale/convert/pb/ProtobufDynEncoder.java +++ b/src/main/java/org/redkale/convert/pb/ProtobufDynEncoder.java @@ -7,15 +7,38 @@ package org.redkale.convert.pb; import java.lang.reflect.AccessibleObject; import java.lang.reflect.Field; import java.lang.reflect.Method; -import java.lang.reflect.Modifier; import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.HashMap; +import java.util.Map; +import org.redkale.asm.Asms; +import org.redkale.asm.ClassWriter; +import static org.redkale.asm.ClassWriter.COMPUTE_FRAMES; +import org.redkale.asm.FieldVisitor; +import org.redkale.asm.Label; +import org.redkale.asm.MethodVisitor; +import org.redkale.asm.Opcodes; +import static org.redkale.asm.Opcodes.ACC_BRIDGE; +import static org.redkale.asm.Opcodes.ACC_FINAL; +import static org.redkale.asm.Opcodes.ACC_PROTECTED; +import static org.redkale.asm.Opcodes.ACC_PUBLIC; +import static org.redkale.asm.Opcodes.ACC_SUPER; +import static org.redkale.asm.Opcodes.ACC_SYNTHETIC; +import static org.redkale.asm.Opcodes.ALOAD; +import static org.redkale.asm.Opcodes.ASTORE; +import static org.redkale.asm.Opcodes.CHECKCAST; +import static org.redkale.asm.Opcodes.GETFIELD; +import static org.redkale.asm.Opcodes.IFNONNULL; +import static org.redkale.asm.Opcodes.INVOKESPECIAL; +import static org.redkale.asm.Opcodes.INVOKEVIRTUAL; +import static org.redkale.asm.Opcodes.POP; +import static org.redkale.asm.Opcodes.RETURN; +import static org.redkale.asm.Opcodes.V11; import org.redkale.convert.*; import org.redkale.convert.ext.*; +import org.redkale.util.AnyValue; import org.redkale.util.RedkaleClassLoader; +import org.redkale.util.RedkaleException; +import org.redkale.util.Utility; /** * 简单对象的PROTOBUF序列化操作类 @@ -26,26 +49,321 @@ import org.redkale.util.RedkaleClassLoader; * @since 2.8.0 * @param 序列化的数据类型 */ -public abstract class ProtobufDynEncoder implements Encodeable { +public abstract class ProtobufDynEncoder extends ProtobufObjectEncoder { protected final Class typeClass; - protected final ObjectEncoder objectEncoder; + protected final ObjectEncoder objectEncoderSelf; - protected ProtobufDynEncoder(final ProtobufFactory factory, Type type) { + // 动态字段: protected SimpledCoder xxxSimpledCoder; + + // 动态字段: protected EnMember xxxEnMember; + + protected ProtobufDynEncoder(final ProtobufFactory factory, Type type, ObjectEncoder objectEncoderSelf) { + super((Class) type); this.typeClass = (Class) type; + this.factory = factory; + this.objectEncoderSelf = objectEncoderSelf; + this.members = objectEncoderSelf.getMembers(); + this.inited = true; factory.register(type, this); - this.objectEncoder = factory.createObjectEncoder(type); } - protected static ProtobufDynEncoder generateDyncEncoder( - final ProtobufFactory factory, final Class clazz, final List members) { + @Override + public abstract void convertTo(ProtobufWriter out, T value); + + protected static ProtobufDynEncoder generateDyncEncoder(final ProtobufFactory factory, final Class clazz) { final ObjectEncoder selfObjEncoder = factory.createObjectEncoder(clazz); - selfObjEncoder.init(factory); - if (selfObjEncoder.getMembers().length != members.size()) { - return null; // 存在ignore等定制配置 + selfObjEncoder.init(factory); // 必须执行,初始化EnMember内部信息 + + final Map simpledCoders = new HashMap<>(); + final Map otherMembers = new HashMap<>(); + StringBuilder elementb = new StringBuilder(); + for (EnMember member : selfObjEncoder.getMembers()) { + final String fieldName = member.getAttribute().field(); + final Class fieldClass = member.getAttribute().type(); + final Type fieldType = member.getAttribute().genericType(); + elementb.append(fieldName).append(','); + if (!ProtobufWriter.isSimpleType(fieldClass) + && !fieldClass.isEnum() + && !ProtobufWriter.supportSimpleCollectionType(fieldType)) { + if ((member.getEncoder() instanceof SimpledCoder)) { + simpledCoders.put(fieldName, (SimpledCoder) member.getEncoder()); + } else { + otherMembers.put(fieldName, member); + } + } + } + + final ClassLoader loader = Thread.currentThread().getContextClassLoader(); + final String newDynName = "org/redkaledyn/pb/_Dyn" + ProtobufDynEncoder.class.getSimpleName() + "__" + + clazz.getName().replace('.', '_').replace('$', '_') + "_" + factory.getFeatures() + "_" + + Utility.md5Hex(elementb.toString()); // tiny必须要加上, 同一个类会有多个字段定制Convert + try { + Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); + Class newClazz = clz == null ? loader.loadClass(newDynName.replace('/', '.')) : clz; + ProtobufDynEncoder resultEncoder = + (ProtobufDynEncoder) newClazz.getConstructor(ProtobufFactory.class, Type.class, ObjectEncoder.class) + .newInstance(factory, clazz, selfObjEncoder); + if (!simpledCoders.isEmpty()) { + for (Map.Entry en : simpledCoders.entrySet()) { + Field f = newClazz.getDeclaredField(en.getKey() + "SimpledCoder"); + f.setAccessible(true); + f.set(resultEncoder, en.getValue()); + } + } + if (!otherMembers.isEmpty()) { + for (Map.Entry en : otherMembers.entrySet()) { + Field f = newClazz.getDeclaredField(en.getKey() + "EnMember"); + f.setAccessible(true); + f.set(resultEncoder, en.getValue()); + } + } + return resultEncoder; + } catch (Throwable ex) { + // do nothing + } + + final String supDynName = ProtobufDynEncoder.class.getName().replace('.', '/'); + final String valtypeName = clazz.getName().replace('.', '/'); + final String pbwriterName = ProtobufWriter.class.getName().replace('.', '/'); + final String typeDesc = org.redkale.asm.Type.getDescriptor(Type.class); + final String pbfactoryDesc = org.redkale.asm.Type.getDescriptor(ProtobufFactory.class); + final String pbwriterDesc = org.redkale.asm.Type.getDescriptor(ProtobufWriter.class); + final String simpledCoderDesc = org.redkale.asm.Type.getDescriptor(SimpledCoder.class); + final String enMemberDesc = org.redkale.asm.Type.getDescriptor(EnMember.class); + final String objEncoderDesc = org.redkale.asm.Type.getDescriptor(ObjectEncoder.class); + final String objectDesc = org.redkale.asm.Type.getDescriptor(Object.class); + final String valtypeDesc = org.redkale.asm.Type.getDescriptor(clazz); + // ------------------------------------------------------------------------------ + ClassWriter cw = new ClassWriter(COMPUTE_FRAMES); + FieldVisitor fv; + MethodVisitor mv; + cw.visit( + V11, + ACC_PUBLIC + ACC_FINAL + ACC_SUPER, + newDynName, + "L" + supDynName + "<" + valtypeDesc + ">;", + supDynName, + null); + if (!simpledCoders.isEmpty()) { + for (String key : simpledCoders.keySet()) { + fv = cw.visitField(ACC_PROTECTED, key + "SimpledCoder", simpledCoderDesc, null, null); + fv.visitEnd(); + } + } + if (!otherMembers.isEmpty()) { + for (String key : otherMembers.keySet()) { + fv = cw.visitField(ACC_PROTECTED, key + "EnMember", enMemberDesc, null, null); + fv.visitEnd(); + } + } + { // 构造函数 + mv = (cw.visitMethod( + ACC_PUBLIC, "", "(" + pbfactoryDesc + typeDesc + objEncoderDesc + ")V", null, null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 2); + mv.visitVarInsn(ALOAD, 3); + mv.visitMethodInsn( + INVOKESPECIAL, supDynName, "", "(" + pbfactoryDesc + typeDesc + objEncoderDesc + ")V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(4, 4); + mv.visitEnd(); + } + { // convertTo 方法 + mv = (cw.visitMethod(ACC_PUBLIC, "convertTo", "(" + pbwriterDesc + valtypeDesc + ")V", null, null)); + // if (value == null) return; + mv.visitVarInsn(ALOAD, 2); // value + Label ifLabel = new Label(); + mv.visitJumpInsn(IFNONNULL, ifLabel); + mv.visitInsn(RETURN); + mv.visitLabel(ifLabel); + mv.visitLineNumber(33, ifLabel); + mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); + // ProtobufWriter out = objectWriter(out0, value); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 2); + mv.visitMethodInsn( + INVOKEVIRTUAL, + newDynName, + "objectWriter", + "(" + pbwriterDesc + objectDesc + ")" + pbwriterDesc, + false); + mv.visitVarInsn(ASTORE, 3); + + mv.visitVarInsn(ALOAD, 3); + mv.visitVarInsn(ALOAD, 2); + mv.visitMethodInsn(INVOKEVIRTUAL, pbwriterName, "writeObjectB", "(Ljava/lang/Object;)I", false); + mv.visitInsn(POP); + + for (EnMember member : selfObjEncoder.getMembers()) { + final String fieldName = member.getAttribute().field(); + final Type fieldType = member.getAttribute().genericType(); + final Class fieldClass = member.getAttribute().type(); + if (ProtobufWriter.isSimpleType(fieldClass)) { + mv.visitVarInsn(ALOAD, 3); // out + Asms.visitInsn(mv, member.getTag()); // tag + mv.visitVarInsn(ALOAD, 2); // value + if (member.getMethod() != null) { + String mname = member.getMethod().getName(); + String mdesc = org.redkale.asm.Type.getMethodDescriptor(member.getMethod()); + mv.visitMethodInsn(INVOKEVIRTUAL, valtypeName, mname, mdesc, false); + } else { // field + Field field = member.getField(); + String fname = field.getName(); + String fdesc = org.redkale.asm.Type.getDescriptor(field.getType()); + mv.visitFieldInsn(GETFIELD, valtypeName, fname, fdesc); + } + String fieldDesc = org.redkale.asm.Type.getDescriptor(fieldClass); + mv.visitMethodInsn(INVOKEVIRTUAL, pbwriterName, "writeFieldValue", "(I" + fieldDesc + ")V", false); + } else if (fieldClass.isEnum()) { + mv.visitVarInsn(ALOAD, 3); // out + Asms.visitInsn(mv, member.getTag()); // tag + mv.visitVarInsn(ALOAD, 2); // value + if (member.getMethod() != null) { + String mname = member.getMethod().getName(); + String mdesc = org.redkale.asm.Type.getMethodDescriptor(member.getMethod()); + mv.visitMethodInsn(INVOKEVIRTUAL, valtypeName, mname, mdesc, false); + } else { // field + Field field = member.getField(); + String fname = field.getName(); + String fdesc = org.redkale.asm.Type.getDescriptor(field.getType()); + mv.visitFieldInsn(GETFIELD, valtypeName, fname, fdesc); + } + mv.visitMethodInsn(INVOKEVIRTUAL, pbwriterName, "writeFieldValue", "(ILjava/lang/Enum;)V", false); + } else if (ProtobufWriter.supportSimpleCollectionType(fieldType)) { + mv.visitVarInsn(ALOAD, 3); // out + Asms.visitInsn(mv, member.getTag()); // tag + mv.visitVarInsn(ALOAD, 2); // value + if (member.getMethod() != null) { + String mname = member.getMethod().getName(); + String mdesc = org.redkale.asm.Type.getMethodDescriptor(member.getMethod()); + mv.visitMethodInsn(INVOKEVIRTUAL, valtypeName, mname, mdesc, false); + } else { // field + Field field = member.getField(); + String fname = field.getName(); + String fdesc = org.redkale.asm.Type.getDescriptor(field.getType()); + mv.visitFieldInsn(GETFIELD, valtypeName, fname, fdesc); + } + Class componentType = ProtobufWriter.getSimpleCollectionComponentType(fieldType); + String wmethodName = null; + if (componentType == Boolean.class) { + wmethodName = "writeFieldBoolsValue"; + } else if (componentType == Byte.class) { + wmethodName = "writeFieldBytesValue"; + } else if (componentType == Character.class) { + wmethodName = "writeFieldCharsValue"; + } else if (componentType == Short.class) { + wmethodName = "writeFieldShortsValue"; + } else if (componentType == Integer.class) { + wmethodName = "writeFieldIntsValue"; + } else if (componentType == Float.class) { + wmethodName = "writeFieldFloatsValue"; + } else if (componentType == Long.class) { + wmethodName = "writeFieldLongsValue"; + } else if (componentType == Double.class) { + wmethodName = "writeFieldDoublesValue"; + } else if (componentType == String.class) { + wmethodName = "writeFieldStringValue"; + } + mv.visitMethodInsn(INVOKEVIRTUAL, pbwriterName, wmethodName, "(ILjava/util/Collection;)V", false); + } else if (simpledCoders.containsKey(fieldName)) { + mv.visitVarInsn(ALOAD, 3); // out + Asms.visitInsn(mv, member.getTag()); // tag + mv.visitVarInsn(ALOAD, 0); // this + mv.visitFieldInsn(GETFIELD, newDynName, fieldName + "SimpledCoder", simpledCoderDesc); + mv.visitVarInsn(ALOAD, 2); // value + if (member.getMethod() != null) { + String mname = member.getMethod().getName(); + String mdesc = org.redkale.asm.Type.getMethodDescriptor(member.getMethod()); + mv.visitMethodInsn(INVOKEVIRTUAL, valtypeName, mname, mdesc, false); + } else { // field + Field field = member.getField(); + String fname = field.getName(); + String fdesc = org.redkale.asm.Type.getDescriptor(field.getType()); + mv.visitFieldInsn(GETFIELD, valtypeName, fname, fdesc); + } + mv.visitMethodInsn( + INVOKEVIRTUAL, + pbwriterName, + "writeFieldValue", + "(I" + simpledCoderDesc + objectDesc + ")V", + false); + } else { + mv.visitVarInsn(ALOAD, 3); // out + mv.visitVarInsn(ALOAD, 0); // this + mv.visitFieldInsn(GETFIELD, newDynName, fieldName + "EnMember", enMemberDesc); + mv.visitVarInsn(ALOAD, 2); // value + mv.visitMethodInsn( + INVOKEVIRTUAL, + pbwriterName, + "writeObjectField", + "(" + enMemberDesc + objectDesc + ")V", + false); + } + } + + mv.visitVarInsn(ALOAD, 3); // out + mv.visitVarInsn(ALOAD, 2); // value + mv.visitMethodInsn(INVOKEVIRTUAL, pbwriterName, "writeObjectE", "(Ljava/lang/Object;)V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(4, 3); + mv.visitEnd(); + } + { // convertTo 虚拟方法 + mv = (cw.visitMethod( + ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, + "convertTo", + "(" + pbwriterDesc + "Ljava/lang/Object;)V", + null, + null)); + // mv.setDebug(true); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 2); + mv.visitTypeInsn(CHECKCAST, valtypeName); + mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "convertTo", "(" + pbwriterDesc + valtypeDesc + ")V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(3, 3); + mv.visitEnd(); + } + cw.visitEnd(); + + byte[] bytes = cw.toByteArray(); + Class newClazz = (Class) + new ClassLoader(loader) { + public final Class loadClass(String name, byte[] b) { + return defineClass(name, b, 0, b.length); + } + }.loadClass(newDynName.replace('/', '.'), bytes); + RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz); + RedkaleClassLoader.putReflectionDeclaredConstructors(newClazz, newDynName.replace('/', '.')); + try { + ProtobufDynEncoder resultEncoder = + (ProtobufDynEncoder) newClazz.getConstructor(ProtobufFactory.class, Type.class, ObjectEncoder.class) + .newInstance(factory, clazz, selfObjEncoder); + if (!simpledCoders.isEmpty()) { + for (Map.Entry en : simpledCoders.entrySet()) { + Field f = newClazz.getDeclaredField(en.getKey() + "SimpledCoder"); + f.setAccessible(true); + f.set(resultEncoder, en.getValue()); + RedkaleClassLoader.putReflectionField(newClazz.getName(), f); + } + } + if (!otherMembers.isEmpty()) { + for (Map.Entry en : otherMembers.entrySet()) { + Field f = newClazz.getDeclaredField(en.getKey() + "EnMember"); + f.setAccessible(true); + f.set(resultEncoder, en.getValue()); + RedkaleClassLoader.putReflectionField(newClazz.getName(), f); + } + } + return resultEncoder; + } catch (Exception ex) { + throw new RedkaleException(ex); } - return null; } // 字段全部是primitive或String类型,且没有泛型的类才能动态生成ProtobufDynEncoder, 不支持的返回null @@ -53,6 +371,10 @@ public abstract class ProtobufDynEncoder implements Encodeable implements Encodeable members = null; - Set names = new HashSet<>(); - try { - ConvertColumnEntry ref; - RedkaleClassLoader.putReflectionPublicFields(clazz.getName()); - for (final Field field : clazz.getFields()) { - if (Modifier.isStatic(field.getModifiers())) { - continue; - } - if (factory.isConvertDisabled(field)) { - continue; - } - ref = factory.findRef(clazz, field); - if (ref != null && ref.ignore()) { - continue; - } - if (factory.findFieldCoder(clazz, field.getName()) != null) { - return null; - } - if (!factory.isSimpleMemberType(clazz, field.getGenericType(), field.getType())) { - return null; - } - String name = factory.readConvertFieldName(clazz, field); - if (names.contains(name)) { - continue; - } - names.add(name); - if (members == null) { - members = new ArrayList<>(); - } - members.add(field); - } - RedkaleClassLoader.putReflectionPublicMethods(clazz.getName()); - for (final Method method : clazz.getMethods()) { - if (Modifier.isStatic(method.getModifiers())) { - continue; - } - if (Modifier.isAbstract(method.getModifiers())) { - continue; - } - if (method.isSynthetic()) { - continue; - } - if (method.getName().length() < 3) { - continue; - } - if (method.getName().equals("getClass")) { - continue; - } - if (!(method.getName().startsWith("is") && method.getName().length() > 2) - && !(method.getName().startsWith("get") - && method.getName().length() > 3)) { - continue; - } - if (factory.isConvertDisabled(method)) { - continue; - } - if (method.getParameterTypes().length != 0) { - continue; - } - if (method.getReturnType() == void.class) { - continue; - } - ref = factory.findRef(clazz, method); - if (ref != null && ref.ignore()) { - continue; - } - if (ref != null && ref.fieldFunc() != null) { - return null; - } - if (!factory.isSimpleMemberType(clazz, method.getGenericReturnType(), method.getReturnType())) { - return null; - } - String name = factory.readConvertFieldName(clazz, method); - if (names.contains(name)) { - continue; - } - if (factory.findFieldCoder(clazz, name) != null) { - return null; - } - names.add(name); - if (members == null) { - members = new ArrayList<>(); - } - members.add(method); - } - if (members == null) { - return null; - } - factory.sortFieldIndex(clazz, members); - return generateDyncEncoder(factory, clazz, members); - } catch (Exception ex) { - ex.printStackTrace(); - return null; + protected static Class readGetSetFieldType(AccessibleObject element) { + if (element instanceof Field) { + return ((Field) element).getType(); } + return ((Method) element).getReturnType(); } @Override diff --git a/src/main/java/org/redkale/convert/pb/ProtobufMapEncoder.java b/src/main/java/org/redkale/convert/pb/ProtobufMapEncoder.java index ac97d14b0..35470fce6 100644 --- a/src/main/java/org/redkale/convert/pb/ProtobufMapEncoder.java +++ b/src/main/java/org/redkale/convert/pb/ProtobufMapEncoder.java @@ -16,19 +16,25 @@ import org.redkale.convert.*; public class ProtobufMapEncoder extends MapEncoder { private final boolean enumtostring; + private final int keyTag; + private final int valTag; public ProtobufMapEncoder(ConvertFactory factory, Type type) { super(factory, type); this.enumtostring = ((ProtobufFactory) factory).enumtostring; + this.keyTag = 1 << 3 | ProtobufFactory.wireType(keyEncoder.getType(), enumtostring); + this.valTag = 2 << 3 | ProtobufFactory.wireType(valueEncoder.getType(), enumtostring); } @Override protected void writeMemberValue(ProtobufWriter out, EnMember member, K key, V value, boolean first) { ProtobufWriter tmp = new ProtobufWriter().configFieldFunc(out); - if (member != null) out.writeFieldName(member); - tmp.writeUInt32(1 << 3 | ProtobufFactory.wireType(keyEncoder.getType(), enumtostring)); + if (member != null) { + out.writeFieldName(member); + } + tmp.writeTag(keyTag); keyEncoder.convertTo(tmp, key); - tmp.writeUInt32(2 << 3 | ProtobufFactory.wireType(valueEncoder.getType(), enumtostring)); + tmp.writeTag(valTag); valueEncoder.convertTo(tmp, value); out.writeLength(tmp.count()); out.writeTo(tmp.toArray()); diff --git a/src/main/java/org/redkale/convert/pb/ProtobufWriter.java b/src/main/java/org/redkale/convert/pb/ProtobufWriter.java index 72625ba02..8393366c6 100644 --- a/src/main/java/org/redkale/convert/pb/ProtobufWriter.java +++ b/src/main/java/org/redkale/convert/pb/ProtobufWriter.java @@ -5,6 +5,7 @@ */ package org.redkale.convert.pb; +import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.nio.ByteBuffer; import java.util.*; @@ -1056,7 +1057,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { } @ClassDepends - public void writeFieldBoolsValue(int tag, Boolean[] value) { + public void writeFieldValue(int tag, Boolean[] value) { if (value != null && value.length > 0) { writeTag(tag); writeBools(value); @@ -1065,7 +1066,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { } @ClassDepends - public void writeFieldBytesValue(int tag, Byte[] value) { + public void writeFieldValue(int tag, Byte[] value) { if (value != null && value.length > 0) { writeTag(tag); writeBytes(value); @@ -1074,7 +1075,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { } @ClassDepends - public void writeFieldCharsValue(int tag, Character[] value) { + public void writeFieldValue(int tag, Character[] value) { if (value != null && value.length > 0) { writeTag(tag); writeChars(value); @@ -1083,7 +1084,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { } @ClassDepends - public void writeFieldShortsValue(int tag, Short[] value) { + public void writeFieldValue(int tag, Short[] value) { if (value != null && value.length > 0) { writeTag(tag); writeShorts(value); @@ -1092,7 +1093,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { } @ClassDepends - public void writeFieldIntsValue(int tag, Integer[] value) { + public void writeFieldValue(int tag, Integer[] value) { if (value != null && value.length > 0) { writeTag(tag); writeInts(value); @@ -1101,7 +1102,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { } @ClassDepends - public void writeFieldFloatsValue(int tag, Float[] value) { + public void writeFieldValue(int tag, Float[] value) { if (value != null && value.length > 0) { writeTag(tag); writeFloats(value); @@ -1110,7 +1111,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { } @ClassDepends - public void writeFieldLongsValue(int tag, Long[] value) { + public void writeFieldValue(int tag, Long[] value) { if (value != null && value.length > 0) { writeTag(tag); writeLongs(value); @@ -1119,7 +1120,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { } @ClassDepends - public void writeFieldDoublesValue(int tag, Double[] value) { + public void writeFieldValue(int tag, Double[] value) { if (value != null && value.length > 0) { writeTag(tag); writeDoubles(value); @@ -1128,9 +1129,8 @@ public class ProtobufWriter extends Writer implements ByteTuple { } @ClassDepends - public void writeFieldStringsValue(int tag, String[] value) { + public void writeFieldValue(int tag, String[] value) { if (value != null && value.length > 0) { - writeTag(tag); writeStrings(tag, value); this.comma = true; } @@ -1211,7 +1211,6 @@ public class ProtobufWriter extends Writer implements ByteTuple { @ClassDepends public void writeFieldStringsValue(int tag, Collection value) { if (value != null && !value.isEmpty()) { - writeTag(tag); writeStrings(tag, value); this.comma = true; } @@ -1233,7 +1232,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (enumtostring) { writeString(value.name()); } else { - writeInt(value.ordinal()); + writeUInt32(value.ordinal()); } this.comma = true; } @@ -1494,6 +1493,70 @@ public class ProtobufWriter extends Writer implements ByteTuple { }; } + public static boolean isSimpleType(Class fieldClass) { + return fieldClass.isPrimitive() + || fieldClass == Boolean.class + || fieldClass == Byte.class + || fieldClass == Character.class + || fieldClass == Short.class + || fieldClass == Integer.class + || fieldClass == Float.class + || fieldClass == Long.class + || fieldClass == Double.class + || fieldClass == String.class + || fieldClass == boolean[].class + || fieldClass == byte[].class + || fieldClass == char[].class + || fieldClass == short[].class + || fieldClass == int[].class + || fieldClass == float[].class + || fieldClass == long[].class + || fieldClass == double[].class + || fieldClass == Boolean[].class + || fieldClass == Byte[].class + || fieldClass == Character[].class + || fieldClass == Short[].class + || fieldClass == Integer[].class + || fieldClass == Float[].class + || fieldClass == Long[].class + || fieldClass == Double[].class + || fieldClass == String[].class; + } + + public static boolean supportSimpleCollectionType(Type type) { + if (!(type instanceof ParameterizedType)) { + return false; + } + ParameterizedType ptype = (ParameterizedType) type; + if (!(ptype.getRawType() instanceof Class)) { + return false; + } + Type[] ptargs = ptype.getActualTypeArguments(); + if (ptargs == null || ptargs.length != 1) { + return false; + } + Class ownerType = (Class) ptype.getRawType(); + if (!Collection.class.isAssignableFrom(ownerType)) { + return false; + } + Type componentType = ptargs[0]; + return componentType == Boolean.class + || componentType == Byte.class + || componentType == Character.class + || componentType == Short.class + || componentType == Integer.class + || componentType == Float.class + || componentType == Long.class + || componentType == Double.class + || componentType == String.class; + } + + public static Class getSimpleCollectionComponentType(Type type) { + return supportSimpleCollectionType(type) + ? (Class) ((ParameterizedType) type).getActualTypeArguments()[0] + : null; + } + /** see com.google.protobuf.CodedOutputStream **/ protected static int computeInt32SizeNoTag(final int value) { if (value == 0) { diff --git a/src/test/java/org/redkale/test/convert/pb/UserBean.java b/src/test/java/org/redkale/test/convert/pb/UserBean.java new file mode 100644 index 000000000..04022e71a --- /dev/null +++ b/src/test/java/org/redkale/test/convert/pb/UserBean.java @@ -0,0 +1,482 @@ +/* + * Copyright (c) 2016-2116 Redkale + * All rights reserved. + */ +package org.redkale.test.convert.pb; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.redkale.convert.ConvertColumn; +import org.redkale.convert.json.JsonConvert; +import org.redkale.persistence.Id; + +/** + * + * @author zhangjx + */ +public class UserBean { + @Id + @ConvertColumn(index = 1) + private long seqid; + + @ConvertColumn(index = 2) + private String name; + + @ConvertColumn(index = 3) + private String[] remarks; + + @ConvertColumn(index = 4) + private byte[] img; + + @ConvertColumn(index = 5) + private BigInteger number; + + @ConvertColumn(index = 6) + private BigDecimal scale; + + @ConvertColumn(index = 7) + private boolean flag; + + @ConvertColumn(index = 8) + private short status; + + @ConvertColumn(index = 9) + private int id; + + @ConvertColumn(index = 10) + private long createTime; + + @ConvertColumn(index = 11) + private float point; + + @ConvertColumn(index = 12) + private double money; + + @ConvertColumn(index = 13) + private byte bit; + + @ConvertColumn(index = 14) + private Boolean flag2; + + @ConvertColumn(index = 15) + private Short status2; + + @ConvertColumn(index = 16) + private Integer id2; + + @ConvertColumn(index = 17) + private Long createTime2; + + @ConvertColumn(index = 18) + private Float point2; + + @ConvertColumn(index = 19) + private Double money2; + + @ConvertColumn(index = 20) + private Set ids; + + @ConvertColumn(index = 21) + public int id3; + + @ConvertColumn(index = 22) + public long createTime3; + + @ConvertColumn(index = 23) + public float point3; + + @ConvertColumn(index = 24) + public double money3; + + @ConvertColumn(index = 25) + public byte bit3; + + @ConvertColumn(index = 26) + private int[] id4; + + @ConvertColumn(index = 27) + private long[] createTime4; + + @ConvertColumn(index = 28) + private float[] point4; + + @ConvertColumn(index = 29) + private double[] money4; + + @ConvertColumn(index = 30) + private byte[] bit4; + + @ConvertColumn(index = 31) + private Integer[] id5; + + @ConvertColumn(index = 32) + private Long[] createTime5; + + @ConvertColumn(index = 33) + private Float[] point5; + + @ConvertColumn(index = 34) + private Double[] money5; + + @ConvertColumn(index = 35) + private Byte[] bit5; + + @ConvertColumn(index = 36) + private List id6; + + @ConvertColumn(index = 37) + private List createTime6; + + @ConvertColumn(index = 38) + private List point6; + + @ConvertColumn(index = 39) + private List money6; + + @ConvertColumn(index = 40) + private List bit6; + + @ConvertColumn(index = 41) + private Map map; + + @ConvertColumn(index = 42) + public UserKind kind; + + public Map getMap() { + return map; + } + + public void setMap(Map map) { + this.map = map; + } + + public List getId6() { + return id6; + } + + public void setId6(List id6) { + this.id6 = id6; + } + + public List getCreateTime6() { + return createTime6; + } + + public void setCreateTime6(List createTime6) { + this.createTime6 = createTime6; + } + + public List getPoint6() { + return point6; + } + + public void setPoint6(List point6) { + this.point6 = point6; + } + + public List getMoney6() { + return money6; + } + + public void setMoney6(List money6) { + this.money6 = money6; + } + + public List getBit6() { + return bit6; + } + + public void setBit6(List bit6) { + this.bit6 = bit6; + } + + public int getId3() { + return id3; + } + + public void setId3(int id3) { + this.id3 = id3; + } + + public long getCreateTime3() { + return createTime3; + } + + public void setCreateTime3(long createTime3) { + this.createTime3 = createTime3; + } + + public float getPoint3() { + return point3; + } + + public void setPoint3(float point3) { + this.point3 = point3; + } + + public double getMoney3() { + return money3; + } + + public void setMoney3(double money3) { + this.money3 = money3; + } + + public byte getBit3() { + return bit3; + } + + public void setBit3(byte bit3) { + this.bit3 = bit3; + } + + public Integer[] getId5() { + return id5; + } + + public void setId5(Integer[] id5) { + this.id5 = id5; + } + + public Long[] getCreateTime5() { + return createTime5; + } + + public void setCreateTime5(Long[] createTime5) { + this.createTime5 = createTime5; + } + + public Float[] getPoint5() { + return point5; + } + + public void setPoint5(Float[] point5) { + this.point5 = point5; + } + + public Double[] getMoney5() { + return money5; + } + + public void setMoney5(Double[] money5) { + this.money5 = money5; + } + + public Byte[] getBit5() { + return bit5; + } + + public void setBit5(Byte[] bit5) { + this.bit5 = bit5; + } + + public int[] getId4() { + return id4; + } + + public void setId4(int[] id4) { + this.id4 = id4; + } + + public long[] getCreateTime4() { + return createTime4; + } + + public void setCreateTime4(long[] createTime4) { + this.createTime4 = createTime4; + } + + public float[] getPoint4() { + return point4; + } + + public void setPoint4(float[] point4) { + this.point4 = point4; + } + + public double[] getMoney4() { + return money4; + } + + public void setMoney4(double[] money4) { + this.money4 = money4; + } + + public byte[] getBit4() { + return bit4; + } + + public void setBit4(byte[] bit4) { + this.bit4 = bit4; + } + + public long getSeqid() { + return seqid; + } + + public void setSeqid(long seqid) { + this.seqid = seqid; + } + + public String getName() { + return name; + } + + public UserBean setName(String name) { + this.name = name; + return this; + } + + public String[] getRemarks() { + return remarks; + } + + public void setRemarks(String[] remarks) { + this.remarks = remarks; + } + + public Set getIds() { + return ids; + } + + public UserBean setIds(Set ids) { + this.ids = ids; + return this; + } + + public byte getBit() { + return bit; + } + + public void setBit(byte bit) { + this.bit = bit; + } + + public byte[] getImg() { + return img; + } + + public void setImg(byte[] img) { + this.img = img; + } + + public BigInteger getNumber() { + return number; + } + + public void setNumber(BigInteger number) { + this.number = number; + } + + public BigDecimal getScale() { + return scale; + } + + public void setScale(BigDecimal scale) { + this.scale = scale; + } + + public boolean isFlag() { + return flag; + } + + public void setFlag(boolean flag) { + this.flag = flag; + } + + public short getStatus() { + return status; + } + + public void setStatus(short status) { + this.status = status; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public long getCreateTime() { + return createTime; + } + + public void setCreateTime(long createTime) { + this.createTime = createTime; + } + + public float getPoint() { + return point; + } + + public void setPoint(float point) { + this.point = point; + } + + public double getMoney() { + return money; + } + + public void setMoney(double money) { + this.money = money; + } + + public Boolean getFlag2() { + return flag2; + } + + public void setFlag2(Boolean flag2) { + this.flag2 = flag2; + } + + public Short getStatus2() { + return status2; + } + + public void setStatus2(Short status2) { + this.status2 = status2; + } + + public Integer getId2() { + return id2; + } + + public void setId2(Integer id2) { + this.id2 = id2; + } + + public Long getCreateTime2() { + return createTime2; + } + + public void setCreateTime2(Long createTime2) { + this.createTime2 = createTime2; + } + + public Float getPoint2() { + return point2; + } + + public void setPoint2(Float point2) { + this.point2 = point2; + } + + public Double getMoney2() { + return money2; + } + + public void setMoney2(Double money2) { + this.money2 = money2; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } +} diff --git a/src/test/java/org/redkale/test/convert/pb/UserBeanProtoDynEncoder.java b/src/test/java/org/redkale/test/convert/pb/UserBeanProtoDynEncoder.java new file mode 100644 index 000000000..e6b2ba5f4 --- /dev/null +++ b/src/test/java/org/redkale/test/convert/pb/UserBeanProtoDynEncoder.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2016-2116 Redkale + * All rights reserved. + */ +package org.redkale.test.convert.pb; + +import java.lang.reflect.Type; +import org.redkale.convert.EnMember; +import org.redkale.convert.ObjectEncoder; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.pb.ProtobufDynEncoder; +import org.redkale.convert.pb.ProtobufFactory; +import org.redkale.convert.pb.ProtobufWriter; + +/** + * + * @author zhangjx + */ +public class UserBeanProtoDynEncoder extends ProtobufDynEncoder { + protected SimpledCoder numberSimpledCoder; + protected SimpledCoder scaleSimpledCoder; + protected EnMember mapEnMember; + + public UserBeanProtoDynEncoder(ProtobufFactory factory, Type type, ObjectEncoder objectEncoder) { + super(factory, type, objectEncoder); + } + + @Override + public void convertTo(ProtobufWriter out0, UserBean value) { + if (value == null) { + return; + } + ProtobufWriter out = objectWriter(out0, value); + out.writeObjectB(value); + out.writeFieldValue(1, value.getSeqid()); + out.writeFieldValue(2, value.getName()); + out.writeFieldValue(3, value.getImg()); + out.writeFieldValue(4, numberSimpledCoder, value.getNumber()); + out.writeFieldValue(5, scaleSimpledCoder, value.getScale()); + out.writeFieldValue(6, value.getBit()); + + out.writeFieldValue(7, value.isFlag()); + out.writeFieldValue(8, value.getStatus()); + out.writeFieldValue(9, value.getId()); + out.writeFieldValue(10, value.getCreateTime()); + out.writeFieldValue(11, value.getPoint()); + out.writeFieldValue(12, value.getMoney()); + + out.writeFieldValue(13, value.getFlag2()); + out.writeFieldValue(14, value.getStatus2()); + out.writeFieldValue(15, value.getId2()); + out.writeFieldValue(16, value.getCreateTime2()); + out.writeFieldValue(17, value.getPoint2()); + out.writeFieldValue(18, value.getMoney2()); + + out.writeFieldValue(19, value.id3); + out.writeFieldValue(20, value.createTime3); + out.writeFieldValue(21, value.point3); + out.writeFieldValue(22, value.money3); + out.writeFieldValue(23, value.bit3); + + out.writeFieldValue(19, value.getId4()); + out.writeFieldValue(20, value.getCreateTime4()); + out.writeFieldValue(21, value.getPoint4()); + out.writeFieldValue(22, value.getMoney4()); + out.writeFieldValue(23, value.getBit4()); + + out.writeFieldValue(19, value.getId5()); + out.writeFieldValue(20, value.getCreateTime5()); + out.writeFieldValue(21, value.getPoint5()); + out.writeFieldValue(22, value.getMoney5()); + out.writeFieldValue(23, value.getBit5()); + + out.writeFieldIntsValue(19, value.getId6()); + out.writeFieldLongsValue(20, value.getCreateTime6()); + out.writeFieldFloatsValue(21, value.getPoint6()); + out.writeFieldDoublesValue(22, value.getMoney6()); + out.writeFieldBytesValue(23, value.getBit6()); + + out.writeFieldValue(100, value.kind); + + out.writeObjectField(mapEnMember, value); + out.writeObjectE(out); + } +} diff --git a/src/test/java/org/redkale/test/convert/pb/UserDynTest.java b/src/test/java/org/redkale/test/convert/pb/UserDynTest.java new file mode 100644 index 000000000..9fbfaea19 --- /dev/null +++ b/src/test/java/org/redkale/test/convert/pb/UserDynTest.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2016-2116 Redkale + * All rights reserved. + */ +package org.redkale.test.convert.pb; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.redkale.convert.Encodeable; +import org.redkale.convert.pb.ProtobufDynEncoder; +import org.redkale.convert.pb.ProtobufFactory; + +/** + * + * @author zhangjx + */ +public class UserDynTest { + + public static void main(String[] args) throws Throwable { + UserDynTest test = new UserDynTest(); + test.run1(); + } + + @Test + public void run1() throws Exception { + ProtobufFactory factory = ProtobufFactory.root(); + Encodeable encoder = factory.loadEncoder(UserBean.class); + Assertions.assertTrue(ProtobufDynEncoder.class.isAssignableFrom(encoder.getClass())); + } +} diff --git a/src/test/java/org/redkale/test/convert/pb/UserKind.java b/src/test/java/org/redkale/test/convert/pb/UserKind.java new file mode 100644 index 000000000..7ac4bf09d --- /dev/null +++ b/src/test/java/org/redkale/test/convert/pb/UserKind.java @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2016-2116 Redkale + * All rights reserved. + */ +package org.redkale.test.convert.pb; + +/** + * + * @author zhangjx + */ +public enum UserKind { + ONE, + TWO, + THREE; +}