diff --git a/src/main/java/org/redkale/convert/ObjectEncoder.java b/src/main/java/org/redkale/convert/ObjectEncoder.java index 1a898b324..625855c60 100644 --- a/src/main/java/org/redkale/convert/ObjectEncoder.java +++ b/src/main/java/org/redkale/convert/ObjectEncoder.java @@ -360,6 +360,7 @@ public class ObjectEncoder implements Encodeable { } } objout.writeObjectE(value); + offerWriter(out, objout); } // ---------------------------------- 可定制方法 ---------------------------------- @@ -375,6 +376,10 @@ public class ObjectEncoder implements Encodeable { return out; } + protected void offerWriter(W parent, W out) { + // do nothing + } + // --------------------------------------------------------------------------------- protected void setTag(EnMember member, int tag) { member.tag = tag; diff --git a/src/main/java/org/redkale/convert/json/JsonDynEncoder.java b/src/main/java/org/redkale/convert/json/JsonDynEncoder.java index d95ed8a49..2a5687d0d 100644 --- a/src/main/java/org/redkale/convert/json/JsonDynEncoder.java +++ b/src/main/java/org/redkale/convert/json/JsonDynEncoder.java @@ -28,16 +28,20 @@ import org.redkale.util.*; * @param 序列化的数据类型 */ @SuppressWarnings("unchecked") -public abstract class JsonDynEncoder implements Encodeable { +public abstract class JsonDynEncoder extends ObjectEncoder { protected final Class typeClass; - protected final ObjectEncoder objectEncoder; + protected final ObjectEncoder objectEncoderSelf; - protected JsonDynEncoder(final JsonFactory factory, Type type) { + protected JsonDynEncoder(JsonFactory factory, Type type, ObjectEncoder objectEncoderSelf) { + super(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 JsonDynEncoder generateDyncEncoder( @@ -70,11 +74,8 @@ public abstract class JsonDynEncoder implements Encodeable { 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); + (JsonDynEncoder) newClazz.getConstructor(JsonFactory.class, Type.class, ObjectEncoder.class) + .newInstance(factory, clazz, selfObjEncoder); if (mixedNames != null) { for (Map.Entry en : mixedNames.entrySet()) { Field f = newClazz.getDeclaredField(en.getKey() + "Encoder"); @@ -116,8 +117,6 @@ public abstract class JsonDynEncoder implements Encodeable { supDynName, null); - fv = cw.visitField(ACC_PROTECTED, "objectEncoderSelf", objEncoderDesc, null, null); - fv.visitEnd(); final int membersSize = elements.size(); boolean onlyTwoIntFieldObjectFlag = false; // 只包含两个int字段 boolean onlyOneLatin1FieldObjectFlag = false; // 只包含一个Latin1 String字段 @@ -161,12 +160,19 @@ public abstract class JsonDynEncoder implements Encodeable { onlyShotIntLongLatin1MoreFieldObjectFlag = false; // 字段个数必须大于1 } { // 构造函数 - mv = (cw.visitMethod(ACC_PUBLIC, "", "(" + jsonfactoryDesc + typeDesc + ")V", null, null)); + mv = (cw.visitMethod( + ACC_PUBLIC, "", "(" + jsonfactoryDesc + typeDesc + objEncoderDesc + ")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); + mv.visitVarInsn(ALOAD, 3); + mv.visitMethodInsn( + INVOKESPECIAL, + supDynName, + "", + "(" + jsonfactoryDesc + typeDesc + objEncoderDesc + ")V", + false); for (AccessibleObject element : elements) { final String fieldName = factory.readConvertFieldName(clazz, element); @@ -684,12 +690,8 @@ public abstract class JsonDynEncoder implements Encodeable { 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); + (JsonDynEncoder) newClazz.getConstructor(JsonFactory.class, Type.class, ObjectEncoder.class) + .newInstance(factory, clazz, selfObjEncoder); if (mixedNames != null) { for (Map.Entry en : mixedNames.entrySet()) { Field f = newClazz.getDeclaredField(en.getKey() + "Encoder"); diff --git a/src/main/java/org/redkale/convert/pb/ProtobufArrayEncoder.java b/src/main/java/org/redkale/convert/pb/ProtobufArrayEncoder.java index ecf42c7a8..edf37bb6a 100644 --- a/src/main/java/org/redkale/convert/pb/ProtobufArrayEncoder.java +++ b/src/main/java/org/redkale/convert/pb/ProtobufArrayEncoder.java @@ -47,10 +47,11 @@ public class ProtobufArrayEncoder extends ArrayEncoder { } else if (item instanceof CharSequence) { encoder.convertTo(out, item); } else { - ProtobufWriter tmp = new ProtobufWriter().configFieldFunc(out); + ProtobufWriter tmp = out.pollChild(); encoder.convertTo(tmp, item); out.writeLength(tmp.count()); out.writeTo(tmp.toArray()); + out.offerChild(tmp); } } } diff --git a/src/main/java/org/redkale/convert/pb/ProtobufCollectionEncoder.java b/src/main/java/org/redkale/convert/pb/ProtobufCollectionEncoder.java index 471786146..ccbd26c2e 100644 --- a/src/main/java/org/redkale/convert/pb/ProtobufCollectionEncoder.java +++ b/src/main/java/org/redkale/convert/pb/ProtobufCollectionEncoder.java @@ -47,10 +47,11 @@ public class ProtobufCollectionEncoder extends CollectionEncoder extends ProtobufObjectEncoder { // 动态字段: protected EnMember xxxEnMember; - protected ProtobufDynEncoder(final ProtobufFactory factory, Type type, ObjectEncoder objectEncoderSelf) { + protected ProtobufDynEncoder(ProtobufFactory factory, Type type, ObjectEncoder objectEncoderSelf) { super((Class) type); this.typeClass = (Class) type; this.factory = factory; @@ -431,13 +414,6 @@ public abstract class ProtobufDynEncoder extends ProtobufObjectEncoder { return generateDyncEncoder(factory, (Class) type); } - protected static Class readGetSetFieldType(AccessibleObject element) { - if (element instanceof Field) { - return ((Field) element).getType(); - } - return ((Method) element).getReturnType(); - } - @Override public Type getType() { return typeClass; diff --git a/src/main/java/org/redkale/convert/pb/ProtobufMapEncoder.java b/src/main/java/org/redkale/convert/pb/ProtobufMapEncoder.java index 35470fce6..3b1822ad4 100644 --- a/src/main/java/org/redkale/convert/pb/ProtobufMapEncoder.java +++ b/src/main/java/org/redkale/convert/pb/ProtobufMapEncoder.java @@ -28,7 +28,7 @@ public class ProtobufMapEncoder extends MapEncoder { @Override protected void writeMemberValue(ProtobufWriter out, EnMember member, K key, V value, boolean first) { - ProtobufWriter tmp = new ProtobufWriter().configFieldFunc(out); + ProtobufWriter tmp = out.pollChild(); if (member != null) { out.writeFieldName(member); } @@ -38,5 +38,6 @@ public class ProtobufMapEncoder extends MapEncoder { valueEncoder.convertTo(tmp, value); out.writeLength(tmp.count()); out.writeTo(tmp.toArray()); + out.offerChild(tmp); } } diff --git a/src/main/java/org/redkale/convert/pb/ProtobufObjectEncoder.java b/src/main/java/org/redkale/convert/pb/ProtobufObjectEncoder.java index ff5bb9274..e5aefd321 100644 --- a/src/main/java/org/redkale/convert/pb/ProtobufObjectEncoder.java +++ b/src/main/java/org/redkale/convert/pb/ProtobufObjectEncoder.java @@ -34,8 +34,15 @@ public class ProtobufObjectEncoder extends ObjectEncoder { @Override protected ProtobufWriter objectWriter(ProtobufWriter out, T value) { if (out.count() > out.initOffset) { - return new ProtobufWriter(out, out.getFeatures()).configFieldFunc(out); + return out.pollChild().configParentFunc(out); } return out; } + + @Override + protected void offerWriter(ProtobufWriter parent, ProtobufWriter out) { + if (parent != out) { + parent.offerChild(out); + } + } } diff --git a/src/main/java/org/redkale/convert/pb/ProtobufStreamEncoder.java b/src/main/java/org/redkale/convert/pb/ProtobufStreamEncoder.java index 7a67960a3..9326ea02a 100644 --- a/src/main/java/org/redkale/convert/pb/ProtobufStreamEncoder.java +++ b/src/main/java/org/redkale/convert/pb/ProtobufStreamEncoder.java @@ -47,10 +47,11 @@ public class ProtobufStreamEncoder extends StreamEncoder { if (item instanceof CharSequence) { componentEncoder.convertTo(out, item); } else { - ProtobufWriter tmp = new ProtobufWriter().configFieldFunc(out); + ProtobufWriter tmp = out.pollChild(); componentEncoder.convertTo(tmp, item); out.writeUInt32(tmp.count()); out.writeTo(tmp.toArray()); + out.offerChild(tmp); } } } diff --git a/src/main/java/org/redkale/convert/pb/ProtobufWriter.java b/src/main/java/org/redkale/convert/pb/ProtobufWriter.java index 8393366c6..e4bde209c 100644 --- a/src/main/java/org/redkale/convert/pb/ProtobufWriter.java +++ b/src/main/java/org/redkale/convert/pb/ProtobufWriter.java @@ -23,6 +23,8 @@ public class ProtobufWriter extends Writer implements ByteTuple { "redkale.convert.protobuf.writer.buffer.defsize", Integer.getInteger("redkale.convert.writer.buffer.defsize", 1024)); + private static final int CHILD_SIZE = 8; + private static final int TENTHOUSAND_MAX = 10001; private static final byte[][] TENTHOUSAND_UINT_BYTES = new byte[TENTHOUSAND_MAX][]; @@ -69,11 +71,13 @@ public class ProtobufWriter extends Writer implements ByteTuple { protected ProtobufWriter parent; - protected ProtobufWriter(ProtobufWriter parent, int features) { + private ArrayDeque childWriters; + + protected ProtobufWriter(ProtobufWriter parent) { this(); this.parent = parent; - this.features = features; if (parent != null) { + this.features = parent.features; this.enumtostring = parent.enumtostring; } } @@ -88,6 +92,15 @@ public class ProtobufWriter extends Writer implements ByteTuple { return this; } + protected ProtobufWriter configParentFunc(ProtobufWriter parent) { + this.parent = parent; + if (parent != null) { + this.features = parent.features; + this.enumtostring = parent.enumtostring; + } + return this; + } + protected ProtobufWriter configFieldFunc(ProtobufWriter out) { if (out == null) { return this; @@ -116,6 +129,12 @@ public class ProtobufWriter extends Writer implements ByteTuple { @Override protected boolean recycle() { super.recycle(); + this.parent = null; + this.mapFieldFunc = null; + this.objFieldFunc = null; + this.objExtFunc = null; + this.features = 0; + this.enumtostring = false; this.count = 0; this.initOffset = 0; if (this.content.length > DEFAULT_SIZE) { @@ -124,6 +143,27 @@ public class ProtobufWriter extends Writer implements ByteTuple { return true; } + public final ProtobufWriter pollChild() { + Queue queue = this.childWriters; + if (queue == null) { + this.childWriters = new ArrayDeque<>(CHILD_SIZE); + queue = this.childWriters; + } + ProtobufWriter result = queue.poll(); + if (result == null) { + result = new ProtobufWriter(); + } + return result.configFieldFunc(this); + } + + public final void offerChild(final ProtobufWriter child) { + Queue queue = this.childWriters; + if (child != null && queue != null && queue.size() < CHILD_SIZE) { + child.recycle(); + queue.offer(child); + } + } + @Override public byte[] content() { return content; @@ -270,7 +310,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { return length; } else { final Class type = obj.getClass(); - ProtobufWriter tmp = new ProtobufWriter().configFieldFunc(this); + ProtobufWriter tmp = pollChild(); if (type == boolean[].class) { for (boolean item : (boolean[]) obj) { tmp.writeBoolean(item); @@ -405,6 +445,7 @@ public class ProtobufWriter extends Writer implements ByteTuple { int length = tmp.count(); writeLength(length); writeTo(tmp.toArray()); + offerChild(tmp); return length; } } @@ -1309,11 +1350,12 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (arrayEncoder.simple) { if (((Object[]) value).length < 1) { this.writeFieldName(member); - ProtobufWriter tmp = new ProtobufWriter().configFieldFunc(this); + ProtobufWriter tmp = pollChild(); arrayEncoder.convertTo(tmp, member, (Object[]) value); // int length = tmp.count(); // this.writeUInt32(length); this.writeTo(tmp.toArray()); + offerChild(tmp); } } else { arrayEncoder.convertTo(this, member, (Object[]) value); @@ -1323,10 +1365,11 @@ public class ProtobufWriter extends Writer implements ByteTuple { if (collectionEncoder.simple) { if (!((Collection) value).isEmpty()) { this.writeFieldName(member); - ProtobufWriter tmp = new ProtobufWriter().configFieldFunc(this); + ProtobufWriter tmp = pollChild(); collectionEncoder.convertTo(tmp, member, (Collection) value); this.writeLength(tmp.count()); this.writeTo(tmp.toArray()); + offerChild(tmp); } } else { collectionEncoder.convertTo(this, member, (Collection) value); @@ -1335,10 +1378,11 @@ public class ProtobufWriter extends Writer implements ByteTuple { ProtobufStreamEncoder streamEncoder = (ProtobufStreamEncoder) encoder; if (streamEncoder.simple) { this.writeFieldName(member); - ProtobufWriter tmp = new ProtobufWriter().configFieldFunc(this); + ProtobufWriter tmp = pollChild(); streamEncoder.convertTo(tmp, member, (Stream) value); this.writeLength(tmp.count()); this.writeTo(tmp.toArray()); + offerChild(tmp); } else { streamEncoder.convertTo(this, member, (Stream) value); } diff --git a/src/test/java/org/redkale/test/convert/_DyncFortuneJsonEncoder.java b/src/test/java/org/redkale/test/convert/_DyncFortuneJsonEncoder.java index 0d24003f1..935f7875a 100644 --- a/src/test/java/org/redkale/test/convert/_DyncFortuneJsonEncoder.java +++ b/src/test/java/org/redkale/test/convert/_DyncFortuneJsonEncoder.java @@ -6,6 +6,7 @@ package org.redkale.test.convert; import java.lang.reflect.Type; +import org.redkale.convert.ObjectEncoder; import org.redkale.convert.json.*; /** @author zhangjx */ @@ -15,8 +16,8 @@ public class _DyncFortuneJsonEncoder extends JsonDynEncoder { protected final byte[] messageCommaFieldBytes = ",\"message\":".getBytes(); - public _DyncFortuneJsonEncoder(JsonFactory factory, Type type) { - super(factory, type); + public _DyncFortuneJsonEncoder(JsonFactory factory, Type type, ObjectEncoder objectEncoderSelf) { + super(factory, type, objectEncoderSelf); } @Override @@ -26,7 +27,7 @@ public class _DyncFortuneJsonEncoder extends JsonDynEncoder { return; } if (!out.isExtFuncEmpty()) { - objectEncoder.convertTo(out, value); + objectEncoderSelf.convertTo(out, value); return; } diff --git a/src/test/java/org/redkale/test/convert/_DyncMessageJsonEncoder.java b/src/test/java/org/redkale/test/convert/_DyncMessageJsonEncoder.java index 637e4a6e1..89ad3cdee 100644 --- a/src/test/java/org/redkale/test/convert/_DyncMessageJsonEncoder.java +++ b/src/test/java/org/redkale/test/convert/_DyncMessageJsonEncoder.java @@ -6,6 +6,7 @@ package org.redkale.test.convert; import java.lang.reflect.Type; +import org.redkale.convert.ObjectEncoder; import org.redkale.convert.json.*; /** @author zhangjx */ @@ -15,8 +16,8 @@ public class _DyncMessageJsonEncoder extends JsonDynEncoder { protected final byte[] messageCommaFieldBytes = ",\"message\":".getBytes(); - public _DyncMessageJsonEncoder(JsonFactory factory, Type type) { - super(factory, type); + public _DyncMessageJsonEncoder(JsonFactory factory, Type type, ObjectEncoder objectEncoderSelf) { + super(factory, type, objectEncoderSelf); } @Override @@ -26,7 +27,7 @@ public class _DyncMessageJsonEncoder extends JsonDynEncoder { return; } if (!out.isExtFuncEmpty()) { - objectEncoder.convertTo(out, value); + objectEncoderSelf.convertTo(out, value); return; } diff --git a/src/test/java/org/redkale/test/convert/_DyncWorldJsonEncoder.java b/src/test/java/org/redkale/test/convert/_DyncWorldJsonEncoder.java index 99dc2b4ec..da3dd1c59 100644 --- a/src/test/java/org/redkale/test/convert/_DyncWorldJsonEncoder.java +++ b/src/test/java/org/redkale/test/convert/_DyncWorldJsonEncoder.java @@ -6,6 +6,7 @@ package org.redkale.test.convert; import java.lang.reflect.Type; +import org.redkale.convert.ObjectEncoder; import org.redkale.convert.json.*; /** @author zhangjx */ @@ -15,8 +16,8 @@ public class _DyncWorldJsonEncoder extends JsonDynEncoder { protected final byte[] randomNumberFieldBytes = ",\"randomNumber\":".getBytes(); - public _DyncWorldJsonEncoder(JsonFactory factory, Type type) { - super(factory, type); + public _DyncWorldJsonEncoder(JsonFactory factory, Type type, ObjectEncoder objectEncoderSelf) { + super(factory, type, objectEncoderSelf); } @Override @@ -26,7 +27,7 @@ public class _DyncWorldJsonEncoder extends JsonDynEncoder { return; } if (!out.isExtFuncEmpty()) { - objectEncoder.convertTo(out, value); + objectEncoderSelf.convertTo(out, value); return; }