From 3ce56c08dfd7aecdebd741c558672163512e93b1 Mon Sep 17 00:00:00 2001 From: redkale Date: Wed, 25 Sep 2024 08:54:48 +0800 Subject: [PATCH] =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/redkale/convert/EnMember.java | 3 + .../redkale/convert/json/JsonDynEncoder.java | 1362 ++++++++--------- .../convert/pb/ProtobufDynEncoder.java | 34 +- .../redkale/convert/pb/ProtobufWriter.java | 256 ++-- 4 files changed, 849 insertions(+), 806 deletions(-) diff --git a/src/main/java/org/redkale/convert/EnMember.java b/src/main/java/org/redkale/convert/EnMember.java index 39edfc8f1..57220eaf8 100644 --- a/src/main/java/org/redkale/convert/EnMember.java +++ b/src/main/java/org/redkale/convert/EnMember.java @@ -8,6 +8,7 @@ package org.redkale.convert; import java.lang.reflect.*; import java.util.function.BiFunction; import org.redkale.annotation.Comment; +import org.redkale.annotation.Nullable; import org.redkale.util.Attribute; /** @@ -39,9 +40,11 @@ public final class EnMember { final byte[] jsonFieldNameBytes; // 对应类成员的Field也可能为null + @Nullable final Field field; // 对应类成员的Method也可能为null + @Nullable final Method method; // 一般为null diff --git a/src/main/java/org/redkale/convert/json/JsonDynEncoder.java b/src/main/java/org/redkale/convert/json/JsonDynEncoder.java index 3e9c9bd0f..dca9a2827 100644 --- a/src/main/java/org/redkale/convert/json/JsonDynEncoder.java +++ b/src/main/java/org/redkale/convert/json/JsonDynEncoder.java @@ -41,9 +41,674 @@ public abstract class JsonDynEncoder implements Encodeable { this.objectEncoder = factory.createObjectEncoder(type); } - @Override - public boolean specifyable() { - return false; + protected static JsonDynEncoder generateDyncEncoder( + final JsonFactory factory, final Class clazz, final List members) { + final ObjectEncoder selfObjEncoder = factory.createObjectEncoder(clazz); + selfObjEncoder.init(factory); + if (selfObjEncoder.getMembers().length != members.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) { + final String fieldName = factory.readConvertFieldName(clazz, element); + memberb.append(fieldName).append(','); + final Class fieldType = readGetSetFieldType(element); + if (fieldType != String.class && !fieldType.isPrimitive()) { + if (mixedNames0 == null) { + mixedNames0 = new HashMap<>(); + } + mixedNames0.put(fieldName, element); + } + } + final Map mixedNames = mixedNames0; + 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 + try { + Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); + Class newClazz = clz == null ? loader.loadClass(newDynName.replace('/', '.')) : clz; + JsonDynEncoder resultEncoder = + (JsonDynEncoder) newClazz.getDeclaredConstructor(JsonFactory.class, Type.class) + .newInstance(factory, clazz); + Field selfField = newClazz.getDeclaredField("objectEncoderSelf"); + selfField.setAccessible(true); + selfField.set(resultEncoder, selfObjEncoder); + if (mixedNames != null) { + for (Map.Entry en : mixedNames.entrySet()) { + Field f = newClazz.getDeclaredField(en.getKey() + "Encoder"); + f.setAccessible(true); + f.set( + resultEncoder, + factory.loadEncoder( + en.getValue() instanceof Field + ? ((Field) en.getValue()).getGenericType() + : ((Method) en.getValue()).getGenericReturnType())); + } + } + return resultEncoder; + } catch (Throwable ex) { + // do nothing + } + // ------------------------------------------------------------------------------ + ClassWriter cw = new ClassWriter(COMPUTE_FRAMES); + FieldVisitor fv; + MethodVisitor mv; + AnnotationVisitor av0; + + cw.visit( + V11, + ACC_PUBLIC + ACC_FINAL + ACC_SUPER, + newDynName, + "L" + supDynName + "<" + valtypeDesc + ">;", + supDynName, + null); + + fv = cw.visitField(ACC_PROTECTED, "objectEncoderSelf", objEncoderDesc, null, null); + fv.visitEnd(); + final int membersSize = members.size(); + boolean onlyTwoIntFieldObjectFlag = false; // 只包含两个int字段 + boolean onlyOneLatin1FieldObjectFlag = false; // 只包含一个Latin1 String字段 + boolean onlyShotIntLongLatin1MoreFieldObjectFlag = true; + int intFieldCount = 0; + for (AccessibleObject element : members) { + final String fieldName = factory.readConvertFieldName(clazz, element); + fv = cw.visitField(ACC_PROTECTED + ACC_FINAL, fieldName + "FieldBytes", "[B", null, null); + fv.visitEnd(); + fv = cw.visitField(ACC_PROTECTED + ACC_FINAL, fieldName + "CommaFieldBytes", "[B", null, null); + fv.visitEnd(); + fv = cw.visitField(ACC_PROTECTED + ACC_FINAL, fieldName + "FirstFieldBytes", "[B", null, null); + fv.visitEnd(); + fv = cw.visitField(ACC_PROTECTED + ACC_FINAL, fieldName + "FieldChars", "[C", null, null); + fv.visitEnd(); + fv = cw.visitField(ACC_PROTECTED + ACC_FINAL, fieldName + "CommaFieldChars", "[C", null, null); + fv.visitEnd(); + fv = cw.visitField(ACC_PROTECTED + ACC_FINAL, fieldName + "FirstFieldChars", "[C", null, null); + fv.visitEnd(); + final Class fieldType = readGetSetFieldType(element); + if (fieldType != String.class && !fieldType.isPrimitive()) { + fv = cw.visitField(ACC_PROTECTED, fieldName + "Encoder", encodeableDesc, null, null); + fv.visitEnd(); + } + if (fieldType == int.class) { + intFieldCount++; + } + if (fieldType == String.class && membersSize == 1 && readConvertSmallString(factory, element) != null) { + onlyOneLatin1FieldObjectFlag = true; + } else if (fieldType != short.class + && fieldType != int.class + && fieldType != long.class + && !(fieldType == String.class && readConvertSmallString(factory, element) != null)) { + onlyShotIntLongLatin1MoreFieldObjectFlag = false; + } + } + if (intFieldCount == 2 && intFieldCount == membersSize) { + onlyTwoIntFieldObjectFlag = true; + } + if (onlyShotIntLongLatin1MoreFieldObjectFlag && membersSize < 2) { + onlyShotIntLongLatin1MoreFieldObjectFlag = false; // 字段个数必须大于1 + } + { // 构造函数 + mv = (cw.visitMethod(ACC_PUBLIC, "", "(" + jsonfactoryDesc + typeDesc + ")V", null, null)); + // mv.setDebug(true); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 2); + mv.visitMethodInsn(INVOKESPECIAL, supDynName, "", "(" + jsonfactoryDesc + typeDesc + ")V", false); + + for (AccessibleObject element : members) { + final String fieldName = factory.readConvertFieldName(clazz, element); + // xxxFieldBytes + mv.visitVarInsn(ALOAD, 0); + mv.visitLdcInsn("\"" + fieldName + "\":"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "getBytes", "()[B", false); + mv.visitFieldInsn(PUTFIELD, newDynName, fieldName + "FieldBytes", "[B"); + // xxxCommaFieldBytes + mv.visitVarInsn(ALOAD, 0); + mv.visitLdcInsn(",\"" + fieldName + "\":"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "getBytes", "()[B", false); + mv.visitFieldInsn(PUTFIELD, newDynName, fieldName + "CommaFieldBytes", "[B"); + // xxxFirstFieldBytes + mv.visitVarInsn(ALOAD, 0); + mv.visitLdcInsn("{\"" + fieldName + "\":"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "getBytes", "()[B", false); + mv.visitFieldInsn(PUTFIELD, newDynName, fieldName + "FirstFieldBytes", "[B"); + // xxxFieldChars + mv.visitVarInsn(ALOAD, 0); + mv.visitLdcInsn("\"" + fieldName + "\":"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", "()[C", false); + mv.visitFieldInsn(PUTFIELD, newDynName, fieldName + "FieldChars", "[C"); + // xxxCommaFieldChars + mv.visitVarInsn(ALOAD, 0); + mv.visitLdcInsn(",\"" + fieldName + "\":"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", "()[C", false); + mv.visitFieldInsn(PUTFIELD, newDynName, fieldName + "CommaFieldChars", "[C"); + // xxxFirstFieldChars + mv.visitVarInsn(ALOAD, 0); + mv.visitLdcInsn("{\"" + fieldName + "\":"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", "()[C", false); + mv.visitFieldInsn(PUTFIELD, newDynName, fieldName + "FirstFieldChars", "[C"); + } + mv.visitInsn(RETURN); + mv.visitMaxs(1 + members.size(), 1 + members.size()); + mv.visitEnd(); + } + + { + mv = (cw.visitMethod(ACC_PUBLIC, "convertTo", "(" + jsonwriterDesc + valtypeDesc + ")V", null, null)); + // mv.setDebug(true); + { // if (value == null) { out.writeObjectNull(null); return; } + mv.visitVarInsn(ALOAD, 2); + Label valif = new Label(); + mv.visitJumpInsn(IFNONNULL, valif); + mv.visitVarInsn(ALOAD, 1); + mv.visitInsn(ACONST_NULL); + mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeObjectNull", "(Ljava/lang/Class;)V", false); + mv.visitInsn(RETURN); + mv.visitLabel(valif); + mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); + } + { // if (!out.isExtFuncEmpty()) { objectEncoder.convertTo(out, value); return; } + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "isExtFuncEmpty", "()Z", false); + Label extif = new Label(); + mv.visitJumpInsn(IFNE, extif); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, "objectEncoderSelf", objEncoderDesc); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 2); + mv.visitMethodInsn( + INVOKEVIRTUAL, + objEncoderName, + "convertTo", + "(" + org.redkale.asm.Type.getDescriptor(Writer.class) + "Ljava/lang/Object;)V", + false); + mv.visitInsn(RETURN); + mv.visitLabel(extif); + mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); + } + + int maxLocals = 4; + 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 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); + final String fieldName = factory.readConvertFieldName(clazz, element); + final Class fieldType = readGetSetFieldType(element); + + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, fieldName + "FirstFieldBytes", "[B"); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, fieldName + "FirstFieldChars", "[C"); + + mv.visitVarInsn(ALOAD, 2); // String message = value.getMessage(); 加载 value + if (element instanceof Field) { + mv.visitFieldInsn( + GETFIELD, + valtypeName, + ((Field) element).getName(), + org.redkale.asm.Type.getDescriptor(fieldType)); + } else { + mv.visitMethodInsn( + INVOKEVIRTUAL, + valtypeName, + ((Method) element).getName(), + "()" + org.redkale.asm.Type.getDescriptor(fieldType), + false); + } + mv.visitMethodInsn( + INVOKEVIRTUAL, + writerName, + "writeObjectByOnlyOneLatin1FieldValue", + "([B[CLjava/lang/String;)V", + false); + maxLocals++; + } else if (onlyTwoIntFieldObjectFlag) { + elementIndex++; + AccessibleObject element1 = members.get(elementIndex); + final String fieldName1 = factory.readConvertFieldName(clazz, element1); + final Class fieldType1 = readGetSetFieldType(element1); + + elementIndex++; + AccessibleObject element2 = members.get(elementIndex); + final String fieldName2 = factory.readConvertFieldName(clazz, element2); + final Class fieldtype2 = readGetSetFieldType(element2); + + mv.visitVarInsn(ALOAD, 1); + + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, fieldName1 + "FirstFieldBytes", "[B"); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, fieldName1 + "FirstFieldChars", "[C"); + + mv.visitVarInsn(ALOAD, 2); // String message = value.getMessage(); 加载 value + if (element1 instanceof Field) { + mv.visitFieldInsn( + GETFIELD, + valtypeName, + ((Field) element1).getName(), + org.redkale.asm.Type.getDescriptor(fieldType1)); + } else { + mv.visitMethodInsn( + INVOKEVIRTUAL, + valtypeName, + ((Method) element1).getName(), + "()" + org.redkale.asm.Type.getDescriptor(fieldType1), + false); + } + maxLocals++; + + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, fieldName2 + "CommaFieldBytes", "[B"); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, fieldName2 + "CommaFieldChars", "[C"); + + mv.visitVarInsn(ALOAD, 2); // String message = value.getMessage(); 加载 value + if (element2 instanceof Field) { + mv.visitFieldInsn( + GETFIELD, + valtypeName, + ((Field) element2).getName(), + org.redkale.asm.Type.getDescriptor(fieldtype2)); + } else { + mv.visitMethodInsn( + INVOKEVIRTUAL, + valtypeName, + ((Method) element2).getName(), + "()" + org.redkale.asm.Type.getDescriptor(fieldtype2), + false); + } + maxLocals++; + + mv.visitMethodInsn( + INVOKEVIRTUAL, writerName, "writeObjectByOnlyTwoIntFieldValue", "([B[CI[B[CI)V", false); + + } else if (onlyShotIntLongLatin1MoreFieldObjectFlag && mustHadComma) { + for (AccessibleObject element : members) { + elementIndex++; + final String fieldName = factory.readConvertFieldName(clazz, element); + final Class fieldType = readGetSetFieldType(element); + + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn( + GETFIELD, + newDynName, + fieldName + (elementIndex == 0 ? "FirstFieldBytes" : "CommaFieldBytes"), + "[B"); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn( + GETFIELD, + newDynName, + fieldName + (elementIndex == 0 ? "FirstFieldChars" : "CommaFieldChars"), + "[C"); + + mv.visitVarInsn(ALOAD, 2); // String message = value.getMessage(); 加载 value + if (element instanceof Field) { + mv.visitFieldInsn( + GETFIELD, + valtypeName, + ((Field) element).getName(), + org.redkale.asm.Type.getDescriptor(fieldType)); + } else { + mv.visitMethodInsn( + INVOKEVIRTUAL, + valtypeName, + ((Method) element).getName(), + "()" + org.redkale.asm.Type.getDescriptor(fieldType), + false); + } + if (fieldType == short.class) { + mv.visitMethodInsn( + INVOKEVIRTUAL, + writerName, + elementIndex + 1 == membersSize ? "writeLastFieldShortValue" : "writeFieldShortValue", + "([B[CS)V", + false); + } else if (fieldType == int.class) { + mv.visitMethodInsn( + INVOKEVIRTUAL, + writerName, + elementIndex + 1 == membersSize ? "writeLastFieldIntValue" : "writeFieldIntValue", + "([B[CI)V", + false); + } else if (fieldType == long.class) { + mv.visitMethodInsn( + INVOKEVIRTUAL, + writerName, + elementIndex + 1 == membersSize ? "writeLastFieldLongValue" : "writeFieldLongValue", + "([B[CJ)V", + false); + } else { + mv.visitMethodInsn( + INVOKEVIRTUAL, + writerName, + elementIndex + 1 == membersSize ? "writeLastFieldLatin1Value" : "writeFieldLatin1Value", + "([B[CLjava/lang/String;)V", + false); + } + + if (fieldType == long.class || fieldType == double.class) { + maxLocals += 2; + } else { + maxLocals++; + } + } + } else { + { // out.writeTo('{'); + mv.visitVarInsn(ALOAD, 1); + mv.visitIntInsn(BIPUSH, '{'); + mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeTo", "(B)V", false); + } + + if (!mustHadComma) { // boolean comma = false; + mv.visitInsn(ICONST_0); + mv.visitVarInsn(ISTORE, 3); + } + for (AccessibleObject element : members) { + elementIndex++; + final String fieldName = factory.readConvertFieldName(clazz, element); + final Class fieldType = readGetSetFieldType(element); + int storeid = ASTORE; + int loadid = ALOAD; + { // String message = value.getMessage(); + mv.visitVarInsn(ALOAD, 2); // 加载 value + if (element instanceof Field) { + mv.visitFieldInsn( + GETFIELD, + valtypeName, + ((Field) element).getName(), + org.redkale.asm.Type.getDescriptor(fieldType)); + } else { + mv.visitMethodInsn( + INVOKEVIRTUAL, + valtypeName, + ((Method) element).getName(), + "()" + org.redkale.asm.Type.getDescriptor(fieldType), + false); + } + if (fieldType == boolean.class) { + storeid = ISTORE; + loadid = ILOAD; + mv.visitVarInsn(storeid, maxLocals); + } else if (fieldType == byte.class) { + storeid = ISTORE; + loadid = ILOAD; + mv.visitVarInsn(storeid, maxLocals); + } else if (fieldType == short.class) { + storeid = ISTORE; + loadid = ILOAD; + mv.visitVarInsn(storeid, maxLocals); + } else if (fieldType == char.class) { + storeid = ISTORE; + loadid = ILOAD; + mv.visitVarInsn(storeid, maxLocals); + } else if (fieldType == int.class) { + storeid = ISTORE; + loadid = ILOAD; + mv.visitVarInsn(storeid, maxLocals); + } else if (fieldType == float.class) { + storeid = FSTORE; + loadid = FLOAD; + mv.visitVarInsn(storeid, maxLocals); + } else if (fieldType == long.class) { + storeid = LSTORE; + loadid = LLOAD; + mv.visitVarInsn(storeid, maxLocals); + } else if (fieldType == double.class) { + storeid = DSTORE; + loadid = DLOAD; + mv.visitVarInsn(storeid, maxLocals); + } else { + // storeid = ASTORE; + // loadid = ALOAD; + mv.visitVarInsn(storeid, maxLocals); + } + } + Label msgnotemptyif = null; + if (!fieldType.isPrimitive() && !nullable) { // if (message != null) { start + mv.visitVarInsn(loadid, maxLocals); + msgnotemptyif = new Label(); + mv.visitJumpInsn(IFNULL, msgnotemptyif); + if (tiny && fieldType == String.class) { + mv.visitVarInsn(loadid, maxLocals); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "isEmpty", "()Z", false); + mv.visitJumpInsn(IFNE, msgnotemptyif); + } + } else if (fieldType == boolean.class && tiny) { + mv.visitVarInsn(loadid, maxLocals); + msgnotemptyif = new Label(); + mv.visitJumpInsn(IFEQ, msgnotemptyif); + } + if (mustHadComma) { // 第一个字段必然会写入 + if (elementIndex == 0) { // 第一个 + // out.writeTo(messageFieldBytes); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, fieldName + "FieldBytes", "[B"); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, fieldName + "FieldChars", "[C"); + mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeField", "([B[C)V", false); + } else { + // out.writeTo(messageCommaFieldBytes); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, fieldName + "CommaFieldBytes", "[B"); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, fieldName + "CommaFieldChars", "[C"); + mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeField", "([B[C)V", false); + } + } else { // if(comma) {} else {} 代码块 + // if (comma) { start + mv.visitVarInsn(ILOAD, 3); + Label commaif = new Label(); + mv.visitJumpInsn(IFEQ, commaif); + + // out.writeTo(messageCommaFieldBytes); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, fieldName + "CommaFieldBytes", "[B"); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, fieldName + "CommaFieldChars", "[C"); + mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeField", "([B[C)V", false); + + Label commaelse = new Label(); + mv.visitJumpInsn(GOTO, commaelse); + mv.visitLabel(commaif); + if (fieldType == boolean.class) { + mv.visitFrame(Opcodes.F_APPEND, 1, new Object[] {Opcodes.INTEGER}, 0, null); + } else if (fieldType == byte.class) { + mv.visitFrame(Opcodes.F_APPEND, 1, new Object[] {Opcodes.INTEGER}, 0, null); + } else if (fieldType == short.class) { + mv.visitFrame(Opcodes.F_APPEND, 1, new Object[] {Opcodes.INTEGER}, 0, null); + } else if (fieldType == char.class) { + mv.visitFrame(Opcodes.F_APPEND, 1, new Object[] {Opcodes.INTEGER}, 0, null); + } else if (fieldType == int.class) { + mv.visitFrame(Opcodes.F_APPEND, 1, new Object[] {Opcodes.INTEGER}, 0, null); + } else if (fieldType == float.class) { + mv.visitFrame(Opcodes.F_APPEND, 1, new Object[] {Opcodes.FLOAT}, 0, null); + } else if (fieldType == long.class) { + mv.visitFrame(Opcodes.F_APPEND, 1, new Object[] {Opcodes.LONG}, 0, null); + } else if (fieldType == double.class) { + mv.visitFrame(Opcodes.F_APPEND, 1, new Object[] {Opcodes.DOUBLE}, 0, null); + } else { + mv.visitFrame( + Opcodes.F_APPEND, + 2, + new Object[] {Opcodes.INTEGER, "java/lang/String"}, + 0, + null); // } else { comma + } + // out.writeTo(messageFieldBytes); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, fieldName + "FieldBytes", "[B"); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, fieldName + "FieldChars", "[C"); + mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeField", "([B[C)V", false); + // comma = true; + mv.visitInsn(ICONST_1); + mv.visitVarInsn(ISTORE, 3); + mv.visitLabel(commaelse); + mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); // if (comma) } end + } + // out.writeString(message); + if (fieldType == boolean.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(loadid, maxLocals); + mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeBoolean", "(Z)V", false); + } else if (fieldType == byte.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(loadid, maxLocals); + mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeByte", "(B)V", false); + } else if (fieldType == short.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(loadid, maxLocals); + mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeShort", "(S)V", false); + } else if (fieldType == char.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(loadid, maxLocals); + mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeChar", "(C)V", false); + } else if (fieldType == int.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(loadid, maxLocals); + mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeInt", "(I)V", false); + } else if (fieldType == float.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(loadid, maxLocals); + mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeFloat", "(F)V", false); + } else if (fieldType == long.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(loadid, maxLocals); + mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeLong", "(J)V", false); + } else if (fieldType == double.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(loadid, maxLocals); + mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeDouble", "(D)V", false); + } else if (fieldType == String.class) { + if (readConvertSmallString(factory, element) == null) { + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(loadid, maxLocals); + mv.visitMethodInsn( + INVOKEVIRTUAL, writerName, "writeString", "(Ljava/lang/String;)V", false); + } else { + mv.visitVarInsn(ALOAD, 1); + mv.visitInsn(ICONST_1); + mv.visitVarInsn(loadid, maxLocals); + mv.visitMethodInsn( + INVOKEVIRTUAL, writerName, "writeLatin1To", "(ZLjava/lang/String;)V", false); + } + } else { // int[],Boolean[],String[] + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, fieldName + "Encoder", encodeableDesc); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(loadid, maxLocals); + mv.visitMethodInsn( + INVOKEINTERFACE, + encodeableName, + "convertTo", + "(" + writerDesc + "Ljava/lang/Object;)V", + true); + } + if (!fieldType.isPrimitive() && !nullable) { // if (message != null) } end + mv.visitLabel(msgnotemptyif); + mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); + } else if (fieldType == boolean.class && tiny) { + mv.visitLabel(msgnotemptyif); + mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); + } + if (fieldType == long.class || fieldType == double.class) { + maxLocals += 2; + } else { + maxLocals++; + } + } + { // out.writeTo('}'); + mv.visitVarInsn(ALOAD, 1); + mv.visitIntInsn(BIPUSH, '}'); + mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeTo", "(B)V", false); + } + } + mv.visitInsn(RETURN); + mv.visitMaxs(maxLocals, maxLocals); + mv.visitEnd(); + } + { + mv = (cw.visitMethod( + ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, + "convertTo", + "(" + jsonwriterDesc + "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", "(" + jsonwriterDesc + valtypeDesc + ")V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(3, 3); + mv.visitEnd(); + } + cw.visitEnd(); + // ------------------------------------------------------------------------------ + byte[] bytes = cw.toByteArray(); + Class newClazz = 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('/', '.'), JsonFactory.class, Type.class); + try { + JsonDynEncoder resultEncoder = + (JsonDynEncoder) newClazz.getDeclaredConstructor(JsonFactory.class, Type.class) + .newInstance(factory, clazz); + Field selfField = newClazz.getDeclaredField("objectEncoderSelf"); + selfField.setAccessible(true); + selfField.set(resultEncoder, selfObjEncoder); + RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), selfField); + if (mixedNames != null) { + for (Map.Entry en : mixedNames.entrySet()) { + Field f = newClazz.getDeclaredField(en.getKey() + "Encoder"); + f.setAccessible(true); + f.set( + resultEncoder, + factory.loadEncoder( + en.getValue() instanceof Field + ? ((Field) en.getValue()).getGenericType() + : ((Method) en.getValue()).getGenericReturnType())); + RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), f); + } + } + return resultEncoder; + } catch (Exception ex) { + throw new ConvertException(ex); + } } // 字段全部是primitive或String类型,且没有泛型的类才能动态生成JsonDynEncoder, 不支持的返回null @@ -232,695 +897,14 @@ public abstract class JsonDynEncoder implements Encodeable { return ((Method) element).getReturnType(); } - protected static JsonDynEncoder generateDyncEncoder( - final JsonFactory factory, final Class clazz, final List members) { - final ObjectEncoder selfObjEncoder = factory.createObjectEncoder(clazz); - selfObjEncoder.init(factory); - if (selfObjEncoder.getMembers().length != members.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) { - ConvertColumnEntry ref1 = factory.findRef(clazz, element); - final String fieldname = - ref1 == null || ref1.name().isEmpty() ? factory.readGetSetFieldName(element) : ref1.name(); - memberb.append(fieldname).append(','); - final Class fieldType = readGetSetFieldType(element); - if (fieldType != String.class && !fieldType.isPrimitive()) { - if (mixedNames0 == null) { - mixedNames0 = new HashMap<>(); - } - mixedNames0.put(fieldname, element); - } - } - final Map mixedNames = mixedNames0; - 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 - try { - Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); - Class newClazz = clz == null ? loader.loadClass(newDynName.replace('/', '.')) : clz; - JsonDynEncoder resultEncoder = - (JsonDynEncoder) newClazz.getDeclaredConstructor(JsonFactory.class, Type.class) - .newInstance(factory, clazz); - Field selfField = newClazz.getDeclaredField("objectEncoderSelf"); - selfField.setAccessible(true); - selfField.set(resultEncoder, selfObjEncoder); - if (mixedNames != null) { - for (Map.Entry en : mixedNames.entrySet()) { - Field f = newClazz.getDeclaredField(en.getKey() + "Encoder"); - f.setAccessible(true); - f.set( - resultEncoder, - factory.loadEncoder( - en.getValue() instanceof Field - ? ((Field) en.getValue()).getGenericType() - : ((Method) en.getValue()).getGenericReturnType())); - } - } - return resultEncoder; - } catch (Throwable ex) { - // do nothing - } - // ------------------------------------------------------------------------------ - ClassWriter cw = new ClassWriter(COMPUTE_FRAMES); - FieldVisitor fv; - MethodVisitor mv; - AnnotationVisitor av0; - - cw.visit( - V11, - ACC_PUBLIC + ACC_FINAL + ACC_SUPER, - newDynName, - "L" + supDynName + "<" + valtypeDesc + ">;", - supDynName, - null); - - fv = cw.visitField(ACC_PROTECTED, "objectEncoderSelf", objEncoderDesc, null, null); - fv.visitEnd(); - final int membersSize = members.size(); - boolean onlyTwoIntFieldObjectFlag = false; // 只包含两个int字段 - boolean onlyOneLatin1FieldObjectFlag = false; // 只包含一个Latin1 String字段 - boolean onlyShotIntLongLatin1MoreFieldObjectFlag = true; - int intFieldCount = 0; - for (AccessibleObject element : members) { - ConvertColumnEntry ref1 = factory.findRef(clazz, element); - final String fieldname = - ref1 == null || ref1.name().isEmpty() ? factory.readGetSetFieldName(element) : ref1.name(); - fv = cw.visitField(ACC_PROTECTED + ACC_FINAL, fieldname + "FieldBytes", "[B", null, null); - fv.visitEnd(); - fv = cw.visitField(ACC_PROTECTED + ACC_FINAL, fieldname + "CommaFieldBytes", "[B", null, null); - fv.visitEnd(); - fv = cw.visitField(ACC_PROTECTED + ACC_FINAL, fieldname + "FirstFieldBytes", "[B", null, null); - fv.visitEnd(); - fv = cw.visitField(ACC_PROTECTED + ACC_FINAL, fieldname + "FieldChars", "[C", null, null); - fv.visitEnd(); - fv = cw.visitField(ACC_PROTECTED + ACC_FINAL, fieldname + "CommaFieldChars", "[C", null, null); - fv.visitEnd(); - fv = cw.visitField(ACC_PROTECTED + ACC_FINAL, fieldname + "FirstFieldChars", "[C", null, null); - fv.visitEnd(); - final Class fieldType = readGetSetFieldType(element); - if (fieldType != String.class && !fieldType.isPrimitive()) { - fv = cw.visitField(ACC_PROTECTED, fieldname + "Encoder", encodeableDesc, null, null); - fv.visitEnd(); - } - if (fieldType == int.class) { - intFieldCount++; - } - if (fieldType == String.class && membersSize == 1 && readConvertSmallString(factory, element) != null) { - onlyOneLatin1FieldObjectFlag = true; - } else if (fieldType != short.class - && fieldType != int.class - && fieldType != long.class - && !(fieldType == String.class && readConvertSmallString(factory, element) != null)) { - onlyShotIntLongLatin1MoreFieldObjectFlag = false; - } - } - if (intFieldCount == 2 && intFieldCount == membersSize) { - onlyTwoIntFieldObjectFlag = true; - } - if (onlyShotIntLongLatin1MoreFieldObjectFlag && membersSize < 2) { - onlyShotIntLongLatin1MoreFieldObjectFlag = false; // 字段个数必须大于1 - } - { // 构造函数 - mv = (cw.visitMethod(ACC_PUBLIC, "", "(" + jsonfactoryDesc + typeDesc + ")V", null, null)); - // mv.setDebug(true); - mv.visitVarInsn(ALOAD, 0); - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(ALOAD, 2); - mv.visitMethodInsn(INVOKESPECIAL, supDynName, "", "(" + jsonfactoryDesc + typeDesc + ")V", false); - - for (AccessibleObject element : members) { - ConvertColumnEntry ref1 = factory.findRef(clazz, element); - final String fieldname = - ref1 == null || ref1.name().isEmpty() ? factory.readGetSetFieldName(element) : ref1.name(); - // xxxFieldBytes - mv.visitVarInsn(ALOAD, 0); - mv.visitLdcInsn("\"" + fieldname + "\":"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "getBytes", "()[B", false); - mv.visitFieldInsn(PUTFIELD, newDynName, fieldname + "FieldBytes", "[B"); - // xxxCommaFieldBytes - mv.visitVarInsn(ALOAD, 0); - mv.visitLdcInsn(",\"" + fieldname + "\":"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "getBytes", "()[B", false); - mv.visitFieldInsn(PUTFIELD, newDynName, fieldname + "CommaFieldBytes", "[B"); - // xxxFirstFieldBytes - mv.visitVarInsn(ALOAD, 0); - mv.visitLdcInsn("{\"" + fieldname + "\":"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "getBytes", "()[B", false); - mv.visitFieldInsn(PUTFIELD, newDynName, fieldname + "FirstFieldBytes", "[B"); - // xxxFieldChars - mv.visitVarInsn(ALOAD, 0); - mv.visitLdcInsn("\"" + fieldname + "\":"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", "()[C", false); - mv.visitFieldInsn(PUTFIELD, newDynName, fieldname + "FieldChars", "[C"); - // xxxCommaFieldChars - mv.visitVarInsn(ALOAD, 0); - mv.visitLdcInsn(",\"" + fieldname + "\":"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", "()[C", false); - mv.visitFieldInsn(PUTFIELD, newDynName, fieldname + "CommaFieldChars", "[C"); - // xxxFirstFieldChars - mv.visitVarInsn(ALOAD, 0); - mv.visitLdcInsn("{\"" + fieldname + "\":"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", "()[C", false); - mv.visitFieldInsn(PUTFIELD, newDynName, fieldname + "FirstFieldChars", "[C"); - } - mv.visitInsn(RETURN); - mv.visitMaxs(1 + members.size(), 1 + members.size()); - mv.visitEnd(); - } - - { - mv = (cw.visitMethod(ACC_PUBLIC, "convertTo", "(" + jsonwriterDesc + valtypeDesc + ")V", null, null)); - // mv.setDebug(true); - { // if (value == null) { out.writeObjectNull(null); return; } - mv.visitVarInsn(ALOAD, 2); - Label valif = new Label(); - mv.visitJumpInsn(IFNONNULL, valif); - mv.visitVarInsn(ALOAD, 1); - mv.visitInsn(ACONST_NULL); - mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeObjectNull", "(Ljava/lang/Class;)V", false); - mv.visitInsn(RETURN); - mv.visitLabel(valif); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - } - { // if (!out.isExtFuncEmpty()) { objectEncoder.convertTo(out, value); return; } - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "isExtFuncEmpty", "()Z", false); - Label extif = new Label(); - mv.visitJumpInsn(IFNE, extif); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, "objectEncoderSelf", objEncoderDesc); - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(ALOAD, 2); - mv.visitMethodInsn( - INVOKEVIRTUAL, - objEncoderName, - "convertTo", - "(" + org.redkale.asm.Type.getDescriptor(Writer.class) + "Ljava/lang/Object;)V", - false); - mv.visitInsn(RETURN); - mv.visitLabel(extif); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - } - - int maxLocals = 4; - 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 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); - ConvertColumnEntry ref1 = factory.findRef(clazz, element); - final String fieldName = - ref1 == null || ref1.name().isEmpty() ? factory.readGetSetFieldName(element) : ref1.name(); - final Class fieldtype = readGetSetFieldType(element); - - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, fieldName + "FirstFieldBytes", "[B"); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, fieldName + "FirstFieldChars", "[C"); - - mv.visitVarInsn(ALOAD, 2); // String message = value.getMessage(); 加载 value - if (element instanceof Field) { - mv.visitFieldInsn( - GETFIELD, - valtypeName, - ((Field) element).getName(), - org.redkale.asm.Type.getDescriptor(fieldtype)); - } else { - mv.visitMethodInsn( - INVOKEVIRTUAL, - valtypeName, - ((Method) element).getName(), - "()" + org.redkale.asm.Type.getDescriptor(fieldtype), - false); - } - mv.visitMethodInsn( - INVOKEVIRTUAL, - writerName, - "writeObjectByOnlyOneLatin1FieldValue", - "([B[CLjava/lang/String;)V", - false); - maxLocals++; - } else if (onlyTwoIntFieldObjectFlag) { - elementIndex++; - AccessibleObject element1 = members.get(elementIndex); - ConvertColumnEntry ref1 = factory.findRef(clazz, element1); - final String fieldName1 = - ref1 == null || ref1.name().isEmpty() ? factory.readGetSetFieldName(element1) : ref1.name(); - final Class fieldType1 = readGetSetFieldType(element1); - - elementIndex++; - AccessibleObject element2 = members.get(elementIndex); - ConvertColumnEntry ref2 = factory.findRef(clazz, element2); - final String fieldName2 = - ref2 == null || ref2.name().isEmpty() ? factory.readGetSetFieldName(element2) : ref2.name(); - final Class fieldtype2 = readGetSetFieldType(element2); - - mv.visitVarInsn(ALOAD, 1); - - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, fieldName1 + "FirstFieldBytes", "[B"); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, fieldName1 + "FirstFieldChars", "[C"); - - mv.visitVarInsn(ALOAD, 2); // String message = value.getMessage(); 加载 value - if (element1 instanceof Field) { - mv.visitFieldInsn( - GETFIELD, - valtypeName, - ((Field) element1).getName(), - org.redkale.asm.Type.getDescriptor(fieldType1)); - } else { - mv.visitMethodInsn( - INVOKEVIRTUAL, - valtypeName, - ((Method) element1).getName(), - "()" + org.redkale.asm.Type.getDescriptor(fieldType1), - false); - } - maxLocals++; - - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, fieldName2 + "CommaFieldBytes", "[B"); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, fieldName2 + "CommaFieldChars", "[C"); - - mv.visitVarInsn(ALOAD, 2); // String message = value.getMessage(); 加载 value - if (element2 instanceof Field) { - mv.visitFieldInsn( - GETFIELD, - valtypeName, - ((Field) element2).getName(), - org.redkale.asm.Type.getDescriptor(fieldtype2)); - } else { - mv.visitMethodInsn( - INVOKEVIRTUAL, - valtypeName, - ((Method) element2).getName(), - "()" + org.redkale.asm.Type.getDescriptor(fieldtype2), - false); - } - maxLocals++; - - mv.visitMethodInsn( - INVOKEVIRTUAL, writerName, "writeObjectByOnlyTwoIntFieldValue", "([B[CI[B[CI)V", false); - - } else if (onlyShotIntLongLatin1MoreFieldObjectFlag && mustHadComma) { - for (AccessibleObject element : members) { - elementIndex++; - ConvertColumnEntry ref1 = factory.findRef(clazz, element); - final String fieldname = - ref1 == null || ref1.name().isEmpty() ? factory.readGetSetFieldName(element) : ref1.name(); - final Class fieldtype = readGetSetFieldType(element); - - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn( - GETFIELD, - newDynName, - fieldname + (elementIndex == 0 ? "FirstFieldBytes" : "CommaFieldBytes"), - "[B"); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn( - GETFIELD, - newDynName, - fieldname + (elementIndex == 0 ? "FirstFieldChars" : "CommaFieldChars"), - "[C"); - - mv.visitVarInsn(ALOAD, 2); // String message = value.getMessage(); 加载 value - if (element instanceof Field) { - mv.visitFieldInsn( - GETFIELD, - valtypeName, - ((Field) element).getName(), - org.redkale.asm.Type.getDescriptor(fieldtype)); - } else { - mv.visitMethodInsn( - INVOKEVIRTUAL, - valtypeName, - ((Method) element).getName(), - "()" + org.redkale.asm.Type.getDescriptor(fieldtype), - false); - } - if (fieldtype == short.class) { - mv.visitMethodInsn( - INVOKEVIRTUAL, - writerName, - elementIndex + 1 == membersSize ? "writeLastFieldShortValue" : "writeFieldShortValue", - "([B[CS)V", - false); - } else if (fieldtype == int.class) { - mv.visitMethodInsn( - INVOKEVIRTUAL, - writerName, - elementIndex + 1 == membersSize ? "writeLastFieldIntValue" : "writeFieldIntValue", - "([B[CI)V", - false); - } else if (fieldtype == long.class) { - mv.visitMethodInsn( - INVOKEVIRTUAL, - writerName, - elementIndex + 1 == membersSize ? "writeLastFieldLongValue" : "writeFieldLongValue", - "([B[CJ)V", - false); - } else { - mv.visitMethodInsn( - INVOKEVIRTUAL, - writerName, - elementIndex + 1 == membersSize ? "writeLastFieldLatin1Value" : "writeFieldLatin1Value", - "([B[CLjava/lang/String;)V", - false); - } - - if (fieldtype == long.class || fieldtype == double.class) { - maxLocals += 2; - } else { - maxLocals++; - } - } - } else { - { // out.writeTo('{'); - mv.visitVarInsn(ALOAD, 1); - mv.visitIntInsn(BIPUSH, '{'); - mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeTo", "(B)V", false); - } - - if (!mustHadComma) { // boolean comma = false; - mv.visitInsn(ICONST_0); - mv.visitVarInsn(ISTORE, 3); - } - for (AccessibleObject element : members) { - elementIndex++; - ConvertColumnEntry ref1 = factory.findRef(clazz, element); - final String fieldname = - ref1 == null || ref1.name().isEmpty() ? factory.readGetSetFieldName(element) : ref1.name(); - final Class fieldtype = readGetSetFieldType(element); - int storeid = ASTORE; - int loadid = ALOAD; - { // String message = value.getMessage(); - mv.visitVarInsn(ALOAD, 2); // 加载 value - if (element instanceof Field) { - mv.visitFieldInsn( - GETFIELD, - valtypeName, - ((Field) element).getName(), - org.redkale.asm.Type.getDescriptor(fieldtype)); - } else { - mv.visitMethodInsn( - INVOKEVIRTUAL, - valtypeName, - ((Method) element).getName(), - "()" + org.redkale.asm.Type.getDescriptor(fieldtype), - false); - } - if (fieldtype == boolean.class) { - storeid = ISTORE; - loadid = ILOAD; - mv.visitVarInsn(storeid, maxLocals); - } else if (fieldtype == byte.class) { - storeid = ISTORE; - loadid = ILOAD; - mv.visitVarInsn(storeid, maxLocals); - } else if (fieldtype == short.class) { - storeid = ISTORE; - loadid = ILOAD; - mv.visitVarInsn(storeid, maxLocals); - } else if (fieldtype == char.class) { - storeid = ISTORE; - loadid = ILOAD; - mv.visitVarInsn(storeid, maxLocals); - } else if (fieldtype == int.class) { - storeid = ISTORE; - loadid = ILOAD; - mv.visitVarInsn(storeid, maxLocals); - } else if (fieldtype == float.class) { - storeid = FSTORE; - loadid = FLOAD; - mv.visitVarInsn(storeid, maxLocals); - } else if (fieldtype == long.class) { - storeid = LSTORE; - loadid = LLOAD; - mv.visitVarInsn(storeid, maxLocals); - } else if (fieldtype == double.class) { - storeid = DSTORE; - loadid = DLOAD; - mv.visitVarInsn(storeid, maxLocals); - } else { - // storeid = ASTORE; - // loadid = ALOAD; - mv.visitVarInsn(storeid, maxLocals); - } - } - Label msgnotemptyif = null; - if (!fieldtype.isPrimitive() && !nullable) { // if (message != null) { start - mv.visitVarInsn(loadid, maxLocals); - msgnotemptyif = new Label(); - mv.visitJumpInsn(IFNULL, msgnotemptyif); - if (tiny && fieldtype == String.class) { - mv.visitVarInsn(loadid, maxLocals); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "isEmpty", "()Z", false); - mv.visitJumpInsn(IFNE, msgnotemptyif); - } - } else if (fieldtype == boolean.class && tiny) { - mv.visitVarInsn(loadid, maxLocals); - msgnotemptyif = new Label(); - mv.visitJumpInsn(IFEQ, msgnotemptyif); - } - if (mustHadComma) { // 第一个字段必然会写入 - if (elementIndex == 0) { // 第一个 - // out.writeTo(messageFieldBytes); - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, fieldname + "FieldBytes", "[B"); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, fieldname + "FieldChars", "[C"); - mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeField", "([B[C)V", false); - } else { - // out.writeTo(messageCommaFieldBytes); - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, fieldname + "CommaFieldBytes", "[B"); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, fieldname + "CommaFieldChars", "[C"); - mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeField", "([B[C)V", false); - } - } else { // if(comma) {} else {} 代码块 - // if (comma) { start - mv.visitVarInsn(ILOAD, 3); - Label commaif = new Label(); - mv.visitJumpInsn(IFEQ, commaif); - - // out.writeTo(messageCommaFieldBytes); - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, fieldname + "CommaFieldBytes", "[B"); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, fieldname + "CommaFieldChars", "[C"); - mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeField", "([B[C)V", false); - - Label commaelse = new Label(); - mv.visitJumpInsn(GOTO, commaelse); - mv.visitLabel(commaif); - if (fieldtype == boolean.class) { - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[] {Opcodes.INTEGER}, 0, null); - } else if (fieldtype == byte.class) { - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[] {Opcodes.INTEGER}, 0, null); - } else if (fieldtype == short.class) { - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[] {Opcodes.INTEGER}, 0, null); - } else if (fieldtype == char.class) { - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[] {Opcodes.INTEGER}, 0, null); - } else if (fieldtype == int.class) { - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[] {Opcodes.INTEGER}, 0, null); - } else if (fieldtype == float.class) { - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[] {Opcodes.FLOAT}, 0, null); - } else if (fieldtype == long.class) { - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[] {Opcodes.LONG}, 0, null); - } else if (fieldtype == double.class) { - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[] {Opcodes.DOUBLE}, 0, null); - } else { - mv.visitFrame( - Opcodes.F_APPEND, - 2, - new Object[] {Opcodes.INTEGER, "java/lang/String"}, - 0, - null); // } else { comma - } - // out.writeTo(messageFieldBytes); - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, fieldname + "FieldBytes", "[B"); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, fieldname + "FieldChars", "[C"); - mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeField", "([B[C)V", false); - // comma = true; - mv.visitInsn(ICONST_1); - mv.visitVarInsn(ISTORE, 3); - mv.visitLabel(commaelse); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); // if (comma) } end - } - // out.writeString(message); - if (fieldtype == boolean.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(loadid, maxLocals); - mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeBoolean", "(Z)V", false); - } else if (fieldtype == byte.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(loadid, maxLocals); - mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeByte", "(B)V", false); - } else if (fieldtype == short.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(loadid, maxLocals); - mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeShort", "(S)V", false); - } else if (fieldtype == char.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(loadid, maxLocals); - mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeChar", "(C)V", false); - } else if (fieldtype == int.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(loadid, maxLocals); - mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeInt", "(I)V", false); - } else if (fieldtype == float.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(loadid, maxLocals); - mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeFloat", "(F)V", false); - } else if (fieldtype == long.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(loadid, maxLocals); - mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeLong", "(J)V", false); - } else if (fieldtype == double.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(loadid, maxLocals); - mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeDouble", "(D)V", false); - } else if (fieldtype == String.class) { - if (readConvertSmallString(factory, element) == null) { - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(loadid, maxLocals); - mv.visitMethodInsn( - INVOKEVIRTUAL, writerName, "writeString", "(Ljava/lang/String;)V", false); - } else { - mv.visitVarInsn(ALOAD, 1); - mv.visitInsn(ICONST_1); - mv.visitVarInsn(loadid, maxLocals); - mv.visitMethodInsn( - INVOKEVIRTUAL, writerName, "writeLatin1To", "(ZLjava/lang/String;)V", false); - } - } else { // int[],Boolean[],String[] - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, fieldname + "Encoder", encodeableDesc); - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(loadid, maxLocals); - mv.visitMethodInsn( - INVOKEINTERFACE, - encodeableName, - "convertTo", - "(" + writerDesc + "Ljava/lang/Object;)V", - true); - } - if (!fieldtype.isPrimitive() && !nullable) { // if (message != null) } end - mv.visitLabel(msgnotemptyif); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - } else if (fieldtype == boolean.class && tiny) { - mv.visitLabel(msgnotemptyif); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - } - if (fieldtype == long.class || fieldtype == double.class) { - maxLocals += 2; - } else { - maxLocals++; - } - } - { // out.writeTo('}'); - mv.visitVarInsn(ALOAD, 1); - mv.visitIntInsn(BIPUSH, '}'); - mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeTo", "(B)V", false); - } - } - mv.visitInsn(RETURN); - mv.visitMaxs(maxLocals, maxLocals); - mv.visitEnd(); - } - { - mv = (cw.visitMethod( - ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, - "convertTo", - "(" + jsonwriterDesc + "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", "(" + jsonwriterDesc + valtypeDesc + ")V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(3, 3); - mv.visitEnd(); - } - cw.visitEnd(); - // ------------------------------------------------------------------------------ - byte[] bytes = cw.toByteArray(); - Class newClazz = 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('/', '.'), JsonFactory.class, Type.class); - try { - JsonDynEncoder resultEncoder = - (JsonDynEncoder) newClazz.getDeclaredConstructor(JsonFactory.class, Type.class) - .newInstance(factory, clazz); - Field selfField = newClazz.getDeclaredField("objectEncoderSelf"); - selfField.setAccessible(true); - selfField.set(resultEncoder, selfObjEncoder); - RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), selfField); - if (mixedNames != null) { - for (Map.Entry en : mixedNames.entrySet()) { - Field f = newClazz.getDeclaredField(en.getKey() + "Encoder"); - f.setAccessible(true); - f.set( - resultEncoder, - factory.loadEncoder( - en.getValue() instanceof Field - ? ((Field) en.getValue()).getGenericType() - : ((Method) en.getValue()).getGenericReturnType())); - RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), f); - } - } - return resultEncoder; - } catch (Exception ex) { - throw new ConvertException(ex); - } - } - @Override public abstract void convertTo(JsonWriter out, T value); + @Override + public boolean specifyable() { + return false; + } + @Override public Type getType() { return typeClass; diff --git a/src/main/java/org/redkale/convert/pb/ProtobufDynEncoder.java b/src/main/java/org/redkale/convert/pb/ProtobufDynEncoder.java index 068781d19..5e6745cfe 100644 --- a/src/main/java/org/redkale/convert/pb/ProtobufDynEncoder.java +++ b/src/main/java/org/redkale/convert/pb/ProtobufDynEncoder.java @@ -28,17 +28,24 @@ import org.redkale.util.RedkaleClassLoader; */ public abstract class ProtobufDynEncoder implements Encodeable { - protected Type type; + protected final Class typeClass; - protected ProtobufDynEncoder(Class clazz) { - this.type = clazz; + protected final ObjectEncoder objectEncoder; + + protected ProtobufDynEncoder(final ProtobufFactory factory, Type type) { + this.typeClass = (Class) type; + factory.register(type, this); + this.objectEncoder = factory.createObjectEncoder(type); } - public abstract void init(final ProtobufFactory factory); - - @Override - public Type getType() { - return type; + protected static ProtobufDynEncoder generateDyncEncoder( + final ProtobufFactory factory, final Class clazz, final List members) { + final ObjectEncoder selfObjEncoder = factory.createObjectEncoder(clazz); + selfObjEncoder.init(factory); + if (selfObjEncoder.getMembers().length != members.size()) { + return null; // 存在ignore等定制配置 + } + return null; } // 字段全部是primitive或String类型,且没有泛型的类才能动态生成ProtobufDynEncoder, 不支持的返回null @@ -201,13 +208,8 @@ public abstract class ProtobufDynEncoder implements Encodeable members) { - final ObjectEncoder selfObjEncoder = factory.createObjectEncoder(clazz); - selfObjEncoder.init(factory); - if (selfObjEncoder.getMembers().length != members.size()) { - return null; // 存在ignore等定制配置 - } - return null; + @Override + public Type getType() { + return typeClass; } } diff --git a/src/main/java/org/redkale/convert/pb/ProtobufWriter.java b/src/main/java/org/redkale/convert/pb/ProtobufWriter.java index aa0ef0b06..72625ba02 100644 --- a/src/main/java/org/redkale/convert/pb/ProtobufWriter.java +++ b/src/main/java/org/redkale/convert/pb/ProtobufWriter.java @@ -438,107 +438,6 @@ public class ProtobufWriter extends Writer implements ByteTuple { writeTag(member.getTag()); } - @Override - public void writeObjectField(final EnMember member, Object obj) { - Object value; - if (objFieldFunc == null) { - value = member.getFieldValue(obj); - } else { - value = objFieldFunc.apply(member.getAttribute(), obj); - } - if (value == null) { - return; - } - if (tiny()) { - if (member.isStringType()) { - if (((CharSequence) value).length() == 0) { - return; - } - } else if (member.isBoolType()) { - if (!((Boolean) value)) { - return; - } - } - } - Type mtype = member.getAttribute().type(); - if (mtype == boolean[].class && ((boolean[]) value).length < 1) { - return; - } - if (mtype == byte[].class && ((byte[]) value).length < 1) { - return; - } - if (mtype == short[].class && ((short[]) value).length < 1) { - return; - } - if (mtype == char[].class && ((char[]) value).length < 1) { - return; - } - if (mtype == int[].class && ((int[]) value).length < 1) { - return; - } - if (mtype == float[].class && ((float[]) value).length < 1) { - return; - } - if (mtype == long[].class && ((long[]) value).length < 1) { - return; - } - if (mtype == double[].class && ((double[]) value).length < 1) { - return; - } - - Encodeable encoder = member.getEncoder(); - if (encoder == null) { - return; - } - if (encoder instanceof MapEncoder) { - if (!((Map) value).isEmpty()) { - ((MapEncoder) encoder).convertTo(this, member, (Map) value); - } - } else if (encoder instanceof ProtobufArrayEncoder) { - ProtobufArrayEncoder arrayEncoder = (ProtobufArrayEncoder) encoder; - if (arrayEncoder.simple) { - if (((Object[]) value).length < 1) { - this.writeFieldName(member); - ProtobufWriter tmp = new ProtobufWriter().configFieldFunc(this); - arrayEncoder.convertTo(tmp, member, (Object[]) value); - // int length = tmp.count(); - // this.writeUInt32(length); - this.writeTo(tmp.toArray()); - } - } else { - arrayEncoder.convertTo(this, member, (Object[]) value); - } - } else if (encoder instanceof ProtobufCollectionEncoder) { - ProtobufCollectionEncoder collectionEncoder = (ProtobufCollectionEncoder) encoder; - if (collectionEncoder.simple) { - if (!((Collection) value).isEmpty()) { - this.writeFieldName(member); - ProtobufWriter tmp = new ProtobufWriter().configFieldFunc(this); - collectionEncoder.convertTo(tmp, member, (Collection) value); - this.writeLength(tmp.count()); - this.writeTo(tmp.toArray()); - } - } else { - collectionEncoder.convertTo(this, member, (Collection) value); - } - } else if (encoder instanceof ProtobufStreamEncoder) { - ProtobufStreamEncoder streamEncoder = (ProtobufStreamEncoder) encoder; - if (streamEncoder.simple) { - this.writeFieldName(member); - ProtobufWriter tmp = new ProtobufWriter().configFieldFunc(this); - streamEncoder.convertTo(tmp, member, (Stream) value); - this.writeLength(tmp.count()); - this.writeTo(tmp.toArray()); - } else { - streamEncoder.convertTo(this, member, (Stream) value); - } - } else { - this.writeFieldName(member); - encoder.convertTo(this, value); - } - this.comma = true; - } - @Override public final void writeByteArray(byte[] values) { if (values == null) { @@ -945,6 +844,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value) { writeTag(tag); writeBoolean(value); + this.comma = true; } } @@ -953,6 +853,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != 0) { writeTag(tag); writeByte(value); + this.comma = true; } } @@ -961,6 +862,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != 0) { writeTag(tag); writeChar(value); + this.comma = true; } } @@ -969,6 +871,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != 0) { writeTag(tag); writeShort(value); + this.comma = true; } } @@ -977,6 +880,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != 0) { writeTag(tag); writeInt(value); + this.comma = true; } } @@ -985,6 +889,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != 0) { writeTag(tag); writeFloat(value); + this.comma = true; } } @@ -993,6 +898,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != 0) { writeTag(tag); writeLong(value); + this.comma = true; } } @@ -1001,6 +907,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != 0) { writeTag(tag); writeDouble(value); + this.comma = true; } } @@ -1009,6 +916,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != null && !value) { writeTag(tag); writeBoolean(value); + this.comma = true; } } @@ -1017,6 +925,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != null && value != 0) { writeTag(tag); writeByte(value); + this.comma = true; } } @@ -1025,6 +934,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != null && value != 0) { writeTag(tag); writeChar(value); + this.comma = true; } } @@ -1033,6 +943,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != null && value != 0) { writeTag(tag); writeShort(value); + this.comma = true; } } @@ -1041,6 +952,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != null && value != 0) { writeTag(tag); writeInt(value); + this.comma = true; } } @@ -1049,6 +961,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != null && value != 0) { writeTag(tag); writeFloat(value); + this.comma = true; } } @@ -1057,6 +970,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != null && value != 0) { writeTag(tag); writeLong(value); + this.comma = true; } } @@ -1065,6 +979,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != null && value != 0) { writeTag(tag); writeDouble(value); + this.comma = true; } } @@ -1073,6 +988,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != null && value.length > 0) { writeTag(tag); writeBools(value); + this.comma = true; } } @@ -1081,6 +997,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != null && value.length > 0) { writeTag(tag); writeBytes(value); + this.comma = true; } } @@ -1089,6 +1006,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != null && value.length > 0) { writeTag(tag); writeChars(value); + this.comma = true; } } @@ -1097,6 +1015,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != null && value.length > 0) { writeTag(tag); writeShorts(value); + this.comma = true; } } @@ -1105,6 +1024,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != null && value.length > 0) { writeTag(tag); writeInts(value); + this.comma = true; } } @@ -1113,6 +1033,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != null && value.length > 0) { writeTag(tag); writeFloats(value); + this.comma = true; } } @@ -1121,6 +1042,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != null && value.length > 0) { writeTag(tag); writeLongs(value); + this.comma = true; } } @@ -1129,6 +1051,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != null && value.length > 0) { writeTag(tag); writeDoubles(value); + this.comma = true; } } @@ -1137,6 +1060,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != null && value.length > 0) { writeTag(tag); writeBools(value); + this.comma = true; } } @@ -1145,6 +1069,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != null && value.length > 0) { writeTag(tag); writeBytes(value); + this.comma = true; } } @@ -1153,6 +1078,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != null && value.length > 0) { writeTag(tag); writeChars(value); + this.comma = true; } } @@ -1161,6 +1087,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != null && value.length > 0) { writeTag(tag); writeShorts(value); + this.comma = true; } } @@ -1169,6 +1096,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != null && value.length > 0) { writeTag(tag); writeInts(value); + this.comma = true; } } @@ -1177,6 +1105,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != null && value.length > 0) { writeTag(tag); writeFloats(value); + this.comma = true; } } @@ -1185,6 +1114,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != null && value.length > 0) { writeTag(tag); writeLongs(value); + this.comma = true; } } @@ -1193,6 +1123,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != null && value.length > 0) { writeTag(tag); writeDoubles(value); + this.comma = true; } } @@ -1201,6 +1132,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != null && value.length > 0) { writeTag(tag); writeStrings(tag, value); + this.comma = true; } } @@ -1209,6 +1141,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != null && !value.isEmpty()) { writeTag(tag); writeBools(value); + this.comma = true; } } @@ -1217,6 +1150,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != null && !value.isEmpty()) { writeTag(tag); writeBytes(value); + this.comma = true; } } @@ -1225,6 +1159,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != null && !value.isEmpty()) { writeTag(tag); writeChars(value); + this.comma = true; } } @@ -1233,6 +1168,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != null && !value.isEmpty()) { writeTag(tag); writeShorts(value); + this.comma = true; } } @@ -1241,6 +1177,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != null && !value.isEmpty()) { writeTag(tag); writeInts(value); + this.comma = true; } } @@ -1249,6 +1186,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != null && !value.isEmpty()) { writeTag(tag); writeFloats(value); + this.comma = true; } } @@ -1257,6 +1195,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != null && !value.isEmpty()) { writeTag(tag); writeLongs(value); + this.comma = true; } } @@ -1265,6 +1204,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != null && !value.isEmpty()) { writeTag(tag); writeDoubles(value); + this.comma = true; } } @@ -1273,6 +1213,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != null && !value.isEmpty()) { writeTag(tag); writeStrings(tag, value); + this.comma = true; } } @@ -1281,6 +1222,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (value != null && (!value.isEmpty() || !tiny())) { writeTag(tag); writeString(value); + this.comma = true; } } @@ -1293,9 +1235,121 @@ public class ProtobufWriter extends Writer implements ByteTuple { } else { writeInt(value.ordinal()); } + this.comma = true; } } + @ClassDepends + public void writeFieldValue(int tag, SimpledCoder encoder, Object value) { + if (value != null) { + writeTag(tag); + encoder.convertTo(this, value); + this.comma = true; + } + } + + @Override + @ClassDepends + public void writeObjectField(final EnMember member, Object obj) { + Object value; + if (objFieldFunc == null) { + value = member.getFieldValue(obj); + } else { + value = objFieldFunc.apply(member.getAttribute(), obj); + } + if (value == null) { + return; + } + if (tiny()) { + if (member.isStringType()) { + if (((CharSequence) value).length() == 0) { + return; + } + } else if (member.isBoolType()) { + if (!((Boolean) value)) { + return; + } + } + } + Type mtype = member.getAttribute().type(); + if (mtype == boolean[].class && ((boolean[]) value).length < 1) { + return; + } + if (mtype == byte[].class && ((byte[]) value).length < 1) { + return; + } + if (mtype == short[].class && ((short[]) value).length < 1) { + return; + } + if (mtype == char[].class && ((char[]) value).length < 1) { + return; + } + if (mtype == int[].class && ((int[]) value).length < 1) { + return; + } + if (mtype == float[].class && ((float[]) value).length < 1) { + return; + } + if (mtype == long[].class && ((long[]) value).length < 1) { + return; + } + if (mtype == double[].class && ((double[]) value).length < 1) { + return; + } + + Encodeable encoder = member.getEncoder(); + if (encoder == null) { + return; + } + if (encoder instanceof MapEncoder) { + if (!((Map) value).isEmpty()) { + ((MapEncoder) encoder).convertTo(this, member, (Map) value); + } + } else if (encoder instanceof ProtobufArrayEncoder) { + ProtobufArrayEncoder arrayEncoder = (ProtobufArrayEncoder) encoder; + if (arrayEncoder.simple) { + if (((Object[]) value).length < 1) { + this.writeFieldName(member); + ProtobufWriter tmp = new ProtobufWriter().configFieldFunc(this); + arrayEncoder.convertTo(tmp, member, (Object[]) value); + // int length = tmp.count(); + // this.writeUInt32(length); + this.writeTo(tmp.toArray()); + } + } else { + arrayEncoder.convertTo(this, member, (Object[]) value); + } + } else if (encoder instanceof ProtobufCollectionEncoder) { + ProtobufCollectionEncoder collectionEncoder = (ProtobufCollectionEncoder) encoder; + if (collectionEncoder.simple) { + if (!((Collection) value).isEmpty()) { + this.writeFieldName(member); + ProtobufWriter tmp = new ProtobufWriter().configFieldFunc(this); + collectionEncoder.convertTo(tmp, member, (Collection) value); + this.writeLength(tmp.count()); + this.writeTo(tmp.toArray()); + } + } else { + collectionEncoder.convertTo(this, member, (Collection) value); + } + } else if (encoder instanceof ProtobufStreamEncoder) { + ProtobufStreamEncoder streamEncoder = (ProtobufStreamEncoder) encoder; + if (streamEncoder.simple) { + this.writeFieldName(member); + ProtobufWriter tmp = new ProtobufWriter().configFieldFunc(this); + streamEncoder.convertTo(tmp, member, (Stream) value); + this.writeLength(tmp.count()); + this.writeTo(tmp.toArray()); + } else { + streamEncoder.convertTo(this, member, (Stream) value); + } + } else { + this.writeFieldName(member); + encoder.convertTo(this, value); + } + this.comma = true; + } + @ClassDepends public void writeTag(int tag) { if (tag < 128) {