deployed 2.0.5.RELEASE,修复集合类型长度域BUG

master
剑器近 2021-09-19 16:00:16 +08:00
parent b7a938ff4a
commit 44050e72ce
11 changed files with 154 additions and 82 deletions

View File

@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>io.github.yezhihao</groupId> <groupId>io.github.yezhihao</groupId>
<artifactId>protostar</artifactId> <artifactId>protostar</artifactId>
<version>2.0.4.RELEASE</version> <version>2.0.5.RELEASE</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>Protostar</name> <name>Protostar</name>

View File

@ -1,10 +1,7 @@
package io.github.yezhihao.protostar; package io.github.yezhihao.protostar;
import io.github.yezhihao.protostar.annotation.Field; import io.github.yezhihao.protostar.annotation.Field;
import io.github.yezhihao.protostar.field.BasicField; import io.github.yezhihao.protostar.field.*;
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.schema.*; import io.github.yezhihao.protostar.schema.*;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@ -65,7 +62,7 @@ public abstract class FieldFactory {
fieldSchema = ConvertSchema.getInstance(field.converter()); fieldSchema = ConvertSchema.getInstance(field.converter());
break; break;
case LIST: case LIST:
fieldSchema = CollectionSchema.getInstance(schema, field.lengthSize()); fieldSchema = CollectionSchema.getInstance(schema);
break; break;
case MAP: case MAP:
fieldSchema = ConvertSchema.getInstance(field.converter()); fieldSchema = ConvertSchema.getInstance(field.converter());
@ -78,15 +75,21 @@ public abstract class FieldFactory {
BasicField result; BasicField result;
if (EXPLAIN) { if (EXPLAIN) {
if (field.lengthSize() > 0) { 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) { } else if (field.length() > 0) {
result = new FixedLengthField.Logger(field, f, fieldSchema); result = new FixedLengthField.Logger(field, f, fieldSchema);
} else { } else {
result = new FixedField.Logger(field, f, fieldSchema); result = new FixedField.Logger(field, f, fieldSchema);
} }
} else { } else {
if (field.lengthSize() > 0 && !(fieldSchema instanceof CollectionSchema)) { if (field.lengthSize() > 0) {
result = new DynamicLengthField(field, f, fieldSchema); if (fieldSchema instanceof CollectionSchema)
result = new DynamicTotalField(field, f, fieldSchema);
else
result = new DynamicLengthField(field, f, fieldSchema);
} else if (field.length() > 0) { } else if (field.length() > 0) {
result = new FixedLengthField(field, f, fieldSchema); result = new FixedLengthField(field, f, fieldSchema);
} else { } else {

View File

@ -70,10 +70,10 @@ public abstract class MapConverter<K, V> extends PrepareLoadStrategy implements
if (schema != null) { if (schema != null) {
int lengthSize = valueSize(); int lengthSize = valueSize();
int begin = output.writerIndex(); int begin = output.writerIndex();
output.writeBytes(ByteBufUtils.BLOCKS[lengthSize]); ByteBufUtils.writeInt(output, lengthSize, 0);
schema.writeTo(output, value); schema.writeTo(output, value);
int length = output.writerIndex() - begin - lengthSize; int length = output.writerIndex() - begin - lengthSize;
ByteBufUtils.setInt(output, lengthSize, begin, length); ByteBufUtils.setInt(output, begin, lengthSize, length);
} else { } else {
log.warn("未注册的信息:ID[{}], VALUE[{}]", key, value); log.warn("未注册的信息:ID[{}], VALUE[{}]", key, value);
} }

View File

@ -30,9 +30,9 @@ public abstract class BasicField<T> implements Comparable<BasicField<T>> {
} }
} }
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) { public void println(int index, String desc, String hex, Object value) {
if (value != null) if (value != null)

View File

@ -13,11 +13,11 @@ import io.netty.buffer.ByteBufUtil;
*/ */
public class DynamicLengthField<T> extends BasicField<T> { public class DynamicLengthField<T> extends BasicField<T> {
protected final Schema<T> schema; protected final Schema schema;
protected final int lengthSize; protected final int lengthSize;
public DynamicLengthField(Field field, java.lang.reflect.Field f, Schema<T> schema) { public DynamicLengthField(Field field, java.lang.reflect.Field f, Schema schema) {
super(field, f); super(field, f);
this.schema = schema; this.schema = schema;
this.lengthSize = field.lengthSize(); this.lengthSize = field.lengthSize();
@ -36,10 +36,10 @@ public class DynamicLengthField<T> extends BasicField<T> {
Object value = f.get(message); Object value = f.get(message);
if (value != null) { if (value != null) {
int begin = output.writerIndex(); int begin = output.writerIndex();
output.writeBytes(ByteBufUtils.BLOCKS[lengthSize]); ByteBufUtils.writeInt(output, lengthSize, 0);
schema.writeTo(output, (T) value); schema.writeTo(output, value);
int length = output.writerIndex() - begin - lengthSize; 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<T> extends BasicField<T> {
Object value = f.get(message); Object value = f.get(message);
if (value != null) { if (value != null) {
int begin = output.writerIndex(); int begin = output.writerIndex();
output.writeBytes(ByteBufUtils.BLOCKS[lengthSize]); ByteBufUtils.writeInt(output, lengthSize, 0);
schema.writeTo(output, (T) value); schema.writeTo(output, value);
int length = output.writerIndex() - begin - lengthSize; int length = output.writerIndex() - begin - lengthSize;
ByteBufUtils.setInt(output, lengthSize, begin, length); ByteBufUtils.setInt(output, begin, lengthSize, length);
} }
int after = output.writerIndex(); int after = output.writerIndex();

View File

@ -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<T> extends BasicField<T> {
protected final Schema<Collection<?>> 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<T> that) {
int r = Integer.compare(this.index, that.index);
if (r == 0)
r = (that instanceof DynamicTotalField) ? 1 : -1;
return r;
}
public static class Logger<T> extends DynamicTotalField<T> {
public Logger(Field field, java.lang.reflect.Field f, Schema<T> 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);
}
}
}
}

View File

@ -12,9 +12,9 @@ import io.netty.buffer.ByteBufUtil;
*/ */
public class FixedField<T> extends BasicField<T> { public class FixedField<T> extends BasicField<T> {
protected final Schema<T> schema; protected final Schema schema;
public FixedField(Field field, java.lang.reflect.Field f, Schema<T> schema) { public FixedField(Field field, java.lang.reflect.Field f, Schema schema) {
super(field, f); super(field, f);
this.schema = schema; this.schema = schema;
} }
@ -28,7 +28,7 @@ public class FixedField<T> extends BasicField<T> {
public void writeTo(ByteBuf output, Object message) throws Exception { public void writeTo(ByteBuf output, Object message) throws Exception {
Object value = f.get(message); Object value = f.get(message);
if (value != null) if (value != null)
schema.writeTo(output, (T) value); schema.writeTo(output, value);
} }
public static class Logger<T> extends FixedField<T> { public static class Logger<T> extends FixedField<T> {
@ -54,7 +54,7 @@ public class FixedField<T> extends BasicField<T> {
Object value = f.get(message); Object value = f.get(message);
if (value != null) if (value != null)
schema.writeTo(output, (T) value); schema.writeTo(output, value);
int after = output.writerIndex(); int after = output.writerIndex();
String hex = ByteBufUtil.hexDump(output.slice(before, after - before)); String hex = ByteBufUtil.hexDump(output.slice(before, after - before));

View File

@ -12,7 +12,7 @@ import io.netty.buffer.ByteBufUtil;
*/ */
public class FixedLengthField<T> extends BasicField<T> { public class FixedLengthField<T> extends BasicField<T> {
protected final Schema<T> schema; protected final Schema schema;
public FixedLengthField(Field field, java.lang.reflect.Field f, Schema<T> schema) { public FixedLengthField(Field field, java.lang.reflect.Field f, Schema<T> schema) {
super(field, f); super(field, f);
@ -28,7 +28,7 @@ public class FixedLengthField<T> extends BasicField<T> {
public void writeTo(ByteBuf output, Object message) throws Exception { public void writeTo(ByteBuf output, Object message) throws Exception {
Object value = f.get(message); Object value = f.get(message);
if (value != null) if (value != null)
schema.writeTo(output, length, (T) value); schema.writeTo(output, length, value);
} }
public static class Logger<T> extends FixedLengthField<T> { public static class Logger<T> extends FixedLengthField<T> {
@ -54,7 +54,7 @@ public class FixedLengthField<T> extends BasicField<T> {
Object value = f.get(message); Object value = f.get(message);
if (value != null) if (value != null)
schema.writeTo(output, length, (T) value); schema.writeTo(output, length, value);
int after = output.writerIndex(); int after = output.writerIndex();
String hex = ByteBufUtil.hexDump(output.slice(before, after - before)); String hex = ByteBufUtil.hexDump(output.slice(before, after - before));

View File

@ -6,77 +6,64 @@ import io.github.yezhihao.protostar.util.Cache;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.Collection;
public class CollectionSchema<T> implements Schema<List<T>> { public class CollectionSchema<T> implements Schema<Collection<T>> {
private static final Cache<String, CollectionSchema> CACHE = new Cache<>(); private static final Cache<Schema, CollectionSchema> CACHE = new Cache<>();
public static CollectionSchema getInstance(Schema schema, int lengthSize) { public static CollectionSchema getInstance(Schema schema) {
return CACHE.get(schema.hashCode() + "_" + lengthSize, key -> new CollectionSchema(schema, lengthSize)); return CACHE.get(schema, key -> new CollectionSchema(key));
} }
private final Schema<T> schema; private final Schema<T> schema;
private final int lengthSize; private CollectionSchema(Schema<T> schema) {
private CollectionSchema(Schema<T> schema, int lengthSize) {
this.schema = schema; this.schema = schema;
this.lengthSize = lengthSize;
} }
@Override @Override
public List<T> readFrom(ByteBuf input) { public Collection<T> readFrom(ByteBuf input) {
if (!input.isReadable()) if (!input.isReadable())
return null; return null;
List<T> list; Collection<T> list = new ArrayList<>(2);
if (lengthSize > 0) { do {
int length = ByteBufUtils.readInt(input, lengthSize); T obj = schema.readFrom(input);
list = new ArrayList<>(length); if (obj == null) break;
for (int i = 0; i < length; i++) { list.add(obj);
T obj = schema.readFrom(input); } while (input.isReadable());
if (obj == null) break; return list;
list.add(obj); }
}
} else { @Override
list = new ArrayList<>(2); public Collection<T> readFrom(ByteBuf input, int totalSize) {
do { int total = ByteBufUtils.readInt(input, totalSize);
T obj = schema.readFrom(input); Collection<T> list = new ArrayList<>(total);
if (obj == null) break; for (int i = 0; i < total; i++) {
list.add(obj); T obj = schema.readFrom(input);
} while (input.isReadable()); list.add(obj);
} }
return list; return list;
} }
@Override @Override
public List<T> readFrom(ByteBuf input, int length) { public void writeTo(ByteBuf output, Collection<T> list) {
int writerIndex = input.writerIndex();
input.writerIndex(input.readerIndex() + length);
List<T> result = this.readFrom(input);
input.writerIndex(writerIndex);
return result;
}
@Override
public void writeTo(ByteBuf output, List<T> list) {
if (list == null || list.isEmpty()) if (list == null || list.isEmpty())
return; return;
if (lengthSize > 0)
ByteBufUtils.writeInt(output, lengthSize, list.size());
for (T obj : list) { for (T obj : list) {
schema.writeTo(output, obj); schema.writeTo(output, obj);
} }
} }
@Override @Override
public void writeTo(ByteBuf output, int length, List<T> list) { public void writeTo(ByteBuf output, int totalSize, Collection<T> list) {
if (list == null || list.isEmpty()) if (list == null || list.isEmpty())
return; return;
ByteBufUtils.writeInt(output, totalSize, list.size());
for (T obj : list) { for (T obj : list) {
schema.writeTo(output, length, obj); schema.writeTo(output, totalSize, obj);
} }
} }
} }

View File

@ -9,13 +9,6 @@ import io.netty.buffer.ByteBuf;
*/ */
public class ByteBufUtils { 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) { public static int readInt(ByteBuf input, int length) {
int value; int value;
switch (length) { 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; int value;
switch (length) { switch (length) {
case 1: case 1:
value = output.getUnsignedByte(index); value = input.getUnsignedByte(index);
break; break;
case 2: case 2:
value = output.getUnsignedShort(index); value = input.getUnsignedShort(index);
break; break;
case 3: case 3:
value = output.getUnsignedMedium(index); value = input.getUnsignedMedium(index);
break; break;
case 4: case 4:
value = output.getInt(index); value = input.getInt(index);
break; break;
default: default:
throw new RuntimeException("unsupported length: " + length + " (expected: 1, 2, 3, 4)"); throw new RuntimeException("unsupported length: " + length + " (expected: 1, 2, 3, 4)");
@ -77,7 +70,7 @@ public class ByteBufUtils {
return value; 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) { switch (length) {
case 1: case 1:
output.setByte(index, value); output.setByte(index, value);

View File

@ -90,4 +90,17 @@ public class StrUtils {
return false; return false;
return componentType.isArray(); 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;
}
} }