Merge pull request #72 from veione/feat_storage

fix[storage]:修复storage加入record生成协议报错
This commit is contained in:
godotg
2023-09-14 10:09:42 +08:00
committed by GitHub
6 changed files with 87 additions and 27 deletions
@@ -30,6 +30,7 @@ import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.stream.Collectors;
/**
* 对应于ProtocolRegistration
@@ -181,6 +182,9 @@ public abstract class EnhanceUtils {
var fieldRegistrations = registration.getFieldRegistrations();
var packetClazz = constructor.getDeclaringClass();
if (packetClazz.isRecord()) {
fields = registration.getOriginalFields();
}
var builder = new StringBuilder();
builder.append("{").append(packetClazz.getCanonicalName() + " packet = (" + packetClazz.getCanonicalName() + ")$2;");
@@ -204,28 +208,46 @@ public abstract class EnhanceUtils {
// see: ProtocolRegistration.read()
private static String readMethodBody(ProtocolRegistration registration) {
var constructor = registration.getConstructor();
var fields = registration.getFields();
var fieldRegistrations = registration.getFieldRegistrations();
var builder = new StringBuilder();
builder.append("{").append("if(!" + EnhanceUtils.byteBufUtilsReadBoolean + "){").append("return null;}");
var packetClazz = constructor.getDeclaringClass();
builder.append(packetClazz.getCanonicalName() + " packet=new " + packetClazz.getCanonicalName() + "();");
if (packetClazz.isRecord()) {
var fields = registration.getOriginalFields();
List<String> constructorParam = new ArrayList<>(fields.length);
for (var i = 0; i < fields.length; i++) {
var field = fields[i];
var fieldRegistration = fieldRegistrations[i];
// protocol backwards compatibility,协议向后兼容
if (field.isAnnotationPresent(Compatible.class)) {
builder.append("if(!$1.isReadable()){ return packet; }");
}
for (var i = 0; i < fields.length; i++) {
var field = fields[i];
var fieldRegistration = fieldRegistrations[i];
// protocol backwards compatibility,协议向后兼容
if (field.isAnnotationPresent(Compatible.class)) {
builder.append("if(!$1.isReadable()){ return packet; }");
var readObject = enhanceSerializer(fieldRegistration.serializer()).readObject(builder, field, fieldRegistration);
constructorParam.add(readObject);
}
var readObject = enhanceSerializer(fieldRegistration.serializer()).readObject(builder, field, fieldRegistration);
builder.append(packetClazz.getCanonicalName() + " packet=new " + packetClazz.getCanonicalName() + "(" + constructorParam.stream().collect(Collectors.joining(StringUtils.COMMA)) + ");");
} else {
var fields = registration.getFields();
builder.append(packetClazz.getCanonicalName() + " packet=new " + packetClazz.getCanonicalName() + "();");
if (Modifier.isPublic(field.getModifiers())) {
builder.append(StringUtils.format("packet.{}={};", field.getName(), readObject));
} else {
builder.append(StringUtils.format("packet.{}({});", ReflectionUtils.fieldToSetMethod(packetClazz, field), readObject));
for (var i = 0; i < fields.length; i++) {
var field = fields[i];
var fieldRegistration = fieldRegistrations[i];
// protocol backwards compatibility,协议向后兼容
if (field.isAnnotationPresent(Compatible.class)) {
builder.append("if(!$1.isReadable()){ return packet; }");
}
var readObject = enhanceSerializer(fieldRegistration.serializer()).readObject(builder, field, fieldRegistration);
if (Modifier.isPublic(field.getModifiers())) {
builder.append(StringUtils.format("packet.{}={};", field.getName(), readObject));
} else {
builder.append(StringUtils.format("packet.{}({});", ReflectionUtils.fieldToSetMethod(packetClazz, field), readObject));
}
}
}
@@ -42,6 +42,7 @@ import javassist.NotFoundException;
import java.io.IOException;
import java.lang.reflect.*;
import java.util.*;
import java.util.Map.Entry;
import static com.zfoo.protocol.ProtocolManager.*;
@@ -311,6 +312,7 @@ public class ProtocolAnalysis {
enhanceProtocolRegistration(enhanceList);
enhanceProtocolAfter(generateOperation);
} catch (Exception e) {
e.printStackTrace();
throw new UnknownException(e);
}
}
@@ -377,15 +379,16 @@ public class ProtocolAnalysis {
GenerateProtobufUtils.clear();
}
private static List<Field> customFieldOrder(Class<?> clazz) {
private static Entry<ArrayList<Field>, List<Field>> customFieldOrder(Class<?> clazz) {
var notCompatibleFields = new ArrayList<Field>();
var compatibleFieldMap = new HashMap<Integer, Field>();
List<Field> originalFields = new ArrayList<>();
for (var field : clazz.getDeclaredFields()) {
var modifiers = field.getModifiers();
if (Modifier.isTransient(modifiers) || Modifier.isStatic(modifiers)) {
continue;
}
if (Modifier.isFinal(modifiers)) {
if (!clazz.isRecord() && Modifier.isFinal(modifiers)) {
throw new RunException("[{}]协议号中的[field:{}]属性的访问修饰符不能为final", clazz.getCanonicalName(), field.getName());
}
if (!Modifier.isPublic(modifiers) && !Modifier.isPrivate(modifiers)) {
@@ -400,6 +403,7 @@ public class ProtocolAnalysis {
throw new RunException("[{}]协议号中的[field:{}]和[field:{}]不能有相同的Compatible顺序[order:{}]", clazz.getCanonicalName(), oldField.getName(), field.getName(), oldField, order);
}
} else {
originalFields.add(field);
notCompatibleFields.add(field);
}
}
@@ -415,26 +419,37 @@ public class ProtocolAnalysis {
.map(Map.Entry::getValue)
.toList();
notCompatibleFields.addAll(compatibleFields);
return notCompatibleFields;
return Map.entry(notCompatibleFields, originalFields);
}
private static ProtocolRegistration parseProtocolRegistration(Class<?> clazz, ProtocolModule module) {
var protocolId = ProtocolManager.protocolId(clazz);
// 对象需要被序列化的属性
var fields = customFieldOrder(clazz);
var fieldsEntry = customFieldOrder(clazz);
try {
var registrationList = new ArrayList<IFieldRegistration>();
List<Field> fields = fieldsEntry.getKey();
if (clazz.isRecord()) {
fields = fieldsEntry.getValue();
}
for (var field : fields) {
registrationList.add(toRegistration(clazz, field));
}
var constructor = clazz.getDeclaredConstructor();
Constructor constructor;
if (clazz.isRecord()) {
constructor = ReflectionUtils.getConstructor(clazz, fields.stream().map(p -> p.getType()).toList().toArray(new Class[]{}));
} else {
constructor = clazz.getDeclaredConstructor();
}
ReflectionUtils.makeAccessible(constructor);
var protocol = new ProtocolRegistration();
protocol.setId(protocolId);
protocol.setConstructor(constructor);
protocol.setFields(ArrayUtils.listToArray(fields, Field.class));
protocol.setFields(ArrayUtils.listToArray(fieldsEntry.getKey(), Field.class));
protocol.setOriginalFields(ArrayUtils.listToArray(fieldsEntry.getValue(), Field.class));
protocol.setFieldRegistrations(ArrayUtils.listToArray(registrationList, IFieldRegistration.class));
protocol.setModule(module.getId());
return protocol;
@@ -630,8 +645,10 @@ public class ProtocolAnalysis {
// 不能是泛型类
AssertionUtils.isTrue(ArrayUtils.isEmpty(clazz.getTypeParameters()), "[class:{}]不能是泛型类", clazz.getCanonicalName());
// 必须要有一个空的构造器
Constructor<?> constructor = ReflectionUtils.publicEmptyConstructor(clazz);
// 普通Pojo必须要有一个空的构造器
if (!clazz.isRecord()) {
Constructor<?> constructor = ReflectionUtils.publicEmptyConstructor(clazz);
}
var protocolAnnotation = clazz.getDeclaredAnnotation(Protocol.class);
short protocolId = -1;
@@ -38,6 +38,8 @@ public class ProtocolRegistration implements IProtocolRegistration {
*/
private IFieldRegistration[] fieldRegistrations;
private Field[] originalFields;
public ProtocolRegistration() {
}
@@ -122,6 +124,14 @@ public class ProtocolRegistration implements IProtocolRegistration {
this.fields = fields;
}
public Field[] getOriginalFields() {
return originalFields;
}
public void setOriginalFields(Field[] originalFields) {
this.originalFields = originalFields;
}
public IFieldRegistration[] getFieldRegistrations() {
return fieldRegistrations;
}
@@ -393,8 +393,10 @@ public abstract class ClassUtils {
ReflectionUtils.assertIsPojoClass(clazz);
// 不能是泛型类
AssertionUtils.isTrue(ArrayUtils.isEmpty(clazz.getTypeParameters()), "[class:{}]不能是泛型类", clazz.getCanonicalName());
// 必须要有一个空的构造器
ReflectionUtils.publicEmptyConstructor(clazz);
// 普通Pojo必须要有一个空的构造器
if (!clazz.isRecord()) {
ReflectionUtils.publicEmptyConstructor(clazz);
}
var filedList = ReflectionUtils.notStaticAndTransientFields(clazz);
@@ -75,7 +75,7 @@ public abstract class ReflectionUtils {
}
public static boolean isPojoClass(Class<?> clazz) {
return clazz.getSuperclass().equals(Object.class);
return clazz.getSuperclass().equals(Object.class) || clazz.isRecord();
}
public static void assertIsPojoClass(Class<?> clazz) {
@@ -322,11 +322,14 @@ public abstract class ReflectionUtils {
public static String fieldToGetMethod(Class<?> clazz, Field field) {
var fieldName = field.getName();
assertIsStandardFieldName(field);
var methodName = "get" + StringUtils.capitalize(fieldName);
if (clazz.isRecord()) {
methodName = fieldName;
}
try {
clazz.getDeclaredMethod(methodName);
return methodName;
@@ -358,6 +361,11 @@ public abstract class ReflectionUtils {
assertIsStandardFieldName(field);
var methodName = "set" + StringUtils.capitalize(fieldName);
if (clazz.isRecord()) {
return methodName;
}
try {
clazz.getDeclaredMethod(methodName, field.getType());
return methodName;
@@ -12,6 +12,7 @@
package com.zfoo.storage.export;
import com.zfoo.protocol.ProtocolManager;
import com.zfoo.protocol.buffer.ByteBufUtils;
import com.zfoo.protocol.generate.GenerateOperation;
import com.zfoo.protocol.serializer.CodeLanguage;
@@ -102,12 +103,12 @@ public class ExportBinaryTesting {
var operation = new GenerateOperation();
operation.setProtocolPath("D:\\github\\godot-bird\\test\\storage\\protocol");
operation.getGenerateLanguages().add(CodeLanguage.GdScript);
//ProtocolManager.initProtocolAuto(protocols, operation);
ProtocolManager.initProtocolAuto(protocols, operation);
// 生成数据
var resourceData = ExportUtils.autoWrapData(ResourceData.class, storageManager.storageMap());
var buffer = new UnpooledHeapByteBuf(ByteBufAllocator.DEFAULT, 100, Integer.MAX_VALUE);
//ProtocolManager.write(buffer, resourceData);
ProtocolManager.write(buffer, resourceData);
var bytes = ByteBufUtils.readAllBytes(buffer);
FileUtils.writeInputStreamToFile(new File("D:/github/godot-bird/binary_data.cfg"), new ByteArrayInputStream(bytes));