deployed 2.0.0.RELEASE,升级相关依赖

使用RuntimeSchema
使用反射(Field)取代内省(PropertyDescriptor),以兼容android平台
master
剑器近 2021-06-25 16:12:20 +08:00
parent a6e0e7c819
commit c305df04b9
18 changed files with 234 additions and 221 deletions

View File

@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>io.github.yezhihao</groupId>
<artifactId>protostar</artifactId>
<version>1.0.5.RELEASE</version>
<version>2.0.0.RELEASE</version>
<packaging>jar</packaging>
<name>Protostar</name>
@ -50,13 +50,13 @@
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.30</version>
<version>1.7.31</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
<version>1.7.31</version>
<scope>provided</scope>
</dependency>
<dependency>

View File

@ -1,9 +1,9 @@
package io.github.yezhihao.protostar;
import io.github.yezhihao.protostar.annotation.Message;
import io.github.yezhihao.protostar.schema.RuntimeSchema;
import io.github.yezhihao.protostar.util.ClassUtils;
import java.beans.Introspector;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -14,7 +14,7 @@ import java.util.Map;
*/
public class DefaultLoadStrategy extends LoadStrategy {
private Map<String, Map<Integer, Schema<?>>> typeClassMapping = new HashMap(140);
private Map<String, Map<Integer, RuntimeSchema<?>>> typeClassMapping = new HashMap(140);
public DefaultLoadStrategy() {
}
@ -26,33 +26,32 @@ public class DefaultLoadStrategy extends LoadStrategy {
if (message != null) {
int[] values = message.value();
for (int typeId : values)
loadSchema(typeClassMapping, typeId, type);
loadRuntimeSchema(typeClassMapping, typeId, type);
}
}
Introspector.flushCaches();
}
@Override
public <T> Schema<T> getSchema(Class<T> typeClass, Integer version) {
Map<Integer, Schema<?>> schemas = typeClassMapping.get(typeClass.getName());
public <T> RuntimeSchema<T> getRuntimeSchema(Class<T> typeClass, Integer version) {
Map<Integer, RuntimeSchema<?>> schemas = typeClassMapping.get(typeClass.getName());
if (schemas == null) {
schemas = loadSchema(typeClassMapping, typeClass);
schemas = loadRuntimeSchema(typeClassMapping, typeClass);
}
if (schemas == null) return null;
return (Schema<T>) schemas.get(version);
return (RuntimeSchema<T>) schemas.get(version);
}
@Override
public <T> Map<Integer, Schema<T>> getSchema(Class<T> typeClass) {
Map<Integer, Schema<?>> schemas = typeClassMapping.get(typeClass.getName());
public <T> Map<Integer, RuntimeSchema<T>> getRuntimeSchema(Class<T> typeClass) {
Map<Integer, RuntimeSchema<?>> schemas = typeClassMapping.get(typeClass.getName());
if (schemas == null) {
schemas = loadSchema(typeClassMapping, typeClass);
schemas = loadRuntimeSchema(typeClassMapping, typeClass);
}
if (schemas == null) return null;
HashMap<Integer, Schema<T>> result = new HashMap<>(schemas.size());
for (Map.Entry<Integer, Schema<?>> entry : schemas.entrySet()) {
result.put(entry.getKey(), (Schema<T>) entry.getValue());
HashMap<Integer, RuntimeSchema<T>> result = new HashMap<>(schemas.size());
for (Map.Entry<Integer, RuntimeSchema<?>> entry : schemas.entrySet()) {
result.put(entry.getKey(), (RuntimeSchema<T>) entry.getValue());
}
return result;
}

View File

@ -10,7 +10,6 @@ import io.github.yezhihao.protostar.schema.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.beans.PropertyDescriptor;
import java.nio.ByteBuffer;
import java.time.LocalDateTime;
@ -23,13 +22,13 @@ public abstract class FieldFactory {
protected static Logger log = LoggerFactory.getLogger(FieldFactory.class.getSimpleName());
public static boolean EXPLAIN = false;
public static BasicField create(Field field, PropertyDescriptor property) {
return create(field, property, null);
public static BasicField create(Field field, java.lang.reflect.Field f) {
return create(field, f, null);
}
public static BasicField create(Field field, PropertyDescriptor property, Schema schema) {
public static BasicField create(Field field, java.lang.reflect.Field f, Schema schema) {
DataType dataType = field.type();
Class<?> typeClass = property.getPropertyType();
Class<?> typeClass = f.getType();
Schema fieldSchema;
switch (dataType) {
@ -63,7 +62,7 @@ public abstract class FieldFactory {
if (schema != null) {
fieldSchema = ObjectSchema.getInstance(schema);
} else {
Convert convert = property.getReadMethod().getAnnotation(Convert.class);
Convert convert = f.getAnnotation(Convert.class);
fieldSchema = ConvertSchema.getInstance(convert.converter());
}
break;
@ -71,7 +70,7 @@ public abstract class FieldFactory {
fieldSchema = CollectionSchema.getInstance(schema);
break;
case MAP:
Convert convert = property.getReadMethod().getAnnotation(Convert.class);
Convert convert = f.getAnnotation(Convert.class);
fieldSchema = ConvertSchema.getInstance(convert.converter());
break;
default:
@ -82,19 +81,19 @@ public abstract class FieldFactory {
BasicField result;
if (EXPLAIN) {
if (field.lengthSize() > 0) {
result = new DynamicLengthField.Logger(field, property, fieldSchema);
result = new DynamicLengthField.Logger(field, f, fieldSchema);
} else if (field.length() > 0) {
result = new FixedLengthField.Logger(field, property, fieldSchema);
result = new FixedLengthField.Logger(field, f, fieldSchema);
} else {
result = new FixedField.Logger(field, property, fieldSchema);
result = new FixedField.Logger(field, f, fieldSchema);
}
} else {
if (field.lengthSize() > 0) {
result = new DynamicLengthField(field, property, fieldSchema);
result = new DynamicLengthField(field, f, fieldSchema);
} else if (field.length() > 0) {
result = new FixedLengthField(field, property, fieldSchema);
result = new FixedLengthField(field, f, fieldSchema);
} else {
result = new FixedField(field, property, fieldSchema);
result = new FixedField(field, f, fieldSchema);
}
}
return result;

View File

@ -5,11 +5,6 @@ import io.github.yezhihao.protostar.field.BasicField;
import io.github.yezhihao.protostar.schema.RuntimeSchema;
import io.netty.buffer.ByteBuf;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.*;
@ -54,11 +49,11 @@ public abstract class IdStrategy {
if (schema != null)
return (Schema<T>) schema;
List<PropertyDescriptor> properties = findFieldProperties(typeClass);
if (properties.isEmpty())
List<java.lang.reflect.Field> fs = findFields(typeClass);
if (fs.isEmpty())
return null;
List<BasicField> fieldList = findFields(root, properties);
List<BasicField> fieldList = findFields(root, fs);
BasicField[] fields = fieldList.toArray(new BasicField[fieldList.size()]);
Arrays.sort(fields);
@ -67,57 +62,44 @@ public abstract class IdStrategy {
return (Schema<T>) schema;
}
protected static List<PropertyDescriptor> findFieldProperties(Class typeClass) {
BeanInfo beanInfo;
try {
beanInfo = Introspector.getBeanInfo(typeClass);
} catch (IntrospectionException e) {
throw new RuntimeException(e);
}
PropertyDescriptor[] properties = beanInfo.getPropertyDescriptors();
List<PropertyDescriptor> result = new ArrayList<>(properties.length);
protected static List<java.lang.reflect.Field> findFields(Class typeClass) {
java.lang.reflect.Field[] fields = typeClass.getDeclaredFields();
List<java.lang.reflect.Field> result = new ArrayList<>(fields.length);
for (PropertyDescriptor property : properties) {
Method readMethod = property.getReadMethod();
if (readMethod != null) {
if (readMethod.isAnnotationPresent(Field.class)) {
result.add(property);
}
for (java.lang.reflect.Field f : fields) {
if (f.isAnnotationPresent(Field.class)) {
result.add(f);
}
}
return result;
}
protected static List<BasicField> findFields(Map<Object, Schema> root, List<PropertyDescriptor> properties) {
List<BasicField> fields = new ArrayList<>(properties.size());
protected static List<BasicField> findFields(Map<Object, Schema> root, List<java.lang.reflect.Field> fs) {
List<BasicField> fields = new ArrayList<>(fs.size());
for (PropertyDescriptor property : properties) {
Method readMethod = property.getReadMethod();
Field field = readMethod.getDeclaredAnnotation(Field.class);
for (java.lang.reflect.Field f : fs) {
Field field = f.getDeclaredAnnotation(Field.class);
if (field != null) {
fillField(root, fields, property, field);
fillField(root, fields, f, field);
}
}
return fields;
}
protected static void fillField(Map<Object, Schema> root, List<BasicField> fields, PropertyDescriptor propertyDescriptor, Field field) {
Class typeClass = propertyDescriptor.getPropertyType();
Method readMethod = propertyDescriptor.getReadMethod();
protected static void fillField(Map<Object, Schema> root, List<BasicField> fields, java.lang.reflect.Field f, Field field) {
Class typeClass = f.getType();
BasicField value;
if (field.type() == DataType.OBJ || field.type() == DataType.LIST) {
if (Collection.class.isAssignableFrom(typeClass))
typeClass = (Class) ((ParameterizedType) readMethod.getGenericReturnType()).getActualTypeArguments()[0];
typeClass = (Class) ((ParameterizedType) f.getGenericType()).getActualTypeArguments()[0];
loadSchema(root, typeClass);
Schema schema = root.get(typeClass.getName());
value = FieldFactory.create(field, propertyDescriptor, schema);
value = FieldFactory.create(field, f, schema);
fields.add(value);
} else {
value = FieldFactory.create(field, propertyDescriptor);
value = FieldFactory.create(field, f);
fields.add(value);
}
}

View File

@ -5,55 +5,50 @@ import io.github.yezhihao.protostar.annotation.Fs;
import io.github.yezhihao.protostar.field.BasicField;
import io.github.yezhihao.protostar.schema.RuntimeSchema;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.*;
/**
* Schema
* RuntimeSchema
* @author yezhihao
* home https://gitee.com/yezhihao/jt808-server
*/
public abstract class LoadStrategy {
protected Map<Object, Map<Integer, Schema<?>>> typeIdMapping = new HashMap<>(64);
protected Map<Object, Map<Integer, RuntimeSchema<?>>> typeIdMapping = new HashMap<>(64);
public abstract <T> Map<Integer, Schema<T>> getSchema(Class<T> typeClass);
public abstract <T> Map<Integer, RuntimeSchema<T>> getRuntimeSchema(Class<T> typeClass);
public abstract <T> Schema<T> getSchema(Class<T> typeClass, Integer version);
public abstract <T> RuntimeSchema<T> getRuntimeSchema(Class<T> typeClass, Integer version);
public Schema getSchema(Object typeId, Integer version) {
Map<Integer, Schema<?>> schemaMap = typeIdMapping.get(typeId);
public RuntimeSchema getRuntimeSchema(Object typeId, Integer version) {
Map<Integer, RuntimeSchema<?>> schemaMap = typeIdMapping.get(typeId);
if (schemaMap == null)
return null;
return schemaMap.get(version);
}
protected void loadSchema(Map<String, Map<Integer, Schema<?>>> root, Object typeId, Class<?> typeClass) {
Map<Integer, Schema<?>> schemas = typeIdMapping.get(typeId);
protected void loadRuntimeSchema(Map<String, Map<Integer, RuntimeSchema<?>>> root, Object typeId, Class<?> typeClass) {
Map<Integer, RuntimeSchema<?>> schemas = typeIdMapping.get(typeId);
if (schemas == null) {
schemas = loadSchema(root, typeClass);
schemas = loadRuntimeSchema(root, typeClass);
typeIdMapping.put(typeId, schemas);
}
}
protected Map<Integer, Schema<?>> loadSchema(Map<String, Map<Integer, Schema<?>>> root, Class<?> typeClass) {
Map<Integer, Schema<?>> schemas = root.get(typeClass.getName());
protected Map<Integer, RuntimeSchema<?>> loadRuntimeSchema(Map<String, Map<Integer, RuntimeSchema<?>>> root, Class<?> typeClass) {
Map<Integer, RuntimeSchema<?>> schemas = root.get(typeClass.getName());
//不支持循环引用
if (schemas != null)
return schemas;
List<PropertyDescriptor> properties = findFieldProperties(typeClass);
if (properties.isEmpty())
List<java.lang.reflect.Field> fs = findFields(typeClass);
if (fs.isEmpty())
return null;
root.put(typeClass.getName(), schemas = new HashMap(4));
Map<Integer, List<BasicField>> multiVersionFields = findMultiVersionFields(root, properties);
Map<Integer, List<BasicField>> multiVersionFields = findMultiVersionFields(root, fs);
for (Map.Entry<Integer, List<BasicField>> entry : multiVersionFields.entrySet()) {
Integer version = entry.getKey();
@ -62,79 +57,68 @@ public abstract class LoadStrategy {
BasicField[] fields = fieldList.toArray(new BasicField[fieldList.size()]);
Arrays.sort(fields);
Schema schema = new RuntimeSchema(typeClass, version, fields);
RuntimeSchema schema = new RuntimeSchema(typeClass, version, fields);
schemas.put(version, schema);
}
return schemas;
}
protected List<PropertyDescriptor> findFieldProperties(Class<?> typeClass) {
BeanInfo beanInfo;
try {
beanInfo = Introspector.getBeanInfo(typeClass);
} catch (IntrospectionException e) {
throw new RuntimeException(e);
}
PropertyDescriptor[] properties = beanInfo.getPropertyDescriptors();
List<PropertyDescriptor> result = new ArrayList<>(properties.length);
protected List<java.lang.reflect.Field> findFields(Class<?> typeClass) {
java.lang.reflect.Field[] fs = typeClass.getDeclaredFields();
for (PropertyDescriptor property : properties) {
Method readMethod = property.getReadMethod();
List<java.lang.reflect.Field> result = new ArrayList<>(fs.length);
if (readMethod != null) {
if (readMethod.isAnnotationPresent(Fs.class) || readMethod.isAnnotationPresent(Field.class)) {
result.add(property);
}
for (java.lang.reflect.Field f : fs) {
if (f.isAnnotationPresent(Fs.class) || f.isAnnotationPresent(Field.class)) {
result.add(f);
}
}
return result;
}
protected Map<Integer, List<BasicField>> findMultiVersionFields(Map<String, Map<Integer, Schema<?>>> root, List<PropertyDescriptor> properties) {
protected Map<Integer, List<BasicField>> findMultiVersionFields(Map<String, Map<Integer, RuntimeSchema<?>>> root, List<java.lang.reflect.Field> fs) {
Map<Integer, List<BasicField>> multiVersionFields = new TreeMap<Integer, List<BasicField>>() {
@Override
public List<BasicField> get(Object key) {
List result = super.get(key);
if (result == null)
super.put((Integer) key, result = new ArrayList<>(properties.size()));
super.put((Integer) key, result = new ArrayList<>(fs.size()));
return result;
}
};
for (PropertyDescriptor property : properties) {
Method readMethod = property.getReadMethod();
for (java.lang.reflect.Field f : fs) {
Field field = readMethod.getDeclaredAnnotation(Field.class);
Field field = f.getDeclaredAnnotation(Field.class);
if (field != null) {
fillField(root, multiVersionFields, property, field);
fillField(root, multiVersionFields, f, field);
} else {
Field[] fields = readMethod.getDeclaredAnnotation(Fs.class).value();
Field[] fields = f.getDeclaredAnnotation(Fs.class).value();
for (int i = 0; i < fields.length; i++)
fillField(root, multiVersionFields, property, fields[i]);
fillField(root, multiVersionFields, f, fields[i]);
}
}
return multiVersionFields;
}
protected void fillField(Map<String, Map<Integer, Schema<?>>> root, Map<Integer, List<BasicField>> multiVersionFields, PropertyDescriptor propertyDescriptor, Field field) {
Class<?> typeClass = propertyDescriptor.getPropertyType();
Method readMethod = propertyDescriptor.getReadMethod();
protected void fillField(Map<String, Map<Integer, RuntimeSchema<?>>> root, Map<Integer, List<BasicField>> multiVersionFields, java.lang.reflect.Field f, Field field) {
Class<?> typeClass = f.getType();
BasicField value;
int[] versions = field.version();
if (field.type() == DataType.OBJ || field.type() == DataType.LIST) {
if (Collection.class.isAssignableFrom(typeClass))
typeClass = (Class<?>) ((ParameterizedType) readMethod.getGenericReturnType()).getActualTypeArguments()[0];
loadSchema(root, typeClass);
typeClass = (Class<?>) ((ParameterizedType) f.getGenericType()).getActualTypeArguments()[0];
loadRuntimeSchema(root, typeClass);
for (int ver : versions) {
Map<Integer, Schema<?>> schemaMap = root.getOrDefault(typeClass.getName(), Collections.EMPTY_MAP);
Schema schema = schemaMap.get(ver);
value = FieldFactory.create(field, propertyDescriptor, schema);
Map<Integer, RuntimeSchema<?>> schemaMap = root.getOrDefault(typeClass.getName(), Collections.EMPTY_MAP);
RuntimeSchema schema = schemaMap.get(ver);
value = FieldFactory.create(field, f, schema);
multiVersionFields.get(ver).add(value);
}
} else {
value = FieldFactory.create(field, propertyDescriptor);
value = FieldFactory.create(field, f);
for (int ver : versions) {
multiVersionFields.get(ver).add(value);
}

View File

@ -1,5 +1,7 @@
package io.github.yezhihao.protostar;
import io.github.yezhihao.protostar.schema.RuntimeSchema;
import java.util.Map;
/**
@ -24,15 +26,15 @@ public class ProtostarUtil {
}
}
public static Schema getSchema(Object typeId, Integer version) {
return LOAD_STRATEGY.getSchema(typeId, version);
public static RuntimeSchema getRuntimeSchema(Object typeId, Integer version) {
return LOAD_STRATEGY.getRuntimeSchema(typeId, version);
}
public static Schema getSchema(Class<?> typeClass, Integer version) {
return LOAD_STRATEGY.getSchema(typeClass, version);
public static RuntimeSchema getRuntimeSchema(Class<?> typeClass, Integer version) {
return LOAD_STRATEGY.getRuntimeSchema(typeClass, version);
}
public static <T> Map<Integer, Schema<T>> getSchema(Class<T> typeClass) {
return LOAD_STRATEGY.getSchema(typeClass);
public static <T> Map<Integer, RuntimeSchema<T>> getRuntimeSchema(Class<T> typeClass) {
return LOAD_STRATEGY.getRuntimeSchema(typeClass);
}
}

View File

@ -12,7 +12,7 @@ import java.lang.annotation.Target;
* @author yezhihao
* home https://gitee.com/yezhihao/jt808-server
*/
@Target(ElementType.METHOD)
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Convert {

View File

@ -9,7 +9,7 @@ import java.lang.annotation.*;
* home https://gitee.com/yezhihao/jt808-server
*/
@Repeatable(Fs.class)
@Target(ElementType.METHOD)
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Field {

View File

@ -9,7 +9,7 @@ import java.lang.annotation.Target;
* @author yezhihao
* home https://gitee.com/yezhihao/jt808-server
*/
@Target(ElementType.METHOD)
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Fs {

View File

@ -6,9 +6,6 @@ import io.netty.buffer.ByteBuf;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
/**
*
* @author yezhihao
@ -19,23 +16,21 @@ public abstract class BasicField<T> implements Comparable<BasicField<T>> {
protected final int index;
protected final int length;
protected final String desc;
protected final Method readMethod;
protected final Method writeMethod;
protected final PropertyDescriptor property;
protected final Field field;
protected final java.lang.reflect.Field f;
public BasicField(Field field, PropertyDescriptor property) {
public BasicField(Field field, java.lang.reflect.Field f) {
this.index = field.index();
int length = field.length();
if (length < 0)
length = field.type().length;
this.length = length;
this.desc = field.desc();
this.readMethod = property.getReadMethod();
this.writeMethod = property.getWriteMethod();
this.field = field;
this.property = property;
this.f = f;
try {
f.setAccessible(true);
} catch (Exception e) {
}
}
public abstract boolean readFrom(ByteBuf input, Object message) throws Exception;
@ -62,13 +57,12 @@ public abstract class BasicField<T> implements Comparable<BasicField<T>> {
@Override
public String toString() {
final StringBuilder sb = new StringBuilder(60);
final StringBuilder sb = new StringBuilder(50);
sb.append('{');
sb.append("index=").append(index);
sb.append(", length=").append(length);
sb.append(", desc").append(desc);
sb.append(", readMethod=").append(readMethod.getName());
sb.append(", writeMethod=").append(writeMethod.getName());
sb.append(", desc").append(field.desc());
sb.append(", field=").append(f.getName());
sb.append('}');
return sb.toString();
}

View File

@ -1,12 +1,10 @@
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.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.github.yezhihao.protostar.Schema;
import io.github.yezhihao.protostar.util.ByteBufUtils;
import java.beans.PropertyDescriptor;
/**
*
@ -19,8 +17,8 @@ public class DynamicLengthField<T> extends BasicField<T> {
protected final int lengthSize;
public DynamicLengthField(Field field, PropertyDescriptor property, Schema<T> schema) {
super(field, property);
public DynamicLengthField(Field field, java.lang.reflect.Field f, Schema<T> schema) {
super(field, f);
this.schema = schema;
this.lengthSize = field.lengthSize();
}
@ -30,12 +28,12 @@ public class DynamicLengthField<T> extends BasicField<T> {
if (!input.isReadable(length))
return false;
Object value = schema.readFrom(input, length);
writeMethod.invoke(message, value);
f.set(message, value);
return true;
}
public void writeTo(ByteBuf output, Object message) throws Exception {
Object value = readMethod.invoke(message);
Object value = f.get(message);
if (value != null) {
int begin = output.writerIndex();
output.writeBytes(ByteBufUtils.BLOCKS[lengthSize]);
@ -55,8 +53,8 @@ public class DynamicLengthField<T> extends BasicField<T> {
public static class Logger<T> extends DynamicLengthField<T> {
public Logger(Field field, PropertyDescriptor property, Schema<T> schema) {
super(field, property, schema);
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 {
@ -66,18 +64,18 @@ public class DynamicLengthField<T> extends BasicField<T> {
if (!input.isReadable(length))
return false;
Object value = schema.readFrom(input, length);
writeMethod.invoke(message, value);
f.set(message, value);
int after = input.readerIndex();
String hex = ByteBufUtil.hexDump(input.slice(before, after - before));
println(this.index, this.desc, hex, value);
println(this.index, this.field.desc(), hex, value);
return true;
}
public void writeTo(ByteBuf output, Object message) throws Exception {
int before = output.writerIndex();
Object value = readMethod.invoke(message);
Object value = f.get(message);
if (value != null) {
int begin = output.writerIndex();
output.writeBytes(ByteBufUtils.BLOCKS[lengthSize]);
@ -88,7 +86,7 @@ public class DynamicLengthField<T> extends BasicField<T> {
int after = output.writerIndex();
String hex = ByteBufUtil.hexDump(output.slice(before, after - before));
println(this.index, this.desc, hex, value);
println(this.index, this.field.desc(), hex, value);
}
}
}

View File

@ -1,11 +1,9 @@
package io.github.yezhihao.protostar.field;
import io.github.yezhihao.protostar.Schema;
import io.github.yezhihao.protostar.annotation.Field;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.github.yezhihao.protostar.Schema;
import java.beans.PropertyDescriptor;
/**
*
@ -16,51 +14,51 @@ public class FixedField<T> extends BasicField<T> {
protected final Schema<T> schema;
public FixedField(Field field, PropertyDescriptor property, Schema<T> schema) {
super(field, property);
public FixedField(Field field, java.lang.reflect.Field f, Schema<T> schema) {
super(field, f);
this.schema = schema;
}
public boolean readFrom(ByteBuf input, Object message) throws Exception {
Object value = schema.readFrom(input);
writeMethod.invoke(message, value);
f.set(message, value);
return true;
}
public void writeTo(ByteBuf output, Object message) throws Exception {
Object value = readMethod.invoke(message);
Object value = f.get(message);
if (value != null)
schema.writeTo(output, (T) value);
}
public static class Logger<T> extends FixedField<T> {
public Logger(Field field, PropertyDescriptor property, Schema<T> schema) {
super(field, property, schema);
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 before = input.readerIndex();
Object value = schema.readFrom(input);
writeMethod.invoke(message, value);
f.set(message, value);
int after = input.readerIndex();
String hex = ByteBufUtil.hexDump(input.slice(before, after - before));
println(this.index, this.desc, hex, value);
println(this.index, this.field.desc(), hex, value);
return true;
}
public void writeTo(ByteBuf output, Object message) throws Exception {
int before = output.writerIndex();
Object value = readMethod.invoke(message);
Object value = f.get(message);
if (value != null)
schema.writeTo(output, (T) value);
int after = output.writerIndex();
String hex = ByteBufUtil.hexDump(output.slice(before, after - before));
println(this.index, this.desc, hex, value);
println(this.index, this.field.desc(), hex, value);
}
}
}

View File

@ -1,11 +1,9 @@
package io.github.yezhihao.protostar.field;
import io.github.yezhihao.protostar.Schema;
import io.github.yezhihao.protostar.annotation.Field;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.github.yezhihao.protostar.Schema;
import java.beans.PropertyDescriptor;
/**
*
@ -16,51 +14,51 @@ public class FixedLengthField<T> extends BasicField<T> {
protected final Schema<T> schema;
public FixedLengthField(Field field, PropertyDescriptor property, Schema<T> schema) {
super(field, property);
public FixedLengthField(Field field, java.lang.reflect.Field f, Schema<T> schema) {
super(field, f);
this.schema = schema;
}
public boolean readFrom(ByteBuf input, Object message) throws Exception {
Object value = schema.readFrom(input, length);
writeMethod.invoke(message, value);
f.set(message, value);
return true;
}
public void writeTo(ByteBuf output, Object message) throws Exception {
Object value = readMethod.invoke(message);
Object value = f.get(message);
if (value != null)
schema.writeTo(output, length, (T) value);
}
public static class Logger<T> extends FixedLengthField<T> {
public Logger(Field field, PropertyDescriptor property, Schema<T> schema) {
super(field, property, schema);
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 before = input.readerIndex();
Object value = schema.readFrom(input, length);
writeMethod.invoke(message, value);
f.set(message, value);
int after = input.readerIndex();
String hex = ByteBufUtil.hexDump(input.slice(before, after - before));
println(this.index, this.desc, hex, value);
println(this.index, this.field.desc(), hex, value);
return true;
}
public void writeTo(ByteBuf output, Object message) throws Exception {
int before = output.writerIndex();
Object value = readMethod.invoke(message);
Object value = f.get(message);
if (value != null)
schema.writeTo(output, length, (T) value);
int after = output.writerIndex();
String hex = ByteBufUtil.hexDump(output.slice(before, after - before));
println(this.index, this.desc, hex, value);
println(this.index, this.field.desc(), hex, value);
}
}
}

View File

@ -34,6 +34,29 @@ public class RuntimeSchema<T> implements Schema<T> {
}
}
public T newInstance() {
try {
return constructor.newInstance((Object[]) null);
} catch (Exception e) {
throw new RuntimeException("newInstance failed " + typeClass.getName(), e);
}
}
public T mergeFrom(ByteBuf input, T result) {
BasicField field = null;
try {
for (int i = 0; i < fields.length; i++) {
if (!input.isReadable())
break;
field = fields[i];
field.readFrom(input, result);
}
return result;
} catch (Exception e) {
throw new RuntimeException("Read failed " + typeClass.getName() + field, e);
}
}
public T readFrom(ByteBuf input) {
BasicField field = null;
try {

View File

@ -5,7 +5,9 @@ import io.github.yezhihao.protostar.annotation.Field;
public class Attr1 {
@Field(index = 0, type = DataType.STRING, lengthSize = 1, desc = "名称")
private String name;
@Field(index = 1, type = DataType.WORD, desc = "ID")
private int id;
public Attr1() {
@ -16,7 +18,6 @@ public class Attr1 {
this.id = id;
}
@Field(index = 0, type = DataType.STRING, lengthSize = 1, desc = "名称")
public String getName() {
return name;
}
@ -25,7 +26,6 @@ public class Attr1 {
this.name = name;
}
@Field(index = 1, type = DataType.WORD, desc = "ID")
public int getId() {
return id;
}

View File

@ -2,10 +2,9 @@ package io.github.yezhihao.protostar.convert;
import io.github.yezhihao.protostar.DataType;
import io.github.yezhihao.protostar.ProtostarUtil;
import io.github.yezhihao.protostar.Schema;
import io.github.yezhihao.protostar.annotation.Convert;
import io.github.yezhihao.protostar.annotation.Field;
import io.github.yezhihao.protostar.annotation.Fs;
import io.github.yezhihao.protostar.schema.RuntimeSchema;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
@ -17,9 +16,9 @@ import java.util.TreeMap;
public class Test {
public static void main(String[] args) {
Map<Integer, Schema<Foo>> multiVersionSchema = ProtostarUtil.getSchema(Foo.class);
Schema<Foo> schema_v0 = multiVersionSchema.get(0);
Schema<Foo> schema_v1 = multiVersionSchema.get(1);
Map<Integer, RuntimeSchema<Foo>> multiVersionSchema = ProtostarUtil.getRuntimeSchema(Foo.class);
RuntimeSchema<Foo> schema_v0 = multiVersionSchema.get(0);
RuntimeSchema<Foo> schema_v1 = multiVersionSchema.get(1);
ByteBuf buffer = Unpooled.buffer(32);
schema_v0.writeTo(buffer, foo());
@ -56,13 +55,18 @@ public class Test {
public static class Foo {
@Field(index = 0, type = DataType.STRING, lengthSize = 1, desc = "名称", version = 0)
@Field(index = 0, type = DataType.STRING, length = 10, desc = "名称", version = 1)
private String name;
@Field(index = 1, type = DataType.WORD, desc = "ID", version = 0)
@Field(index = 1, type = DataType.DWORD, desc = "ID", version = 1)
private int id;
@Field(index = 3, type = DataType.BCD8421, desc = "日期", version = {0, 1})
private LocalDateTime dateTime;
@Convert(converter = AttributeConverter.class)
@Field(index = 4, type = DataType.MAP, desc = "属性", version = {0, 1})
private Map<Integer, Object> attributes;
@Fs({@Field(index = 0, type = DataType.STRING, lengthSize = 1, desc = "名称", version = 0),
@Field(index = 0, type = DataType.STRING, length = 10, desc = "名称", version = 1)})
public String getName() {
return name;
}
@ -71,8 +75,6 @@ public class Test {
this.name = name;
}
@Fs({@Field(index = 1, type = DataType.WORD, desc = "ID", version = 0),
@Field(index = 1, type = DataType.DWORD, desc = "ID", version = 1)})
public int getId() {
return id;
}
@ -81,7 +83,6 @@ public class Test {
this.id = id;
}
@Field(index = 3, type = DataType.BCD8421, desc = "日期", version = {0, 1})
public LocalDateTime getDateTime() {
return dateTime;
}
@ -90,8 +91,6 @@ public class Test {
this.dateTime = dateTime;
}
@Convert(converter = AttributeConverter.class)
@Field(index = 4, type = DataType.MAP, desc = "属性", version = {0, 1})
public Map<Integer, Object> getAttributes() {
return attributes;
}

View File

@ -2,8 +2,8 @@ package io.github.yezhihao.protostar.multiversion;
import io.github.yezhihao.protostar.DataType;
import io.github.yezhihao.protostar.ProtostarUtil;
import io.github.yezhihao.protostar.Schema;
import io.github.yezhihao.protostar.annotation.Field;
import io.github.yezhihao.protostar.schema.RuntimeSchema;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
@ -14,9 +14,9 @@ import java.util.Map;
public class Test {
public static void main(String[] args) {
Map<Integer, Schema<Foo>> multiVersionSchema = ProtostarUtil.getSchema(Foo.class);
Schema<Foo> schema_v0 = multiVersionSchema.get(0);
Schema<Foo> schema_v1 = multiVersionSchema.get(1);
Map<Integer, RuntimeSchema<Foo>> multiVersionSchema = ProtostarUtil.getRuntimeSchema(Foo.class);
RuntimeSchema<Foo> schema_v0 = multiVersionSchema.get(0);
RuntimeSchema<Foo> schema_v1 = multiVersionSchema.get(1);
ByteBuf buffer = Unpooled.buffer(32);
Foo foo = foo();
@ -48,12 +48,15 @@ public class Test {
public static class Foo {
private String name;
private int id;
private LocalDateTime dateTime;
@Field(index = 0, type = DataType.STRING, lengthSize = 1, desc = "名称", version = 0)
@Field(index = 0, type = DataType.STRING, length = 10, desc = "名称", version = 1)
private String name;
@Field(index = 1, type = DataType.WORD, desc = "ID", version = 0)
@Field(index = 1, type = DataType.DWORD, desc = "ID", version = 1)
private int id;
@Field(index = 3, type = DataType.BCD8421, desc = "日期", version = {0, 1})
private LocalDateTime dateTime;
public String getName() {
return name;
}
@ -62,8 +65,6 @@ public class Test {
this.name = name;
}
@Field(index = 1, type = DataType.WORD, desc = "ID", version = 0)
@Field(index = 1, type = DataType.DWORD, desc = "ID", version = 1)
public int getId() {
return id;
}
@ -72,7 +73,6 @@ public class Test {
this.id = id;
}
@Field(index = 3, type = DataType.BCD8421, desc = "日期", version = {0, 1})
public LocalDateTime getDateTime() {
return dateTime;
}

View File

@ -3,8 +3,8 @@ package io.github.yezhihao.protostar.simple;
import io.github.yezhihao.protostar.DataType;
import io.github.yezhihao.protostar.FieldFactory;
import io.github.yezhihao.protostar.ProtostarUtil;
import io.github.yezhihao.protostar.Schema;
import io.github.yezhihao.protostar.annotation.Field;
import io.github.yezhihao.protostar.schema.RuntimeSchema;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
@ -17,16 +17,24 @@ public class Test {
public static void main(String[] args) {
FieldFactory.EXPLAIN = true;
Map<Integer, Schema<Foo>> multiVersionSchema = ProtostarUtil.getSchema(Foo.class);
Schema<Foo> schema = multiVersionSchema.get(0);
Map<Integer, RuntimeSchema<Foo>> bodySchemas = ProtostarUtil.getRuntimeSchema(Foo.class);
RuntimeSchema<Foo> bodySchema = bodySchemas.get(0);
Map<Integer, RuntimeSchema<BaseDO>> headSchemas = ProtostarUtil.getRuntimeSchema(BaseDO.class);
RuntimeSchema<BaseDO> headSchema = headSchemas.get(0);
ByteBuf buffer = Unpooled.buffer(32);
Foo foo = foo();
schema.writeTo(buffer, foo);
headSchema.writeTo(buffer, foo);
bodySchema.writeTo(buffer, foo);
String hex = ByteBufUtil.hexDump(buffer);
System.out.println(hex);
foo = schema.readFrom(buffer);
Foo foo1 = new Foo();
headSchema.mergeFrom(buffer, foo1);
bodySchema.mergeFrom(buffer, foo1);
System.out.println(foo);
}
@ -35,16 +43,45 @@ public class Test {
foo.setName("张三");
foo.setId(128);
foo.setDateTime(LocalDateTime.of(2020, 7, 7, 19, 23, 59));
foo.setType(1);
foo.setClientId("123qwe");
return foo;
}
public static class Foo {
public static class BaseDO {
private String name;
private int id;
private LocalDateTime dateTime;
@Field(index = 0, type = DataType.WORD, desc = "ID")
protected int type;
@Field(index = 1, type = DataType.STRING, length = 20, desc = "名称")
protected String clientId;
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public String getClientId() {
return clientId;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
}
public static class Foo extends BaseDO {
@Field(index = 0, type = DataType.STRING, lengthSize = 1, desc = "名称")
private String name;
@Field(index = 1, type = DataType.WORD, desc = "ID")
private int id;
@Field(index = 3, type = DataType.BCD8421, desc = "日期")
private LocalDateTime dateTime;
public String getName() {
return name;
}
@ -53,7 +90,6 @@ public class Test {
this.name = name;
}
@Field(index = 1, type = DataType.WORD, desc = "ID")
public int getId() {
return id;
}
@ -62,7 +98,6 @@ public class Test {
this.id = id;
}
@Field(index = 3, type = DataType.BCD8421, desc = "日期")
public LocalDateTime getDateTime() {
return dateTime;
}
@ -74,7 +109,9 @@ public class Test {
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("Foo{");
sb.append("name='").append(name).append('\'');
sb.append("type=").append(type);
sb.append(", clientId='").append(clientId).append('\'');
sb.append(", name='").append(name).append('\'');
sb.append(", id=").append(id);
sb.append(", dateTime=").append(dateTime);
sb.append('}');