diff --git a/src/main/java/org/redkale/convert/ConvertFactory.java b/src/main/java/org/redkale/convert/ConvertFactory.java index 07e6d2e3e..fa0a37b4e 100644 --- a/src/main/java/org/redkale/convert/ConvertFactory.java +++ b/src/main/java/org/redkale/convert/ConvertFactory.java @@ -553,6 +553,127 @@ public abstract class ConvertFactory { return fname; } + public String readGetSetFieldName(AccessibleObject element) { + if (element instanceof Field) { + return ((Field) element).getName(); + } + return readGetSetFieldName((Method) element); + } + + public boolean isSimpleMemberType(Class declaringClass, Type type, Class clazz) { + if (type == String.class) { + return true; + } + if (clazz.isPrimitive()) { + return true; + } + if (clazz.isEnum()) { + return true; + } + if (type == Boolean.class) { + return true; + } + if (type == Byte.class) { + return true; + } + if (type == Short.class) { + return true; + } + if (type == Character.class) { + return true; + } + if (type == Integer.class) { + return true; + } + if (type == Float.class) { + return true; + } + if (type == Long.class) { + return true; + } + if (type == Double.class) { + return true; + } + if (type == boolean[].class) { + return true; + } + if (type == byte[].class) { + return true; + } + if (type == short[].class) { + return true; + } + if (type == char[].class) { + return true; + } + if (type == int[].class) { + return true; + } + if (type == float[].class) { + return true; + } + if (type == long[].class) { + return true; + } + if (type == double[].class) { + return true; + } + if (type == Boolean[].class) { + return true; + } + if (type == Byte[].class) { + return true; + } + if (type == Short[].class) { + return true; + } + if (type == Character[].class) { + return true; + } + if (type == Integer[].class) { + return true; + } + if (type == Float[].class) { + return true; + } + if (type == Long[].class) { + return true; + } + if (type == Double[].class) { + return true; + } + if (type == String[].class) { + return true; + } + if (rootFactory().findEncoder(type) != null) { + return true; + } + if (declaringClass == clazz) { + return false; + } + if (Collection.class.isAssignableFrom(clazz) && type instanceof ParameterizedType) { + Type[] ts = ((ParameterizedType) type).getActualTypeArguments(); + if (ts.length == 1) { + Type t = ts[0]; + if (t == Boolean.class + || t == Byte.class + || t == Short.class + || t == Character.class + || t == Integer.class + || t == Float.class + || t == Long.class + || t == Double.class + || t == String.class + || rootFactory().findEncoder(t) != null + || ((t instanceof Class) && ((Class) t).isEnum())) { + return true; + } + return false; + } + } + return false; + } + final String getEntityAlias(Class clazz) { if (clazz == String.class) { return "A"; diff --git a/src/main/java/org/redkale/convert/json/JsonDynEncoder.java b/src/main/java/org/redkale/convert/json/JsonDynEncoder.java index e96abd071..f11e2017d 100644 --- a/src/main/java/org/redkale/convert/json/JsonDynEncoder.java +++ b/src/main/java/org/redkale/convert/json/JsonDynEncoder.java @@ -42,121 +42,6 @@ public abstract class JsonDynEncoder implements Encodeable { return false; } - private static boolean checkMemberType( - final JsonFactory factory, final Class declaringClass, Type type, Class clazz) { - if (type == String.class) { - return true; - } - if (clazz.isPrimitive()) { - return true; - } - if (clazz.isEnum()) { - return true; - } - if (type == Boolean.class) { - return true; - } - if (type == Byte.class) { - return true; - } - if (type == Short.class) { - return true; - } - if (type == Character.class) { - return true; - } - if (type == Integer.class) { - return true; - } - if (type == Float.class) { - return true; - } - if (type == Long.class) { - return true; - } - if (type == Double.class) { - return true; - } - if (type == boolean[].class) { - return true; - } - if (type == byte[].class) { - return true; - } - if (type == short[].class) { - return true; - } - if (type == char[].class) { - return true; - } - if (type == int[].class) { - return true; - } - if (type == float[].class) { - return true; - } - if (type == long[].class) { - return true; - } - if (type == double[].class) { - return true; - } - if (type == Boolean[].class) { - return true; - } - if (type == Byte[].class) { - return true; - } - if (type == Short[].class) { - return true; - } - if (type == Character[].class) { - return true; - } - if (type == Integer[].class) { - return true; - } - if (type == Float[].class) { - return true; - } - if (type == Long[].class) { - return true; - } - if (type == Double[].class) { - return true; - } - if (type == String[].class) { - return true; - } - if (factory.rootFactory().findEncoder(type) != null) { - return true; - } - if (declaringClass == clazz) { - return false; - } - if (Collection.class.isAssignableFrom(clazz) && type instanceof ParameterizedType) { - Type[] ts = ((ParameterizedType) type).getActualTypeArguments(); - if (ts.length == 1) { - Type t = ts[0]; - if (t == Boolean.class - || t == Byte.class - || t == Short.class - || t == Character.class - || t == Integer.class - || t == Float.class - || t == Long.class - || t == Double.class - || t == String.class - || factory.rootFactory().findEncoder(t) != null - || ((t instanceof Class) && ((Class) t).isEnum())) { - return true; - } - return false; - } - } - return false; - } - // 字段全部是primitive或String类型,且没有泛型的类才能动态生成JsonDynEncoder, 不支持的返回null public static JsonDynEncoder createDyncEncoder(final JsonFactory factory, final Type type) { if (!(type instanceof Class)) { @@ -239,7 +124,7 @@ public abstract class JsonDynEncoder implements Encodeable { if (factory.findFieldCoder(clazz, field.getName()) != null) { return null; } - if (!(checkMemberType(factory, clazz, field.getGenericType(), field.getType()))) { + if (!factory.isSimpleMemberType(clazz, field.getGenericType(), field.getType())) { return null; } String name = convertFieldName(factory, clazz, field); @@ -290,7 +175,7 @@ public abstract class JsonDynEncoder implements Encodeable { if (ref != null && ref.fieldFunc() != null) { return null; } - if (!(checkMemberType(factory, clazz, method.getGenericReturnType(), method.getReturnType()))) { + if (!factory.isSimpleMemberType(clazz, method.getGenericReturnType(), method.getReturnType())) { return null; } String name = convertFieldName(factory, clazz, method); @@ -319,8 +204,8 @@ public abstract class JsonDynEncoder implements Encodeable { return idx1 - idx2; } } - String n1 = ref1 == null || ref1.name().isEmpty() ? readGetSetFieldName(o1) : ref1.name(); - String n2 = ref2 == null || ref2.name().isEmpty() ? readGetSetFieldName(o2) : ref2.name(); + String n1 = ref1 == null || ref1.name().isEmpty() ? factory.readGetSetFieldName(o1) : ref1.name(); + String n2 = ref2 == null || ref2.name().isEmpty() ? factory.readGetSetFieldName(o2) : ref2.name(); if (n1 == null && n2 == null) { return 0; } @@ -341,11 +226,11 @@ public abstract class JsonDynEncoder implements Encodeable { protected static String convertFieldName(final JsonFactory factory, Class clazz, AccessibleObject element) { ConvertColumnEntry ref = factory.findRef(clazz, element); - String name = ref == null || ref.name().isEmpty() ? readGetSetFieldName(element) : ref.name(); + String name = ref == null || ref.name().isEmpty() ? factory.readGetSetFieldName(element) : ref.name(); return name; } - protected static ConvertSmallString readConvertSmallString(AccessibleObject element) { + protected static ConvertSmallString readConvertSmallString(JsonFactory factory, AccessibleObject element) { if (element instanceof Field) { return ((Field) element).getAnnotation(ConvertSmallString.class); } @@ -353,7 +238,7 @@ public abstract class JsonDynEncoder implements Encodeable { ConvertSmallString small = method.getAnnotation(ConvertSmallString.class); if (small == null) { try { - Field f = method.getDeclaringClass().getDeclaredField(readGetSetFieldName(method)); + Field f = method.getDeclaringClass().getDeclaredField(factory.readGetSetFieldName(method)); if (f != null) { small = f.getAnnotation(ConvertSmallString.class); } @@ -371,26 +256,6 @@ public abstract class JsonDynEncoder implements Encodeable { return ((Method) element).getReturnType(); } - protected static String readGetSetFieldName(AccessibleObject element) { - if (element instanceof Field) { - return ((Field) element).getName(); - } - Method method = (Method) element; - String fname = method.getName(); - if (!(fname.startsWith("is") && fname.length() > 2) - && !(fname.startsWith("get") && fname.length() > 3) - && !(fname.startsWith("set") && fname.length() > 3)) { - return fname; - } - fname = fname.substring(fname.startsWith("is") ? 2 : 3); - if (fname.length() > 1 && !(fname.charAt(1) >= 'A' && fname.charAt(1) <= 'Z')) { - fname = Character.toLowerCase(fname.charAt(0)) + fname.substring(1); - } else if (fname.length() == 1) { - fname = "" + Character.toLowerCase(fname.charAt(0)); - } - return fname; - } - protected static JsonDynEncoder generateDyncEncoder( final JsonFactory factory, final Class clazz, final List members) { final ObjectEncoder selfObjEncoder = factory.createObjectEncoder(clazz); @@ -415,7 +280,8 @@ public abstract class JsonDynEncoder implements Encodeable { StringBuilder memberb = new StringBuilder(); for (AccessibleObject element : members) { ConvertColumnEntry ref1 = factory.findRef(clazz, element); - final String fieldname = ref1 == null || ref1.name().isEmpty() ? readGetSetFieldName(element) : ref1.name(); + final String fieldname = + ref1 == null || ref1.name().isEmpty() ? factory.readGetSetFieldName(element) : ref1.name(); memberb.append(fieldname).append(','); final Class fieldType = readGetSetFieldType(element); if (fieldType != String.class && !fieldType.isPrimitive()) { @@ -478,7 +344,8 @@ public abstract class JsonDynEncoder implements Encodeable { int intFieldCount = 0; for (AccessibleObject element : members) { ConvertColumnEntry ref1 = factory.findRef(clazz, element); - final String fieldname = ref1 == null || ref1.name().isEmpty() ? readGetSetFieldName(element) : ref1.name(); + final String fieldname = + ref1 == null || ref1.name().isEmpty() ? factory.readGetSetFieldName(element) : ref1.name(); fv = cw.visitField(ACC_PROTECTED + ACC_FINAL, fieldname + "FieldBytes", "[B", null, null); fv.visitEnd(); fv = cw.visitField(ACC_PROTECTED + ACC_FINAL, fieldname + "CommaFieldBytes", "[B", null, null); @@ -499,12 +366,12 @@ public abstract class JsonDynEncoder implements Encodeable { if (fieldType == int.class) { intFieldCount++; } - if (fieldType == String.class && membersSize == 1 && readConvertSmallString(element) != null) { + if (fieldType == String.class && membersSize == 1 && readConvertSmallString(factory, element) != null) { onlyOneLatin1FieldObjectFlag = true; } else if (fieldType != short.class && fieldType != int.class && fieldType != long.class - && !(fieldType == String.class && readConvertSmallString(element) != null)) { + && !(fieldType == String.class && readConvertSmallString(factory, element) != null)) { onlyShotIntLongLatin1MoreFieldObjectFlag = false; } } @@ -525,7 +392,7 @@ public abstract class JsonDynEncoder implements Encodeable { for (AccessibleObject element : members) { ConvertColumnEntry ref1 = factory.findRef(clazz, element); final String fieldname = - ref1 == null || ref1.name().isEmpty() ? readGetSetFieldName(element) : ref1.name(); + ref1 == null || ref1.name().isEmpty() ? factory.readGetSetFieldName(element) : ref1.name(); // xxxFieldBytes mv.visitVarInsn(ALOAD, 0); mv.visitLdcInsn("\"" + fieldname + "\":"); @@ -610,7 +477,7 @@ public abstract class JsonDynEncoder implements Encodeable { AccessibleObject element = members.get(elementIndex); ConvertColumnEntry ref1 = factory.findRef(clazz, element); final String fieldName = - ref1 == null || ref1.name().isEmpty() ? readGetSetFieldName(element) : ref1.name(); + ref1 == null || ref1.name().isEmpty() ? factory.readGetSetFieldName(element) : ref1.name(); final Class fieldtype = readGetSetFieldType(element); mv.visitVarInsn(ALOAD, 1); @@ -646,14 +513,14 @@ public abstract class JsonDynEncoder implements Encodeable { AccessibleObject element1 = members.get(elementIndex); ConvertColumnEntry ref1 = factory.findRef(clazz, element1); final String fieldName1 = - ref1 == null || ref1.name().isEmpty() ? readGetSetFieldName(element1) : ref1.name(); + ref1 == null || ref1.name().isEmpty() ? factory.readGetSetFieldName(element1) : ref1.name(); final Class fieldType1 = readGetSetFieldType(element1); elementIndex++; AccessibleObject element2 = members.get(elementIndex); ConvertColumnEntry ref2 = factory.findRef(clazz, element2); final String fieldName2 = - ref2 == null || ref2.name().isEmpty() ? readGetSetFieldName(element2) : ref2.name(); + ref2 == null || ref2.name().isEmpty() ? factory.readGetSetFieldName(element2) : ref2.name(); final Class fieldtype2 = readGetSetFieldType(element2); mv.visitVarInsn(ALOAD, 1); @@ -710,7 +577,7 @@ public abstract class JsonDynEncoder implements Encodeable { elementIndex++; ConvertColumnEntry ref1 = factory.findRef(clazz, element); final String fieldname = - ref1 == null || ref1.name().isEmpty() ? readGetSetFieldName(element) : ref1.name(); + ref1 == null || ref1.name().isEmpty() ? factory.readGetSetFieldName(element) : ref1.name(); final Class fieldtype = readGetSetFieldType(element); mv.visitVarInsn(ALOAD, 1); @@ -793,7 +660,7 @@ public abstract class JsonDynEncoder implements Encodeable { elementIndex++; ConvertColumnEntry ref1 = factory.findRef(clazz, element); final String fieldname = - ref1 == null || ref1.name().isEmpty() ? readGetSetFieldName(element) : ref1.name(); + ref1 == null || ref1.name().isEmpty() ? factory.readGetSetFieldName(element) : ref1.name(); final Class fieldtype = readGetSetFieldType(element); int storeid = ASTORE; int loadid = ALOAD; @@ -972,7 +839,7 @@ public abstract class JsonDynEncoder implements Encodeable { mv.visitVarInsn(loadid, maxLocals); mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeDouble", "(D)V", false); } else if (fieldtype == String.class) { - if (readConvertSmallString(element) == null) { + if (readConvertSmallString(factory, element) == null) { mv.visitVarInsn(ALOAD, 1); mv.visitVarInsn(loadid, maxLocals); mv.visitMethodInsn( diff --git a/src/main/java/org/redkale/convert/pb/ProtobufDynEncoder.java b/src/main/java/org/redkale/convert/pb/ProtobufDynEncoder.java new file mode 100644 index 000000000..816b6632c --- /dev/null +++ b/src/main/java/org/redkale/convert/pb/ProtobufDynEncoder.java @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2016-2116 Redkale + * All rights reserved. + */ +package org.redkale.convert.pb; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import org.redkale.convert.ConvertColumnEntry; +import org.redkale.convert.Encodeable; +import org.redkale.convert.ObjectEncoder; +import org.redkale.convert.ext.BoolArraySimpledCoder; +import org.redkale.convert.ext.BoolSimpledCoder; +import org.redkale.convert.ext.ByteArraySimpledCoder; +import org.redkale.convert.ext.ByteSimpledCoder; +import org.redkale.convert.ext.CharArraySimpledCoder; +import org.redkale.convert.ext.CharSimpledCoder; +import org.redkale.convert.ext.DoubleArraySimpledCoder; +import org.redkale.convert.ext.DoubleSimpledCoder; +import org.redkale.convert.ext.FloatArraySimpledCoder; +import org.redkale.convert.ext.FloatSimpledCoder; +import org.redkale.convert.ext.IntArraySimpledCoder; +import org.redkale.convert.ext.IntSimpledCoder; +import org.redkale.convert.ext.LongArraySimpledCoder; +import org.redkale.convert.ext.LongSimpledCoder; +import org.redkale.convert.ext.ShortArraySimpledCoder; +import org.redkale.convert.ext.ShortSimpledCoder; +import org.redkale.convert.ext.StringArraySimpledCoder; +import org.redkale.convert.ext.StringSimpledCoder; +import org.redkale.util.RedkaleClassLoader; + +/** + * 简单对象的PROTOBUF序列化操作类 + * + *

详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + * @param 序列化的数据类型 + */ +public abstract class ProtobufDynEncoder implements Encodeable { + + public abstract void init(final ProtobufFactory factory); + + // 字段全部是primitive或String类型,且没有泛型的类才能动态生成ProtobufDynEncoder, 不支持的返回null + public static ProtobufDynEncoder createDyncEncoder(final ProtobufFactory factory, final Type type) { + if (!(type instanceof Class)) { + return null; + } + // 发现有自定义的基础数据类型Encoder就不动态生成ProtobufDynEncoder了 + if (factory.loadEncoder(boolean.class) != BoolSimpledCoder.instance) { + return null; + } + if (factory.loadEncoder(byte.class) != ByteSimpledCoder.instance) { + return null; + } + if (factory.loadEncoder(short.class) != ShortSimpledCoder.instance) { + return null; + } + if (factory.loadEncoder(char.class) != CharSimpledCoder.instance) { + return null; + } + if (factory.loadEncoder(int.class) != IntSimpledCoder.instance) { + return null; + } + if (factory.loadEncoder(float.class) != FloatSimpledCoder.instance) { + return null; + } + if (factory.loadEncoder(long.class) != LongSimpledCoder.instance) { + return null; + } + if (factory.loadEncoder(double.class) != DoubleSimpledCoder.instance) { + return null; + } + if (factory.loadEncoder(String.class) != StringSimpledCoder.instance) { + return null; + } + // array + if (factory.loadEncoder(boolean[].class) != BoolArraySimpledCoder.instance) { + return null; + } + if (factory.loadEncoder(byte[].class) != ByteArraySimpledCoder.instance) { + return null; + } + if (factory.loadEncoder(short[].class) != ShortArraySimpledCoder.instance) { + return null; + } + if (factory.loadEncoder(char[].class) != CharArraySimpledCoder.instance) { + return null; + } + if (factory.loadEncoder(int[].class) != IntArraySimpledCoder.instance) { + return null; + } + if (factory.loadEncoder(float[].class) != FloatArraySimpledCoder.instance) { + return null; + } + if (factory.loadEncoder(long[].class) != LongArraySimpledCoder.instance) { + return null; + } + if (factory.loadEncoder(double[].class) != DoubleArraySimpledCoder.instance) { + return null; + } + if (factory.loadEncoder(String[].class) != StringArraySimpledCoder.instance) { + return null; + } + + final Class clazz = (Class) type; + List members = null; + Set names = new HashSet<>(); + try { + ConvertColumnEntry ref; + RedkaleClassLoader.putReflectionPublicFields(clazz.getName()); + for (final Field field : clazz.getFields()) { + if (Modifier.isStatic(field.getModifiers())) { + continue; + } + if (factory.isConvertDisabled(field)) { + continue; + } + ref = factory.findRef(clazz, field); + if (ref != null && ref.ignore()) { + continue; + } + if (factory.findFieldCoder(clazz, field.getName()) != null) { + return null; + } + if (!factory.isSimpleMemberType(clazz, field.getGenericType(), field.getType())) { + return null; + } + String name = convertFieldName(factory, clazz, field); + if (names.contains(name)) { + continue; + } + names.add(name); + if (members == null) { + members = new ArrayList<>(); + } + members.add(field); + } + RedkaleClassLoader.putReflectionPublicMethods(clazz.getName()); + for (final Method method : clazz.getMethods()) { + if (Modifier.isStatic(method.getModifiers())) { + continue; + } + if (Modifier.isAbstract(method.getModifiers())) { + continue; + } + if (method.isSynthetic()) { + continue; + } + if (method.getName().length() < 3) { + continue; + } + if (method.getName().equals("getClass")) { + continue; + } + if (!(method.getName().startsWith("is") && method.getName().length() > 2) + && !(method.getName().startsWith("get") + && method.getName().length() > 3)) { + continue; + } + if (factory.isConvertDisabled(method)) { + continue; + } + if (method.getParameterTypes().length != 0) { + continue; + } + if (method.getReturnType() == void.class) { + continue; + } + ref = factory.findRef(clazz, method); + if (ref != null && ref.ignore()) { + continue; + } + if (ref != null && ref.fieldFunc() != null) { + return null; + } + if (!factory.isSimpleMemberType(clazz, method.getGenericReturnType(), method.getReturnType())) { + return null; + } + String name = convertFieldName(factory, clazz, method); + if (names.contains(name)) { + continue; + } + if (factory.findFieldCoder(clazz, name) != null) { + return null; + } + names.add(name); + if (members == null) { + members = new ArrayList<>(); + } + members.add(method); + } + if (members == null) { + return null; + } + Collections.sort(members, (o1, o2) -> { + ConvertColumnEntry ref1 = factory.findRef(clazz, o1); + ConvertColumnEntry ref2 = factory.findRef(clazz, o2); + if ((ref1 != null && ref1.getIndex() > 0) || (ref2 != null && ref2.getIndex() > 0)) { + int idx1 = ref1 == null ? Integer.MAX_VALUE / 2 : ref1.getIndex(); + int idx2 = ref2 == null ? Integer.MAX_VALUE / 2 : ref2.getIndex(); + if (idx1 != idx2) { + return idx1 - idx2; + } + } + String n1 = ref1 == null || ref1.name().isEmpty() ? factory.readGetSetFieldName(o1) : ref1.name(); + String n2 = ref2 == null || ref2.name().isEmpty() ? factory.readGetSetFieldName(o2) : ref2.name(); + if (n1 == null && n2 == null) { + return 0; + } + if (n1 == null) { + return -1; + } + if (n2 == null) { + return 1; + } + return n1.compareTo(n2); + }); + return generateDyncEncoder(factory, clazz, members); + } catch (Exception ex) { + ex.printStackTrace(); + return null; + } + } + + protected static String convertFieldName(final ProtobufFactory factory, Class clazz, AccessibleObject element) { + ConvertColumnEntry ref = factory.findRef(clazz, element); + String name = ref == null || ref.name().isEmpty() ? factory.readGetSetFieldName(element) : ref.name(); + return name; + } + + protected static ProtobufDynEncoder generateDyncEncoder( + final ProtobufFactory factory, final Class clazz, final List members) { + final ObjectEncoder selfObjEncoder = factory.createObjectEncoder(clazz); + selfObjEncoder.init(factory); + if (selfObjEncoder.getMembers().length != members.size()) { + return null; // 存在ignore等定制配置 + } + return null; + } +} diff --git a/src/main/java/org/redkale/convert/pb/ProtobufFactory.java b/src/main/java/org/redkale/convert/pb/ProtobufFactory.java index 94963965a..32c7b17c5 100644 --- a/src/main/java/org/redkale/convert/pb/ProtobufFactory.java +++ b/src/main/java/org/redkale/convert/pb/ProtobufFactory.java @@ -91,6 +91,11 @@ public class ProtobufFactory extends ConvertFactory Encodeable createDyncEncoder(Type type) { + return ProtobufDynEncoder.createDyncEncoder(this, type); + } + @Override protected SimpledCoder createEnumSimpledCoder(Class enumClass) { return new ProtobufEnumSimpledCoder(enumClass, this.enumtostring);