deployed 2.0.2.RELEASE,增强MapConverter,简化用户端实现。合并Convert到Field(为支持多版本Convert)

master
剑器近 2021-07-08 15:40:34 +08:00
parent 75969aa5e6
commit a2f5abb6f4
9 changed files with 66 additions and 110 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.1.RELEASE</version> <version>2.0.2.RELEASE</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>Protostar</name> <name>Protostar</name>

View File

@ -7,25 +7,25 @@ package io.github.yezhihao.protostar;
*/ */
public enum DataType { public enum DataType {
//无符号单字节整型(字节, 8位 /** 无符号单字节整型(8位) */
BYTE(1), BYTE(1),
//无符号双字节整型字节16位 /** 无符号双字节整型(16位) */
WORD(2), WORD(2),
//无符号四字节整型字节32位 /** 无符号四字节整型(32位) */
DWORD(4), DWORD(4),
//无符号八字节整型字节64位 /** 无符号八字节整型(64位) */
QWORD(8), QWORD(8),
//N字节字节数组 /** 字节数组 */
BYTES(-1), BYTES(-1),
//N字节BCD8421码 /** BCD8421码 */
BCD8421(-1), BCD8421(-1),
//字符串,若无数据置空 /** 字符串 */
STRING(-1), STRING(-1),
//对象 /** 对象 */
OBJ(-1), OBJ(-1),
//列表 /** 列表 */
LIST(-1), LIST(-1),
//字典 /** 字典 */
MAP(-1); MAP(-1);
public int length; public int length;

View File

@ -1,14 +1,11 @@
package io.github.yezhihao.protostar; package io.github.yezhihao.protostar;
import io.github.yezhihao.protostar.annotation.Convert;
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.BasicField;
import io.github.yezhihao.protostar.field.DynamicLengthField; import io.github.yezhihao.protostar.field.DynamicLengthField;
import io.github.yezhihao.protostar.field.FixedField; import io.github.yezhihao.protostar.field.FixedField;
import io.github.yezhihao.protostar.field.FixedLengthField; import io.github.yezhihao.protostar.field.FixedLengthField;
import io.github.yezhihao.protostar.schema.*; import io.github.yezhihao.protostar.schema.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@ -19,7 +16,7 @@ import java.time.LocalDateTime;
* home https://gitee.com/yezhihao/jt808-server * home https://gitee.com/yezhihao/jt808-server
*/ */
public abstract class FieldFactory { public abstract class FieldFactory {
protected static Logger log = LoggerFactory.getLogger(FieldFactory.class.getSimpleName());
public static boolean EXPLAIN = false; public static boolean EXPLAIN = false;
public static BasicField create(Field field, java.lang.reflect.Field f) { public static BasicField create(Field field, java.lang.reflect.Field f) {
@ -59,19 +56,16 @@ public abstract class FieldFactory {
fieldSchema = StringSchema.Chars.getInstance(field.pad(), field.charset()); fieldSchema = StringSchema.Chars.getInstance(field.pad(), field.charset());
break; break;
case OBJ: case OBJ:
if (schema != null) { if (schema != null)
fieldSchema = ObjectSchema.getInstance(schema); fieldSchema = ObjectSchema.getInstance(schema);
} else { else
Convert convert = f.getAnnotation(Convert.class); fieldSchema = ConvertSchema.getInstance(field.converter());
fieldSchema = ConvertSchema.getInstance(convert.converter());
}
break; break;
case LIST: case LIST:
fieldSchema = CollectionSchema.getInstance(schema); fieldSchema = CollectionSchema.getInstance(schema);
break; break;
case MAP: case MAP:
Convert convert = f.getAnnotation(Convert.class); fieldSchema = ConvertSchema.getInstance(field.converter());
fieldSchema = ConvertSchema.getInstance(convert.converter());
break; break;
default: default:
throw new RuntimeException("不支持的类型转换"); throw new RuntimeException("不支持的类型转换");

View File

@ -1,21 +0,0 @@
package io.github.yezhihao.protostar.annotation;
import io.github.yezhihao.protostar.converter.Converter;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
*
* @author yezhihao
* home https://gitee.com/yezhihao/jt808-server
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Convert {
Class<? extends Converter> converter();
}

View File

@ -1,6 +1,7 @@
package io.github.yezhihao.protostar.annotation; package io.github.yezhihao.protostar.annotation;
import io.github.yezhihao.protostar.DataType; import io.github.yezhihao.protostar.DataType;
import io.github.yezhihao.protostar.converter.Converter;
import java.lang.annotation.*; import java.lang.annotation.*;
@ -23,9 +24,11 @@ public @interface Field {
String charset() default "GBK"; String charset() default "GBK";
byte pad() default 0x00; byte pad() default 0;
String desc() default ""; String desc() default "";
int[] version() default {-1, 0, 1}; int[] version() default {-1, 0, 1};
Class<? extends Converter> converter() default Converter.class;
} }

View File

@ -1,12 +1,18 @@
package io.github.yezhihao.protostar.converter; package io.github.yezhihao.protostar.converter;
import io.github.yezhihao.protostar.PrepareLoadStrategy;
import io.github.yezhihao.protostar.Schema;
import io.github.yezhihao.protostar.util.ByteBufUtils; import io.github.yezhihao.protostar.util.ByteBufUtils;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map; import java.util.Map;
import java.util.TreeMap; import java.util.TreeMap;
public abstract class MapConverter<K, V> implements Converter<Map<K, V>> { public abstract class MapConverter<K, V> extends PrepareLoadStrategy implements Converter<Map<K, V>> {
private final Logger log = LoggerFactory.getLogger(this.getClass().getSimpleName());
protected abstract K readKey(ByteBuf input); protected abstract K readKey(ByteBuf input);
@ -14,24 +20,31 @@ public abstract class MapConverter<K, V> implements Converter<Map<K, V>> {
protected abstract int valueSize(); protected abstract int valueSize();
protected abstract V convert(K key, ByteBuf input);
protected abstract void convert(K key, ByteBuf output, V value);
@Override @Override
public Map<K, V> convert(ByteBuf input) { public Map<K, V> convert(ByteBuf input) {
if (!input.isReadable()) if (!input.isReadable())
return null; return null;
Map<K, V> map = new TreeMap<>(); Map<K, V> map = new TreeMap<>();
do { do {
K id = readKey(input); K key = readKey(input);
int len = ByteBufUtils.readInt(input, valueSize()); int len = ByteBufUtils.readInt(input, valueSize());
Object value = convert(id, input.readSlice(len)); Object value = readValue(key, input.readSlice(len));
map.put(id, (V) value); map.put(key, (V) value);
} while (input.isReadable()); } while (input.isReadable());
return map; return map;
} }
public Object readValue(K key, ByteBuf input) {
if (!input.isReadable())
return null;
Schema schema = getSchema(key);
if (schema != null)
return schema.readFrom(input);
byte[] bytes = new byte[input.readableBytes()];
input.readBytes(bytes);
return bytes;
}
@Override @Override
public void convert(ByteBuf output, Map<K, V> map) { public void convert(ByteBuf output, Map<K, V> map) {
@ -40,14 +53,22 @@ public abstract class MapConverter<K, V> implements Converter<Map<K, V>> {
for (Map.Entry<K, V> entry : map.entrySet()) { for (Map.Entry<K, V> entry : map.entrySet()) {
K key = entry.getKey(); K key = entry.getKey();
V value = entry.getValue(); V value = entry.getValue();
writeKey(output, key); writeKey(output, key);
int valueSize = valueSize(); writeValue(key, output, value);
}
}
public void writeValue(K key, ByteBuf output, Object value) {
Schema schema = getSchema(key);
if (schema != null) {
int lengthSize = valueSize();
int begin = output.writerIndex(); int begin = output.writerIndex();
output.writeBytes(ByteBufUtils.BLOCKS[valueSize]); output.writeBytes(ByteBufUtils.BLOCKS[lengthSize]);
convert(key, output, value); schema.writeTo(output, value);
int len = output.writerIndex() - begin - valueSize; int length = output.writerIndex() - begin - lengthSize;
ByteBufUtils.setInt(output, valueSize, begin, len); ByteBufUtils.setInt(output, lengthSize, begin, length);
} else {
log.warn("未注册的信息:ID[{}], VALUE[{}]", key, value);
} }
} }
} }

View File

@ -1,40 +1,21 @@
package io.github.yezhihao.protostar.convert; package io.github.yezhihao.protostar.convert;
import io.github.yezhihao.protostar.IdStrategy; import io.github.yezhihao.protostar.PrepareLoadStrategy;
import io.github.yezhihao.protostar.Schema;
import io.github.yezhihao.protostar.converter.MapConverter; import io.github.yezhihao.protostar.converter.MapConverter;
import io.github.yezhihao.protostar.schema.NumberSchema;
import io.github.yezhihao.protostar.schema.StringSchema;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AttributeConverter extends MapConverter<Integer, Object> { public class AttributeConverter extends MapConverter<Integer, Object> {
private static final Logger log = LoggerFactory.getLogger(AttributeConverter.class);
private static final IdStrategy INSTANCE = AttributeType.INSTANCE;
@Override @Override
public Object convert(Integer key, ByteBuf input) { protected void addSchemas(PrepareLoadStrategy schemaRegistry) {
if (!input.isReadable()) schemaRegistry
return null; .addSchema(1, NumberSchema.Int32.INSTANCE)
Schema schema = INSTANCE.getSchema(key); .addSchema(2, StringSchema.Chars.getInstance((byte) 0, "GBK"))
if (schema != null)
return INSTANCE.readFrom(key, input);
byte[] bytes = new byte[input.readableBytes()];
input.readBytes(bytes);
log.warn("未识别的附加信息ID[{}], HEX[{}]", key, ByteBufUtil.hexDump(bytes));
return bytes;
}
@Override .addSchema(3, Attr1.class)
public void convert(Integer key, ByteBuf output, Object value) { .addSchema(4, Attr2.Schema.INSTANCE);
Schema schema = INSTANCE.getSchema(key);
if (schema != null) {
schema.writeTo(output, value);
} else {
log.warn("未注册的附加信息ID[{}], Value[{}]", key, value);
}
} }
@Override @Override

View File

@ -1,21 +0,0 @@
package io.github.yezhihao.protostar.convert;
import io.github.yezhihao.protostar.IdStrategy;
import io.github.yezhihao.protostar.PrepareLoadStrategy;
import io.github.yezhihao.protostar.schema.NumberSchema;
import io.github.yezhihao.protostar.schema.StringSchema;
public class AttributeType extends PrepareLoadStrategy {
public static final IdStrategy INSTANCE = new AttributeType();
@Override
protected void addSchemas(PrepareLoadStrategy schemaRegistry) {
schemaRegistry
.addSchema(1, NumberSchema.Int32.INSTANCE)
.addSchema(2, StringSchema.Chars.getInstance((byte) 0, "GBK"))
.addSchema(3, Attr1.class)
.addSchema(4, Attr2.Schema.INSTANCE);
}
}

View File

@ -2,7 +2,6 @@ package io.github.yezhihao.protostar.convert;
import io.github.yezhihao.protostar.DataType; import io.github.yezhihao.protostar.DataType;
import io.github.yezhihao.protostar.ProtostarUtil; import io.github.yezhihao.protostar.ProtostarUtil;
import io.github.yezhihao.protostar.annotation.Convert;
import io.github.yezhihao.protostar.annotation.Field; import io.github.yezhihao.protostar.annotation.Field;
import io.github.yezhihao.protostar.schema.RuntimeSchema; import io.github.yezhihao.protostar.schema.RuntimeSchema;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
@ -63,8 +62,8 @@ public class Test {
private int id; private int id;
@Field(index = 3, type = DataType.BCD8421, desc = "日期", version = {0, 1}) @Field(index = 3, type = DataType.BCD8421, desc = "日期", version = {0, 1})
private LocalDateTime dateTime; private LocalDateTime dateTime;
@Convert(converter = AttributeConverter.class) @Field(index = 4, type = DataType.MAP, desc = "属性", version = 0, converter = AttributeConverter.class)
@Field(index = 4, type = DataType.MAP, desc = "属性", version = {0, 1}) @Field(index = 4, type = DataType.MAP, desc = "属性", version = 1, converter = AttributeConverterV2.class)
private Map<Integer, Object> attributes; private Map<Integer, Object> attributes;
public String getName() { public String getName() {