diff --git a/src/main/java/org/redkale/boot/ApiDocCommand.java b/src/main/java/org/redkale/boot/ApiDocCommand.java index 8121d2028..a2891e703 100644 --- a/src/main/java/org/redkale/boot/ApiDocCommand.java +++ b/src/main/java/org/redkale/boot/ApiDocCommand.java @@ -595,7 +595,7 @@ public final class ApiDocCommand { if (col != null) { desc = col.comment(); if (!col.nullable()) { - requireds.add(member.getAttribute().field()); + requireds.add(member.getFieldName()); } } if (desc.isEmpty() && member.getField().getAnnotation(Comment.class) != null) { @@ -613,7 +613,7 @@ public final class ApiDocCommand { if (col != null) { desc = col.comment(); if (!col.nullable()) { - requireds.add(member.getAttribute().field()); + requireds.add(member.getFieldName()); } } if (desc.isEmpty() && member.getMethod().getAnnotation(Comment.class) != null) { @@ -630,7 +630,7 @@ public final class ApiDocCommand { if (!desc.isEmpty()) { schemaMap.put("description", desc); } - properties.put(member.getAttribute().field(), schemaMap); + properties.put(member.getFieldName(), schemaMap); } } if (!requireds.isEmpty()) { @@ -899,7 +899,7 @@ public final class ApiDocCommand { if (index > 0) { json.append(","); } - json.append('"').append(member.getAttribute().field()).append("\":{}"); + json.append('"').append(member.getFieldName()).append("\":{}"); index++; } json.append("}"); diff --git a/src/main/java/org/redkale/convert/DeMember.java b/src/main/java/org/redkale/convert/DeMember.java index fd1f15a1e..837bcd324 100644 --- a/src/main/java/org/redkale/convert/DeMember.java +++ b/src/main/java/org/redkale/convert/DeMember.java @@ -119,6 +119,10 @@ public final class DeMember { return ((TagDecodeable) decoder).convertFrom(in, this); } + public String getFieldName() { + return this.attribute.field(); + } + public Attribute getAttribute() { return this.attribute; } diff --git a/src/main/java/org/redkale/convert/DeMemberInfo.java b/src/main/java/org/redkale/convert/DeMemberInfo.java index f52c2eb09..564a20b7f 100644 --- a/src/main/java/org/redkale/convert/DeMemberInfo.java +++ b/src/main/java/org/redkale/convert/DeMemberInfo.java @@ -30,7 +30,7 @@ public class DeMemberInfo { this.memberFieldMap = new HashMap<>(deMembers.length); this.memberTagMap = new HashMap<>(deMembers.length); for (DeMember member : deMembers) { - this.memberFieldMap.put(member.getAttribute().field(), member); + this.memberFieldMap.put(member.getFieldName(), member); this.memberTagMap.put(member.getTag(), member); } this.memberNode = DeMemberNode.create(deMembers); diff --git a/src/main/java/org/redkale/convert/EnMember.java b/src/main/java/org/redkale/convert/EnMember.java index 57220eaf8..fcf9c7a0d 100644 --- a/src/main/java/org/redkale/convert/EnMember.java +++ b/src/main/java/org/redkale/convert/EnMember.java @@ -137,6 +137,10 @@ public final class EnMember { return attribute.field().equals(name); } + public String getFieldName() { + return this.attribute.field(); + } + public Attribute getAttribute() { return attribute; } diff --git a/src/main/java/org/redkale/convert/ObjectDecoder.java b/src/main/java/org/redkale/convert/ObjectDecoder.java index 2d461939f..ccf8a4fb0 100644 --- a/src/main/java/org/redkale/convert/ObjectDecoder.java +++ b/src/main/java/org/redkale/convert/ObjectDecoder.java @@ -359,13 +359,12 @@ public class ObjectDecoder implements Decodeable { @Override public T convertFrom(final R in) { this.checkInited(); - R objin = objectReader(in); - final String clazz = objin.readObjectB(typeClass); + final String clazz = in.readObjectB(typeClass); if (clazz == null) { return null; } if (!clazz.isEmpty()) { - return (T) factory.loadDecoder(factory.getEntityAlias(clazz)).convertFrom(objin); + return (T) factory.loadDecoder(factory.getEntityAlias(clazz)).convertFrom(in); } if (this.creator == null) { if (typeClass.isInterface() || Modifier.isAbstract(typeClass.getModifiers())) { @@ -378,18 +377,17 @@ public class ObjectDecoder implements Decodeable { if (this.creatorConstructorMembers == null) { // 空构造函数 final T result = this.creator == null ? null : this.creator.create(); boolean first = true; - while (objin.hasNext()) { - DeMember member = objin.readFieldName(info); - objin.readBlank(); + while (in.hasNext()) { + DeMember member = in.readFieldName(info); + in.readBlank(); if (member == null) { - objin.skipValue(); // 跳过不存在的属性的值 + in.skipValue(); // 跳过不存在的属性的值 } else { - readDeMemberValue(objin, member, result, first); + readDeMemberValue(in, member, result, first); } first = false; } - objin.readObjectE(typeClass); - offerReader(in, objin); + in.readObjectE(typeClass); return result; } else { // 带参数的构造函数 final DeMember[] constructorFields = this.creatorConstructorMembers; @@ -397,13 +395,13 @@ public class ObjectDecoder implements Decodeable { final Object[][] otherParams = new Object[info.length()][2]; int oc = 0; boolean first = true; - while (objin.hasNext()) { - DeMember member = objin.readFieldName(info); - objin.readBlank(); + while (in.hasNext()) { + DeMember member = in.readFieldName(info); + in.readBlank(); if (member == null) { - objin.skipValue(); // 跳过不存在的属性的值 + in.skipValue(); // 跳过不存在的属性的值 } else { - Object val = readDeMemberValue(objin, member, first); + Object val = readDeMemberValue(in, member, first); boolean flag = true; for (int i = 0; i < constructorFields.length; i++) { if (member == constructorFields[i]) { @@ -418,8 +416,7 @@ public class ObjectDecoder implements Decodeable { } first = false; } - objin.readObjectE(typeClass); - offerReader(in, objin); + in.readObjectE(typeClass); if (this.creator == null) { return null; } @@ -440,18 +437,6 @@ public class ObjectDecoder implements Decodeable { // do nothing } - protected boolean hasNext(R in, boolean first) { - return in.hasNext(); - } - - protected R objectReader(R in) { - return in; - } - - protected void offerReader(R parent, R out) { - // do nothing - } - protected Object readDeMemberValue(R in, DeMember member, boolean first) { return member.read(in); } diff --git a/src/main/java/org/redkale/convert/bson/BsonReader.java b/src/main/java/org/redkale/convert/bson/BsonReader.java index a6b60202f..0f856de7a 100644 --- a/src/main/java/org/redkale/convert/bson/BsonReader.java +++ b/src/main/java/org/redkale/convert/bson/BsonReader.java @@ -7,9 +7,9 @@ package org.redkale.convert.bson; import java.nio.charset.StandardCharsets; import org.redkale.convert.*; +import static org.redkale.convert.Reader.SIGN_NULL; import org.redkale.convert.ext.ByteSimpledCoder; import org.redkale.util.*; -import static org.redkale.convert.Reader.SIGN_NULL; /** * BSON数据源 @@ -129,7 +129,6 @@ public class BsonReader extends Reader { break; default: Decodeable decoder = BsonFactory.typeEnum(val); - System.out.println("val = " + val + ", decoder = " + decoder); if (decoder != null) { decoder.convertFrom(this); } diff --git a/src/main/java/org/redkale/convert/json/JsonMultiImplDecoder.java b/src/main/java/org/redkale/convert/json/JsonMultiImplDecoder.java index a9a30f475..823c65d99 100644 --- a/src/main/java/org/redkale/convert/json/JsonMultiImplDecoder.java +++ b/src/main/java/org/redkale/convert/json/JsonMultiImplDecoder.java @@ -47,7 +47,7 @@ public class JsonMultiImplDecoder implements Decodeable { max = decoder.getMembers().length; } for (DeMember member : decoder.getMembers()) { - String name = member.getAttribute().field(); + String name = member.getFieldName(); this.repeatFieldToDecoders.put(name, decoder); fields[i].add(name); Attribute t = fieldTypes.get(name); @@ -164,7 +164,7 @@ public class JsonMultiImplDecoder implements Decodeable { for (int j = 0; j < params.length; j++) { if (params[j] != null && params[j][0] != null - && constructorFields[i].getAttribute().field().equals(((Attribute) params[j][0]).field())) { + && constructorFields[i].getFieldName().equals(((Attribute) params[j][0]).field())) { constructorParams[i] = params[j][1]; params[j] = null; break; diff --git a/src/main/java/org/redkale/convert/json/JsonReader.java b/src/main/java/org/redkale/convert/json/JsonReader.java index a498278e9..7f18d0f99 100644 --- a/src/main/java/org/redkale/convert/json/JsonReader.java +++ b/src/main/java/org/redkale/convert/json/JsonReader.java @@ -44,7 +44,7 @@ public class JsonReader extends Reader { public JsonReader(char[] text, int start, int len) { this.text = Objects.requireNonNull(text); this.position = start - 1; - this.limit = start + len - 1; + this.limit = this.position + len; } public final JsonReader setText(String text) { @@ -58,7 +58,7 @@ public class JsonReader extends Reader { public final JsonReader setText(char[] text, int start, int len) { this.text = text; this.position = start - 1; - this.limit = start + len - 1; + this.limit = this.position + len; return this; } diff --git a/src/main/java/org/redkale/convert/pb/ProtobufArrayDecoder.java b/src/main/java/org/redkale/convert/pb/ProtobufArrayDecoder.java index b0dd8aade..c6168326d 100644 --- a/src/main/java/org/redkale/convert/pb/ProtobufArrayDecoder.java +++ b/src/main/java/org/redkale/convert/pb/ProtobufArrayDecoder.java @@ -27,26 +27,25 @@ public class ProtobufArrayDecoder extends ArrayDecoder { @Override public T[] convertFrom(ProtobufReader in, DeMember member) { this.checkInited(); + final boolean simpled = this.componentSimpled; final Decodeable itemDecoder = this.componentDecoder; in.readArrayB(member, itemDecoder); - int contentLength = in.readMemberContentLength(member, itemDecoder); final List result = new ArrayList(); - boolean first = true; - int startPosition = in.position(); - while (in.hasNext(startPosition, contentLength)) { - ProtobufReader itemReader = getItemReader(in, member, first); - if (itemReader == null) { // 元素读取完毕 + final int limit = in.limit(); + while (in.hasNext()) { + ProtobufReader subin = in; + if (!simpled) { + int contentLen = in.readRawVarint32(); + in.limit(in.position() + contentLen + 1); + } + result.add(itemDecoder.convertFrom(subin)); + in.limit(limit); + if (!in.readNextTag(member)) { // 元素结束 break; } - result.add(itemDecoder.convertFrom(itemReader)); - first = false; } in.readArrayE(); T[] rs = this.componentArrayFunction.apply(result.size()); return result.toArray(rs); } - - protected ProtobufReader getItemReader(ProtobufReader in, DeMember member, boolean first) { - return ProtobufFactory.getItemReader(in, member, componentSimpled, first); - } } diff --git a/src/main/java/org/redkale/convert/pb/ProtobufCollectionDecoder.java b/src/main/java/org/redkale/convert/pb/ProtobufCollectionDecoder.java index 4f779b2d2..153c7890f 100644 --- a/src/main/java/org/redkale/convert/pb/ProtobufCollectionDecoder.java +++ b/src/main/java/org/redkale/convert/pb/ProtobufCollectionDecoder.java @@ -25,25 +25,23 @@ public class ProtobufCollectionDecoder extends CollectionDecoder convertFrom(ProtobufReader in, DeMember member) { this.checkInited(); + final boolean simpled = !this.componentSimpled; final Decodeable itemDecoder = this.componentDecoder; in.readArrayB(member, itemDecoder); - int contentLength = in.readMemberContentLength(member, itemDecoder); final Collection result = this.creator.create(); - boolean first = true; - int startPosition = in.position(); - while (in.hasNext(startPosition, contentLength)) { - ProtobufReader itemReader = getItemReader(in, member, first); - if (itemReader == null) { // 元素读取完毕 + final int limit = in.limit(); + while (in.hasNext()) { + if (!simpled) { + int contentLen = in.readRawVarint32(); + in.limit(in.position() + contentLen + 1); + } + result.add(itemDecoder.convertFrom(in)); + in.limit(limit); + if (!in.readNextTag(member)) { // 元素结束 break; } - result.add(itemDecoder.convertFrom(itemReader)); - first = false; } in.readArrayE(); return result; } - - protected ProtobufReader getItemReader(ProtobufReader in, DeMember member, boolean first) { - return ProtobufFactory.getItemReader(in, member, componentSimpled, first); - } } diff --git a/src/main/java/org/redkale/convert/pb/ProtobufConvert.java b/src/main/java/org/redkale/convert/pb/ProtobufConvert.java index 51ef1f959..2ed74e752 100644 --- a/src/main/java/org/redkale/convert/pb/ProtobufConvert.java +++ b/src/main/java/org/redkale/convert/pb/ProtobufConvert.java @@ -240,7 +240,7 @@ public class ProtobufConvert extends BinaryConvert extends ProtobufObjectEncoder { final Map otherMembers = new HashMap<>(); StringBuilder elementb = new StringBuilder(); for (EnMember member : selfObjEncoder.getMembers()) { - final String fieldName = member.getAttribute().field(); + final String fieldName = member.getFieldName(); final Class fieldClass = member.getAttribute().type(); final Type fieldType = member.getAttribute().genericType(); elementb.append(fieldName).append(','); @@ -172,7 +172,7 @@ public abstract class ProtobufDynEncoder extends ProtobufObjectEncoder { mv.visitMethodInsn(INVOKEVIRTUAL, pbwriterName, "writeObjectB", "(Ljava/lang/Object;)V", false); for (EnMember member : selfObjEncoder.getMembers()) { - final String fieldName = member.getAttribute().field(); + final String fieldName = member.getFieldName(); final Type fieldType = member.getAttribute().genericType(); final Class fieldClass = member.getAttribute().type(); if (ProtobufFactory.isSimpleType(fieldClass)) { diff --git a/src/main/java/org/redkale/convert/pb/ProtobufFactory.java b/src/main/java/org/redkale/convert/pb/ProtobufFactory.java index 5490e0616..5fe0bf1cc 100644 --- a/src/main/java/org/redkale/convert/pb/ProtobufFactory.java +++ b/src/main/java/org/redkale/convert/pb/ProtobufFactory.java @@ -303,44 +303,6 @@ public class ProtobufFactory extends ConvertFactory extends MapDecoder { this.checkInited(); in.readMapB(member, this.keyDecoder, this.valueDecoder); final Map result = this.creator.create(); - boolean first = true; Decodeable kdecoder = this.keyDecoder; Decodeable vdecoder = this.valueDecoder; + final int limit = in.limit(); while (in.hasNext()) { - ProtobufReader entryReader = getEntryReader(in, member, first); - if (entryReader == null) { + int contentLen = in.readRawVarint32(); + in.limit(in.position() + contentLen + 1); + in.readTag(); + K key = kdecoder.convertFrom(in); + in.readTag(); + V value = vdecoder.convertFrom(in); + result.put(key, value); + in.limit(limit); + if (!in.readNextTag(member)) { // 元素结束 break; } - entryReader.readTag(); - K key = kdecoder.convertFrom(entryReader); - entryReader.readTag(); - V value = vdecoder.convertFrom(entryReader); - result.put(key, value); - first = false; } in.readMapE(); return result; } - - protected ProtobufReader getEntryReader(ProtobufReader in, DeMember member, boolean first) { - if (!first && member != null) { - int tag = in.readTag(); - if (tag != member.getTag()) { - in.backTag(tag); - return null; - } - } - byte[] bs = in.readByteArray(); - return new ProtobufReader(bs); - } } diff --git a/src/main/java/org/redkale/convert/pb/ProtobufObjectDecoder.java b/src/main/java/org/redkale/convert/pb/ProtobufObjectDecoder.java index 3ac80f0aa..f787f5cf1 100644 --- a/src/main/java/org/redkale/convert/pb/ProtobufObjectDecoder.java +++ b/src/main/java/org/redkale/convert/pb/ProtobufObjectDecoder.java @@ -13,12 +13,27 @@ import org.redkale.util.*; * @author zhangjx * @param T */ -public class ProtobufObjectDecoder extends ObjectDecoder { +public class ProtobufObjectDecoder extends ObjectDecoder + implements TagDecodeable { protected ProtobufObjectDecoder(Type type) { super(type); } + @Override + public T convertFrom(ProtobufReader in, DeMember member) { + if (member == null) { + return super.convertFrom(in); + } else { + final int limit = in.limit(); + int contentLen = in.readRawVarint32(); + in.limit(in.position() + contentLen + 1); + T result = super.convertFrom(in); + in.limit(limit); + return result; + } + } + @Override protected void initForEachDeMember(ConvertFactory factory, DeMember member) { if (member.getIndex() < 1) { @@ -30,19 +45,6 @@ public class ProtobufObjectDecoder extends ObjectDecoder { setTag(member, ProtobufFactory.getTag(attr.field(), attr.genericType(), member.getPosition(), enumtostring)); } - @Override - protected ProtobufReader objectReader(ProtobufReader in) { - if (in.position() > in.initoffset) { - return new ProtobufReader(in.readByteArray()); - } - return in; - } - - @Override - protected boolean hasNext(ProtobufReader in, boolean first) { - return in.hasNext(); - } - @Override protected Object readDeMemberValue(ProtobufReader in, DeMember member, boolean first) { Decodeable decoder = member.getDecoder(); @@ -62,4 +64,5 @@ public class ProtobufObjectDecoder extends ObjectDecoder { member.read(in, result); } } + } diff --git a/src/main/java/org/redkale/convert/pb/ProtobufReader.java b/src/main/java/org/redkale/convert/pb/ProtobufReader.java index ac8c2c808..151678017 100644 --- a/src/main/java/org/redkale/convert/pb/ProtobufReader.java +++ b/src/main/java/org/redkale/convert/pb/ProtobufReader.java @@ -16,9 +16,11 @@ public class ProtobufReader extends Reader { protected int position = -1; - protected int initoffset; + protected byte[] content; - private byte[] content; + //protected int initoffset; + + protected int limit; protected int cacheTag = Integer.MIN_VALUE; @@ -49,7 +51,8 @@ public class ProtobufReader extends Reader { public final void setBytes(byte[] bytes) { if (bytes == null) { this.position = 0; - this.initoffset = 0; + //this.initoffset = 0; + this.limit = 0; } else { setBytes(bytes, 0, bytes.length); } @@ -58,17 +61,28 @@ public class ProtobufReader extends Reader { public final void setBytes(byte[] bytes, int start, int len) { if (bytes == null) { this.position = 0; - this.initoffset = 0; + //this.initoffset = 0; + this.limit = 0; } else { this.content = bytes; this.position = start - 1; - this.initoffset = this.position; + this.limit = start + len; + //this.initoffset = this.position; } } + public void limit(int limit) { + this.limit = limit; + } + + public int limit() { + return this.limit; + } + protected boolean recycle() { this.position = -1; - this.initoffset = -1; + this.limit = -1; + //this.initoffset = -1; this.content = null; return true; } @@ -78,11 +92,12 @@ public class ProtobufReader extends Reader { return this; } + // 通常用于尾部解析 public byte[] remainBytes() { - if (this.position >= this.content.length) { + if (this.position >= this.limit) { return new byte[0]; } - return Arrays.copyOfRange(this.content, this.position + 1, this.content.length); + return Arrays.copyOfRange(this.content, this.position + 1, this.limit); } /** 跳过属性的值 */ @@ -113,7 +128,7 @@ public class ProtobufReader extends Reader { @Override public final String readObjectB(final Class clazz) { - return (this.position + 1) < this.content.length ? "" : null; + return (this.position + 1) < this.limit ? "" : null; } @Override @@ -159,13 +174,6 @@ public class ProtobufReader extends Reader { return this.position; } - public final int readMemberContentLength(DeMember member, Decodeable decoder) { - if (member == null && decoder == null) { - return -1; // 为byte[] - } - return member != null ? -1 : readRawVarint32(); // readUInt32 - } - @Override public final DeMember readFieldName(final DeMemberInfo memberInfo) { int tag = readTag(); @@ -452,6 +460,18 @@ public class ProtobufReader extends Reader { return val; } + public boolean readNextTag(DeMember member) { + if (!hasNext()) { + return false; + } + int tag = readTag(); + if (tag != member.getTag()) { // 元素结束 + backTag(tag); + return false; + } + return true; + } + protected final int readTag() { if (cacheTag != Integer.MIN_VALUE) { int tag = cacheTag; @@ -471,22 +491,7 @@ public class ProtobufReader extends Reader { @Override public boolean hasNext() { - return (this.position + 1) < this.content.length; - } - - /** - * 判断对象是否存在下一个属性或者数组是否存在下一个元素 - * - * @param startPosition 起始位置 - * @param contentLength 内容大小, 不确定的传-1 - * @return 是否存在 - */ - public boolean hasNext(int startPosition, int contentLength) { - // ("-------------: " + startPosition + ", " + contentLength + ", " + this.position); - if (startPosition >= 0 && contentLength >= 0) { - return (this.position) < (startPosition + contentLength); - } - return (this.position + 1) < this.content.length; + return (this.position + 1) < this.limit; } @Override @@ -503,7 +508,7 @@ public class ProtobufReader extends Reader { fastpath: { int curr = this.position; - if ((curr + 1) == data.length) { + if ((curr + 1) == limit) { break fastpath; } @@ -511,7 +516,7 @@ public class ProtobufReader extends Reader { if ((x = data[++curr]) >= 0) { this.position = curr; return x; - } else if (data.length - (curr + 1) < 9) { + } else if (limit - (curr + 1) < 9) { break fastpath; } else if ((x ^= (data[++curr] << 7)) < 0) { x ^= (~0 << 7); @@ -543,7 +548,7 @@ public class ProtobufReader extends Reader { fastpath: { int curr = this.position; - if ((curr + 1) == data.length) { + if ((curr + 1) == this.limit) { break fastpath; } @@ -552,7 +557,7 @@ public class ProtobufReader extends Reader { if ((y = data[++curr]) >= 0) { this.position = curr; return y; - } else if (data.length - (curr + 1) < 9) { + } else if (this.limit - (curr + 1) < 9) { break fastpath; } else if ((y ^= (data[++curr] << 7)) < 0) { x = y ^ (~0 << 7); diff --git a/src/main/java/org/redkale/convert/pb/ProtobufStreamDecoder.java b/src/main/java/org/redkale/convert/pb/ProtobufStreamDecoder.java index 3bbec0285..fc694c134 100644 --- a/src/main/java/org/redkale/convert/pb/ProtobufStreamDecoder.java +++ b/src/main/java/org/redkale/convert/pb/ProtobufStreamDecoder.java @@ -26,25 +26,23 @@ public class ProtobufStreamDecoder extends StreamDecoder { @Override public Stream convertFrom(ProtobufReader in, DeMember member) { this.checkInited(); + final boolean simpled = !this.componentSimpled; final Decodeable itemDecoder = this.componentDecoder; in.readArrayB(member, itemDecoder); - int contentLength = in.readMemberContentLength(member, itemDecoder); final List result = new ArrayList(); - boolean first = true; - int startPosition = in.position(); - while (in.hasNext(startPosition, contentLength)) { - ProtobufReader itemReader = getItemReader(in, member, first); - if (itemReader == null) { // 元素读取完毕 + final int limit = in.limit(); + while (in.hasNext()) { + if (!simpled) { + int contentLen = in.readRawVarint32(); + in.limit(in.position() + contentLen + 1); + } + result.add(itemDecoder.convertFrom(in)); + in.limit(limit); + if (!in.readNextTag(member)) { // 元素结束 break; } - result.add(itemDecoder.convertFrom(itemReader)); - first = false; } in.readArrayE(); return result.stream(); } - - protected ProtobufReader getItemReader(ProtobufReader in, DeMember member, boolean first) { - return ProtobufFactory.getItemReader(in, member, componentSimpled, first); - } } diff --git a/src/main/java/org/redkale/util/Utility.java b/src/main/java/org/redkale/util/Utility.java index 81e8d69ca..9701cbb68 100644 --- a/src/main/java/org/redkale/util/Utility.java +++ b/src/main/java/org/redkale/util/Utility.java @@ -3562,6 +3562,18 @@ public final class Utility { * @param bytes 字节数组 */ public static void println(String string, byte... bytes) { + println(string, bytes, 0, bytes.length); + } + + /** + * 将字节数组的内容转换成字符串并打印到控制台, string参数不为空时会追加在字节数组内容字符串之前 + * + * @param string 字符串前缀 + * @param bytes 字节数组 + * @param start 起始位置 + * @param len 长度 + */ + public static void println(String string, byte[] bytes, int start, int len) { if (bytes == null) { return; } @@ -3569,9 +3581,10 @@ public final class Utility { if (string != null) { sb.append(string); } - sb.append(bytes.length).append(".["); + sb.append(len).append(".["); boolean last = false; - for (byte b : bytes) { + for (int i = 0; i < len; i++) { + byte b = bytes[start + i]; if (last) { sb.append(','); }