diff --git a/pom.xml b/pom.xml index 8cba8cd..330f944 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 io.github.yezhihao protostar - 2.0.4.RELEASE + 2.0.5.RELEASE jar Protostar diff --git a/src/main/java/io/github/yezhihao/protostar/FieldFactory.java b/src/main/java/io/github/yezhihao/protostar/FieldFactory.java index c9a8511..2e9647d 100644 --- a/src/main/java/io/github/yezhihao/protostar/FieldFactory.java +++ b/src/main/java/io/github/yezhihao/protostar/FieldFactory.java @@ -1,10 +1,7 @@ package io.github.yezhihao.protostar; import io.github.yezhihao.protostar.annotation.Field; -import io.github.yezhihao.protostar.field.BasicField; -import io.github.yezhihao.protostar.field.DynamicLengthField; -import io.github.yezhihao.protostar.field.FixedField; -import io.github.yezhihao.protostar.field.FixedLengthField; +import io.github.yezhihao.protostar.field.*; import io.github.yezhihao.protostar.schema.*; import java.nio.ByteBuffer; @@ -65,7 +62,7 @@ public abstract class FieldFactory { fieldSchema = ConvertSchema.getInstance(field.converter()); break; case LIST: - fieldSchema = CollectionSchema.getInstance(schema, field.lengthSize()); + fieldSchema = CollectionSchema.getInstance(schema); break; case MAP: fieldSchema = ConvertSchema.getInstance(field.converter()); @@ -78,15 +75,21 @@ public abstract class FieldFactory { BasicField result; if (EXPLAIN) { if (field.lengthSize() > 0) { - result = new DynamicLengthField.Logger(field, f, fieldSchema); + if (fieldSchema instanceof CollectionSchema) + result = new DynamicTotalField.Logger(field, f, fieldSchema); + else + result = new DynamicLengthField.Logger(field, f, fieldSchema); } else if (field.length() > 0) { result = new FixedLengthField.Logger(field, f, fieldSchema); } else { result = new FixedField.Logger(field, f, fieldSchema); } } else { - if (field.lengthSize() > 0 && !(fieldSchema instanceof CollectionSchema)) { - result = new DynamicLengthField(field, f, fieldSchema); + if (field.lengthSize() > 0) { + if (fieldSchema instanceof CollectionSchema) + result = new DynamicTotalField(field, f, fieldSchema); + else + result = new DynamicLengthField(field, f, fieldSchema); } else if (field.length() > 0) { result = new FixedLengthField(field, f, fieldSchema); } else { diff --git a/src/main/java/io/github/yezhihao/protostar/converter/MapConverter.java b/src/main/java/io/github/yezhihao/protostar/converter/MapConverter.java index 73816a9..59bb9e4 100644 --- a/src/main/java/io/github/yezhihao/protostar/converter/MapConverter.java +++ b/src/main/java/io/github/yezhihao/protostar/converter/MapConverter.java @@ -70,10 +70,10 @@ public abstract class MapConverter extends PrepareLoadStrategy implements if (schema != null) { int lengthSize = valueSize(); int begin = output.writerIndex(); - output.writeBytes(ByteBufUtils.BLOCKS[lengthSize]); + ByteBufUtils.writeInt(output, lengthSize, 0); schema.writeTo(output, value); int length = output.writerIndex() - begin - lengthSize; - ByteBufUtils.setInt(output, lengthSize, begin, length); + ByteBufUtils.setInt(output, begin, lengthSize, length); } else { log.warn("未注册的信息:ID[{}], VALUE[{}]", key, value); } diff --git a/src/main/java/io/github/yezhihao/protostar/field/BasicField.java b/src/main/java/io/github/yezhihao/protostar/field/BasicField.java index 2de58e5..deb2886 100644 --- a/src/main/java/io/github/yezhihao/protostar/field/BasicField.java +++ b/src/main/java/io/github/yezhihao/protostar/field/BasicField.java @@ -30,9 +30,9 @@ public abstract class BasicField implements Comparable> { } } - public abstract boolean readFrom(ByteBuf input, Object message) throws Exception; + public abstract boolean readFrom(ByteBuf input, T message) throws Exception; - public abstract void writeTo(ByteBuf output, Object message) throws Exception; + public abstract void writeTo(ByteBuf output, T message) throws Exception; public void println(int index, String desc, String hex, Object value) { if (value != null) diff --git a/src/main/java/io/github/yezhihao/protostar/field/DynamicLengthField.java b/src/main/java/io/github/yezhihao/protostar/field/DynamicLengthField.java index 998b629..afc7473 100644 --- a/src/main/java/io/github/yezhihao/protostar/field/DynamicLengthField.java +++ b/src/main/java/io/github/yezhihao/protostar/field/DynamicLengthField.java @@ -13,11 +13,11 @@ import io.netty.buffer.ByteBufUtil; */ public class DynamicLengthField extends BasicField { - protected final Schema schema; + protected final Schema schema; protected final int lengthSize; - public DynamicLengthField(Field field, java.lang.reflect.Field f, Schema schema) { + public DynamicLengthField(Field field, java.lang.reflect.Field f, Schema schema) { super(field, f); this.schema = schema; this.lengthSize = field.lengthSize(); @@ -36,10 +36,10 @@ public class DynamicLengthField extends BasicField { Object value = f.get(message); if (value != null) { int begin = output.writerIndex(); - output.writeBytes(ByteBufUtils.BLOCKS[lengthSize]); - schema.writeTo(output, (T) value); + ByteBufUtils.writeInt(output, lengthSize, 0); + schema.writeTo(output, value); int length = output.writerIndex() - begin - lengthSize; - ByteBufUtils.setInt(output, lengthSize, begin, length); + ByteBufUtils.setInt(output, begin, lengthSize, length); } } @@ -78,10 +78,10 @@ public class DynamicLengthField extends BasicField { Object value = f.get(message); if (value != null) { int begin = output.writerIndex(); - output.writeBytes(ByteBufUtils.BLOCKS[lengthSize]); - schema.writeTo(output, (T) value); + ByteBufUtils.writeInt(output, lengthSize, 0); + schema.writeTo(output, value); int length = output.writerIndex() - begin - lengthSize; - ByteBufUtils.setInt(output, lengthSize, begin, length); + ByteBufUtils.setInt(output, begin, lengthSize, length); } int after = output.writerIndex(); diff --git a/src/main/java/io/github/yezhihao/protostar/field/DynamicTotalField.java b/src/main/java/io/github/yezhihao/protostar/field/DynamicTotalField.java new file mode 100644 index 0000000..2ebbdf2 --- /dev/null +++ b/src/main/java/io/github/yezhihao/protostar/field/DynamicTotalField.java @@ -0,0 +1,76 @@ +package io.github.yezhihao.protostar.field; + +import io.github.yezhihao.protostar.Schema; +import io.github.yezhihao.protostar.annotation.Field; +import io.github.yezhihao.protostar.util.ByteBufUtils; +import io.github.yezhihao.protostar.util.StrUtils; +import io.netty.buffer.ByteBuf; + +import java.util.Collection; + +/** + * 动态长度的字段 + * @author yezhihao + * home https://gitee.com/yezhihao/jt808-server + */ +public class DynamicTotalField extends BasicField { + + protected final Schema> schema; + + protected final int totalSize; + + public DynamicTotalField(Field field, java.lang.reflect.Field f, Schema schema) { + super(field, f); + this.schema = schema; + this.totalSize = field.lengthSize(); + } + + public boolean readFrom(ByteBuf input, Object message) throws Exception { + Object value = schema.readFrom(input, totalSize); + f.set(message, value); + return true; + } + + public void writeTo(ByteBuf output, Object message) throws Exception { + Collection value = (Collection) f.get(message); + if (value != null) + schema.writeTo(output, totalSize, value); + } + + @Override + public int compareTo(BasicField that) { + int r = Integer.compare(this.index, that.index); + if (r == 0) + r = (that instanceof DynamicTotalField) ? 1 : -1; + return r; + } + + public static class Logger extends DynamicTotalField { + + public Logger(Field field, java.lang.reflect.Field f, Schema schema) { + super(field, f, schema); + } + + public boolean readFrom(ByteBuf input, Object message) throws Exception { + int total = ByteBufUtils.getInt(input, input.readerIndex(), totalSize); + String hex = StrUtils.leftPad(Integer.toHexString(total), totalSize << 1, '0'); + println(this.index, this.field.desc() + "总数", hex, total); + + Collection value = schema.readFrom(input, totalSize); + f.set(message, value); + return true; + } + + public void writeTo(ByteBuf output, Object message) throws Exception { + Collection value = (Collection) f.get(message); + if (value != null) { + + int total = value.size(); + String hex = StrUtils.leftPad(Integer.toHexString(total), totalSize << 1, '0'); + println(this.index, this.field.desc() + "总数", hex, total); + + schema.writeTo(output, totalSize, value); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/io/github/yezhihao/protostar/field/FixedField.java b/src/main/java/io/github/yezhihao/protostar/field/FixedField.java index cc21653..2010266 100644 --- a/src/main/java/io/github/yezhihao/protostar/field/FixedField.java +++ b/src/main/java/io/github/yezhihao/protostar/field/FixedField.java @@ -12,9 +12,9 @@ import io.netty.buffer.ByteBufUtil; */ public class FixedField extends BasicField { - protected final Schema schema; + protected final Schema schema; - public FixedField(Field field, java.lang.reflect.Field f, Schema schema) { + public FixedField(Field field, java.lang.reflect.Field f, Schema schema) { super(field, f); this.schema = schema; } @@ -28,7 +28,7 @@ public class FixedField extends BasicField { public void writeTo(ByteBuf output, Object message) throws Exception { Object value = f.get(message); if (value != null) - schema.writeTo(output, (T) value); + schema.writeTo(output, value); } public static class Logger extends FixedField { @@ -54,7 +54,7 @@ public class FixedField extends BasicField { Object value = f.get(message); if (value != null) - schema.writeTo(output, (T) value); + schema.writeTo(output, value); int after = output.writerIndex(); String hex = ByteBufUtil.hexDump(output.slice(before, after - before)); diff --git a/src/main/java/io/github/yezhihao/protostar/field/FixedLengthField.java b/src/main/java/io/github/yezhihao/protostar/field/FixedLengthField.java index 17fe6d5..e9ac309 100644 --- a/src/main/java/io/github/yezhihao/protostar/field/FixedLengthField.java +++ b/src/main/java/io/github/yezhihao/protostar/field/FixedLengthField.java @@ -12,7 +12,7 @@ import io.netty.buffer.ByteBufUtil; */ public class FixedLengthField extends BasicField { - protected final Schema schema; + protected final Schema schema; public FixedLengthField(Field field, java.lang.reflect.Field f, Schema schema) { super(field, f); @@ -28,7 +28,7 @@ public class FixedLengthField extends BasicField { public void writeTo(ByteBuf output, Object message) throws Exception { Object value = f.get(message); if (value != null) - schema.writeTo(output, length, (T) value); + schema.writeTo(output, length, value); } public static class Logger extends FixedLengthField { @@ -54,7 +54,7 @@ public class FixedLengthField extends BasicField { Object value = f.get(message); if (value != null) - schema.writeTo(output, length, (T) value); + schema.writeTo(output, length, value); int after = output.writerIndex(); String hex = ByteBufUtil.hexDump(output.slice(before, after - before)); diff --git a/src/main/java/io/github/yezhihao/protostar/schema/CollectionSchema.java b/src/main/java/io/github/yezhihao/protostar/schema/CollectionSchema.java index 69cc063..71771c2 100644 --- a/src/main/java/io/github/yezhihao/protostar/schema/CollectionSchema.java +++ b/src/main/java/io/github/yezhihao/protostar/schema/CollectionSchema.java @@ -6,77 +6,64 @@ import io.github.yezhihao.protostar.util.Cache; import io.netty.buffer.ByteBuf; import java.util.ArrayList; -import java.util.List; +import java.util.Collection; -public class CollectionSchema implements Schema> { +public class CollectionSchema implements Schema> { - private static final Cache CACHE = new Cache<>(); + private static final Cache CACHE = new Cache<>(); - public static CollectionSchema getInstance(Schema schema, int lengthSize) { - return CACHE.get(schema.hashCode() + "_" + lengthSize, key -> new CollectionSchema(schema, lengthSize)); + public static CollectionSchema getInstance(Schema schema) { + return CACHE.get(schema, key -> new CollectionSchema(key)); } private final Schema schema; - private final int lengthSize; - - private CollectionSchema(Schema schema, int lengthSize) { + private CollectionSchema(Schema schema) { this.schema = schema; - this.lengthSize = lengthSize; } @Override - public List readFrom(ByteBuf input) { + public Collection readFrom(ByteBuf input) { if (!input.isReadable()) return null; - List list; - if (lengthSize > 0) { - int length = ByteBufUtils.readInt(input, lengthSize); - list = new ArrayList<>(length); - for (int i = 0; i < length; i++) { - T obj = schema.readFrom(input); - if (obj == null) break; - list.add(obj); - } - } else { - list = new ArrayList<>(2); - do { - T obj = schema.readFrom(input); - if (obj == null) break; - list.add(obj); - } while (input.isReadable()); + Collection list = new ArrayList<>(2); + do { + T obj = schema.readFrom(input); + if (obj == null) break; + list.add(obj); + } while (input.isReadable()); + return list; + } + + @Override + public Collection readFrom(ByteBuf input, int totalSize) { + int total = ByteBufUtils.readInt(input, totalSize); + Collection list = new ArrayList<>(total); + for (int i = 0; i < total; i++) { + T obj = schema.readFrom(input); + list.add(obj); } return list; } - @Override - public List readFrom(ByteBuf input, int length) { - int writerIndex = input.writerIndex(); - input.writerIndex(input.readerIndex() + length); - List result = this.readFrom(input); - input.writerIndex(writerIndex); - return result; - } - - @Override - public void writeTo(ByteBuf output, List list) { + public void writeTo(ByteBuf output, Collection list) { if (list == null || list.isEmpty()) return; - if (lengthSize > 0) - ByteBufUtils.writeInt(output, lengthSize, list.size()); + for (T obj : list) { schema.writeTo(output, obj); } } @Override - public void writeTo(ByteBuf output, int length, List list) { + public void writeTo(ByteBuf output, int totalSize, Collection list) { if (list == null || list.isEmpty()) return; + ByteBufUtils.writeInt(output, totalSize, list.size()); for (T obj : list) { - schema.writeTo(output, length, obj); + schema.writeTo(output, totalSize, obj); } } } \ No newline at end of file diff --git a/src/main/java/io/github/yezhihao/protostar/util/ByteBufUtils.java b/src/main/java/io/github/yezhihao/protostar/util/ByteBufUtils.java index 4080eae..92f9185 100644 --- a/src/main/java/io/github/yezhihao/protostar/util/ByteBufUtils.java +++ b/src/main/java/io/github/yezhihao/protostar/util/ByteBufUtils.java @@ -9,13 +9,6 @@ import io.netty.buffer.ByteBuf; */ public class ByteBufUtils { - /** 长度域占位数据块 */ - public static final byte[][] BLOCKS = new byte[][]{ - new byte[0], - new byte[1], new byte[2], - new byte[3], new byte[4]}; - - public static int readInt(ByteBuf input, int length) { int value; switch (length) { @@ -56,20 +49,20 @@ public class ByteBufUtils { } } - public static int getInt(ByteBuf output, int length, int index) { + public static int getInt(ByteBuf input, int index, int length) { int value; switch (length) { case 1: - value = output.getUnsignedByte(index); + value = input.getUnsignedByte(index); break; case 2: - value = output.getUnsignedShort(index); + value = input.getUnsignedShort(index); break; case 3: - value = output.getUnsignedMedium(index); + value = input.getUnsignedMedium(index); break; case 4: - value = output.getInt(index); + value = input.getInt(index); break; default: throw new RuntimeException("unsupported length: " + length + " (expected: 1, 2, 3, 4)"); @@ -77,7 +70,7 @@ public class ByteBufUtils { return value; } - public static void setInt(ByteBuf output, int length, int index, int value) { + public static void setInt(ByteBuf output, int index, int length, int value) { switch (length) { case 1: output.setByte(index, value); diff --git a/src/main/java/io/github/yezhihao/protostar/util/StrUtils.java b/src/main/java/io/github/yezhihao/protostar/util/StrUtils.java index c8408e5..119ce26 100644 --- a/src/main/java/io/github/yezhihao/protostar/util/StrUtils.java +++ b/src/main/java/io/github/yezhihao/protostar/util/StrUtils.java @@ -90,4 +90,17 @@ public class StrUtils { return false; return componentType.isArray(); } + + public static String leftPad(String str, int size, char ch) { + int length = str.length(); + int pads = size - length; + if (pads > 0) { + char[] result = new char[size]; + str.getChars(0, length, result, pads); + while (pads > 0) + result[--pads] = ch; + return new String(result); + } + return str; + } } \ No newline at end of file