deployed 2.0.2.RELEASE,增强MapConverter,简化用户端实现。合并Convert到Field(为支持多版本Convert)
parent
75969aa5e6
commit
a2f5abb6f4
2
pom.xml
2
pom.xml
|
@ -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>
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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("不支持的类型转换");
|
||||||
|
|
|
@ -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();
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
||||||
}
|
}
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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() {
|
||||||
|
|
Loading…
Reference in New Issue