deployed 2.0.5.RELEASE,修复集合类型长度域BUG
parent
b7a938ff4a
commit
44050e72ce
2
pom.xml
2
pom.xml
|
@ -3,7 +3,7 @@
|
|||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>io.github.yezhihao</groupId>
|
||||
<artifactId>protostar</artifactId>
|
||||
<version>2.0.4.RELEASE</version>
|
||||
<version>2.0.5.RELEASE</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Protostar</name>
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -70,10 +70,10 @@ public abstract class MapConverter<K, V> 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);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
if (value != null)
|
||||
|
|
|
@ -13,11 +13,11 @@ import io.netty.buffer.ByteBufUtil;
|
|||
*/
|
||||
public class DynamicLengthField<T> extends BasicField<T> {
|
||||
|
||||
protected final Schema<T> schema;
|
||||
protected final Schema schema;
|
||||
|
||||
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);
|
||||
this.schema = schema;
|
||||
this.lengthSize = field.lengthSize();
|
||||
|
@ -36,10 +36,10 @@ public class DynamicLengthField<T> extends BasicField<T> {
|
|||
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<T> extends BasicField<T> {
|
|||
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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,9 +12,9 @@ import io.netty.buffer.ByteBufUtil;
|
|||
*/
|
||||
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);
|
||||
this.schema = schema;
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ public class FixedField<T> extends BasicField<T> {
|
|||
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<T> extends FixedField<T> {
|
||||
|
@ -54,7 +54,7 @@ public class FixedField<T> extends BasicField<T> {
|
|||
|
||||
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));
|
||||
|
|
|
@ -12,7 +12,7 @@ import io.netty.buffer.ByteBufUtil;
|
|||
*/
|
||||
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) {
|
||||
super(field, f);
|
||||
|
@ -28,7 +28,7 @@ public class FixedLengthField<T> extends BasicField<T> {
|
|||
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<T> extends FixedLengthField<T> {
|
||||
|
@ -54,7 +54,7 @@ public class FixedLengthField<T> extends BasicField<T> {
|
|||
|
||||
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));
|
||||
|
|
|
@ -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<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) {
|
||||
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<T> schema;
|
||||
|
||||
private final int lengthSize;
|
||||
|
||||
private CollectionSchema(Schema<T> schema, int lengthSize) {
|
||||
private CollectionSchema(Schema<T> schema) {
|
||||
this.schema = schema;
|
||||
this.lengthSize = lengthSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> readFrom(ByteBuf input) {
|
||||
public Collection<T> readFrom(ByteBuf input) {
|
||||
if (!input.isReadable())
|
||||
return null;
|
||||
List<T> 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<T> 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<T> readFrom(ByteBuf input, int totalSize) {
|
||||
int total = ByteBufUtils.readInt(input, totalSize);
|
||||
Collection<T> list = new ArrayList<>(total);
|
||||
for (int i = 0; i < total; i++) {
|
||||
T obj = schema.readFrom(input);
|
||||
list.add(obj);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<T> readFrom(ByteBuf input, int length) {
|
||||
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) {
|
||||
public void writeTo(ByteBuf output, Collection<T> 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<T> list) {
|
||||
public void writeTo(ByteBuf output, int totalSize, Collection<T> 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue