diff --git a/src/org/redkale/convert/ObjectDecoder.java b/src/org/redkale/convert/ObjectDecoder.java index 3443d1760..76ac7b93d 100644 --- a/src/org/redkale/convert/ObjectDecoder.java +++ b/src/org/redkale/convert/ObjectDecoder.java @@ -6,7 +6,6 @@ package org.redkale.convert; import java.beans.*; -import static org.redkale.convert.ObjectEncoder.TYPEZERO; import org.redkale.util.Creator; import java.lang.reflect.*; import java.util.Arrays; @@ -66,8 +65,6 @@ public final class ObjectDecoder implements Decodeable list = new HashSet(); @@ -78,7 +75,7 @@ public final class ObjectDecoder implements Decodeable implements Decodeable implements Decodeable implements Encodeable list = new HashSet(); + final ConstructorProperties cps = ObjectEncoder.findConstructorProperties(factory.loadCreator(this.typeClass)); + try { + ConvertColumnEntry ref; + for (final Field field : clazz.getFields()) { + if (Modifier.isStatic(field.getModifiers())) continue; + ref = factory.findRef(field); + if (ref != null && ref.ignore()) continue; + Type t = createClassType(field.getGenericType(), this.type); + list.add(new EnMember(createAttribute(factory, clazz, field, null, null), factory.loadEncoder(t))); + } + final boolean reversible = factory.isReversible(); + 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().startsWith("get")) continue; + if (method.getParameterTypes().length != 0) continue; + if (method.getReturnType() == void.class) continue; + if (reversible && (cps == null || !contains(cps.value(), readGetSetFieldName(method)))) { + boolean is = method.getName().startsWith("is"); + try { + clazz.getMethod(method.getName().replaceFirst(is ? "is" : "get", "set"), method.getReturnType()); + } catch (Exception e) { + continue; + } + } + ref = factory.findRef(method); + if (ref != null && ref.ignore()) continue; + Type t = createClassType(method.getGenericReturnType(), this.type); + list.add(new EnMember(createAttribute(factory, clazz, null, method, null), factory.loadEncoder(t))); + } + this.members = list.toArray(new EnMember[list.size()]); + Arrays.sort(this.members); + + } catch (Exception ex) { + throw new ConvertException(ex); + } + } finally { + inited = true; + synchronized (lock) { + lock.notifyAll(); } - if (count == paramTypes.length) return pt; - return new ParameterizedType() { - - @Override - public Type[] getActualTypeArguments() { - return newTypes; - } - - @Override - public Type getRawType() { - return pt.getRawType(); - } - - @Override - public Type getOwnerType() { - return pt.getOwnerType(); - } - - }; } - if (realGenericTypes == null) return type; - if (type instanceof WildcardType) { + } + + @Override + public final void convertTo(W out, T value) { + if (value == null) { + out.wirteClassName(null); + out.writeNull(); + return; + } + if (!this.inited) { + synchronized (lock) { + try { + lock.wait(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + if (value != null && value.getClass() != this.typeClass) { + final Class clz = value.getClass(); + out.wirteClassName(factory.getEntity(clz)); + factory.loadEncoder(clz).convertTo(out, value); + return; + } + out.writeObjectB(members.length, value); + boolean comma = false; + for (EnMember member : members) { + comma = member.write(out, comma, value); + } + out.writeObjectE(value); + } + + @Override + public final Type getType() { + return this.type; + } + + @Override + public String toString() { + return "ObjectEncoder{" + "type=" + type + ", members=" + Arrays.toString(members) + '}'; + } + + static Type createClassType(final Type type, final Type declaringType) { + if (TypeToken.isClassType(type)) return type; + //存在通配符则declaringType 必须是 ParameterizedType + if (!(declaringType instanceof ParameterizedType)) return Object.class; + if (type instanceof ParameterizedType) { // e.g. Map + final ParameterizedType pt = (ParameterizedType) type; + final Type[] paramTypes = pt.getActualTypeArguments(); + for (int i = 0; i < paramTypes.length; i++) { + paramTypes[i] = createClassType(paramTypes[i], declaringType); + } + return TypeToken.createParameterizedType(pt.getOwnerType(), pt.getRawType(), paramTypes); + } + + final ParameterizedType declaringPType = (ParameterizedType) declaringType; + final Type[] virTypes = ((Class) declaringPType.getRawType()).getTypeParameters(); + final Type[] desTypes = declaringPType.getActualTypeArguments(); + if (type instanceof WildcardType) { // e.g. final WildcardType wt = (WildcardType) type; for (Type f : wt.getUpperBounds()) { - for (int i = 0; i < virGenericTypes.length; i++) { - if (virGenericTypes[i] == f) return realGenericTypes.length == 0 ? Object.class : realGenericTypes[i]; + for (int i = 0; i < virTypes.length; i++) { + if (virTypes[i].equals(f)) return desTypes.length <= i ? Object.class : desTypes[i]; } } - } else if (type instanceof TypeVariable) { - for (int i = 0; i < virGenericTypes.length; i++) { - if (virGenericTypes[i] == type) return i >= realGenericTypes.length ? Object.class : realGenericTypes[i]; + } else if (type instanceof TypeVariable) { // e.g. + for (int i = 0; i < virTypes.length; i++) { + if (virTypes[i].equals(type)) return desTypes.length <= i ? Object.class : desTypes[i]; } } return type; } +// +// static Type makeGenericType(final Type type, final Type[] virGenericTypes, final Type[] realGenericTypes) { +// if (type instanceof Class) { //e.g. String +// return type; +// } else if (type instanceof ParameterizedType) { //e.g. Map +// final ParameterizedType pt = (ParameterizedType) type; +// Type[] paramTypes = pt.getActualTypeArguments(); +// final Type[] newTypes = new Type[paramTypes.length]; +// int count = 0; +// for (int i = 0; i < newTypes.length; i++) { +// newTypes[i] = makeGenericType(paramTypes[i], virGenericTypes, realGenericTypes); +// if (paramTypes[i] == newTypes[i]) count++; +// } +// if (count == paramTypes.length) return pt; +// return new ParameterizedType() { +// +// @Override +// public Type[] getActualTypeArguments() { +// return newTypes; +// } +// +// @Override +// public Type getRawType() { +// return pt.getRawType(); +// } +// +// @Override +// public Type getOwnerType() { +// return pt.getOwnerType(); +// } +// +// }; +// } +// if (realGenericTypes == null) return type; +// if (type instanceof WildcardType) { // e.g. +// final WildcardType wt = (WildcardType) type; +// for (Type f : wt.getUpperBounds()) { +// for (int i = 0; i < virGenericTypes.length; i++) { +// if (virGenericTypes[i] == f) return realGenericTypes.length == 0 ? Object.class : realGenericTypes[i]; +// } +// } +// } else if (type instanceof TypeVariable) { // e.g. +// for (int i = 0; i < virGenericTypes.length; i++) { +// if (virGenericTypes[i] == type) return i >= realGenericTypes.length ? Object.class : realGenericTypes[i]; +// } +// } +// return type; +// } static boolean contains(String[] values, String value) { for (String str : values) { @@ -151,102 +276,4 @@ public final class ObjectEncoder implements Encodeable list = new HashSet(); - final Type[] virGenericTypes = this.typeClass.getTypeParameters(); - final Type[] realGenericTypes = (type instanceof ParameterizedType) ? ((ParameterizedType) type).getActualTypeArguments() : null; - if (realGenericTypes != null) { - // println(type + "," + Arrays.toString(virGenericTypes) + ", " + Arrays.toString(realGenericTypes)); - } - final ConstructorProperties cps = ObjectEncoder.findConstructorProperties(factory.loadCreator(this.typeClass)); - try { - ConvertColumnEntry ref; - for (final Field field : clazz.getFields()) { - if (Modifier.isStatic(field.getModifiers())) continue; - ref = factory.findRef(field); - if (ref != null && ref.ignore()) continue; - Type t = makeGenericType(field.getGenericType(), virGenericTypes, realGenericTypes); - list.add(new EnMember(createAttribute(factory, clazz, field, null, null), factory.loadEncoder(t))); - } - final boolean reversible = factory.isReversible(); - 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().startsWith("get")) continue; - if (method.getParameterTypes().length != 0) continue; - if (method.getReturnType() == void.class) continue; - if (reversible && (cps == null || !contains(cps.value(), readGetSetFieldName(method)))) { - boolean is = method.getName().startsWith("is"); - try { - clazz.getMethod(method.getName().replaceFirst(is ? "is" : "get", "set"), method.getReturnType()); - } catch (Exception e) { - continue; - } - } - ref = factory.findRef(method); - if (ref != null && ref.ignore()) continue; - Type t = makeGenericType(method.getGenericReturnType(), virGenericTypes, realGenericTypes); - list.add(new EnMember(createAttribute(factory, clazz, null, method, null), factory.loadEncoder(t))); - } - this.members = list.toArray(new EnMember[list.size()]); - Arrays.sort(this.members); - - } catch (Exception ex) { - throw new ConvertException(ex); - } - } finally { - inited = true; - synchronized (lock) { - lock.notifyAll(); - } - } - } - - @Override - public final void convertTo(W out, T value) { - if (value == null) { - out.wirteClassName(null); - out.writeNull(); - return; - } - if (!this.inited) { - synchronized (lock) { - try { - lock.wait(); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - if (value != null && value.getClass() != this.typeClass) { - final Class clz = value.getClass(); - out.wirteClassName(factory.getEntity(clz)); - factory.loadEncoder(clz).convertTo(out, value); - return; - } - out.writeObjectB(members.length, value); - boolean comma = false; - for (EnMember member : members) { - comma = member.write(out, comma, value); - } - out.writeObjectE(value); - } - - @Override - public final Type getType() { - return this.type; - } - - @Override - public String toString() { - return "ObjectEncoder{" + "type=" + type + ", members=" + Arrays.toString(members) + '}'; - } } diff --git a/src/org/redkale/util/TypeToken.java b/src/org/redkale/util/TypeToken.java index 8920ce899..5382198a4 100644 --- a/src/org/redkale/util/TypeToken.java +++ b/src/org/redkale/util/TypeToken.java @@ -4,8 +4,9 @@ */ package org.redkale.util; -import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; +import java.lang.reflect.*; +import java.util.*; import jdk.internal.org.objectweb.asm.*; import static jdk.internal.org.objectweb.asm.Opcodes.*; @@ -29,7 +30,107 @@ public abstract class TypeToken { return type; } - public static Type createParameterizedType(final Type ownerType, final Type rawType, final Type... actualTypeArguments) { + /** + * 判断Type是否能确定最终的class, 是则返回true,存在通配符或者不确定类型则返回false。 + * 例如: Map< String, String > 返回 ture; Map< ? extends Serializable, String > 返回false; + * + * @param type + * @return + */ + public final static boolean isClassType(final Type type) { + if (type instanceof Class) return true; + if (type instanceof WildcardType) return false; + if (type instanceof TypeVariable) return false; + if (type instanceof GenericArrayType) return isClassType(((GenericArrayType) type).getGenericComponentType()); + if (!(type instanceof ParameterizedType)) return false; //只能是null了 + final ParameterizedType ptype = (ParameterizedType) type; + if (ptype.getOwnerType() != null && !isClassType(ptype.getOwnerType())) return false; + if (!isClassType(ptype.getRawType())) return false; + for (Type t : ptype.getActualTypeArguments()) { + if (!isClassType(t)) return false; + } + return true; + } + + /** + * 动态创建 ParameterizedType + * + * @param ownerType0 + * @param rawType0 + * @param actualTypeArguments0 + * @return + */ + public static Type createParameterizedType(final Type ownerType0, final Type rawType0, final Type... actualTypeArguments0) { + if (ownerType0 == null && rawType0 instanceof Class) { + final Class[] actualClassArguments = new Class[actualTypeArguments0.length]; + int count = 0; + for (int i = 0; i < actualTypeArguments0.length; i++) { + if (actualTypeArguments0[i] instanceof Class) { + actualClassArguments[i] = (Class) actualTypeArguments0[i]; + count++; + } + } + if (count == actualClassArguments.length) return createParameterizedType((Class) rawType0, actualClassArguments); + } + return new ParameterizedType() { + private final Class rawType = (Class) rawType0; + + private final Type ownerType = ownerType0; + + private final Type[] argTypes = actualTypeArguments0; + + @Override + public Type[] getActualTypeArguments() { + return argTypes.clone(); + } + + @Override + public Type getRawType() { + return rawType; + } + + @Override + public Type getOwnerType() { + return ownerType; + } + + @Override + public int hashCode() { + return Arrays.hashCode(argTypes) ^ Objects.hashCode(rawType) ^ Objects.hashCode(ownerType); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof ParameterizedType)) return false; + final ParameterizedType that = (ParameterizedType) o; + if (this == that) return true; + return Objects.equals(ownerType, that.getOwnerType()) + && Objects.equals(rawType, that.getRawType()) + && Arrays.equals(argTypes, that.getActualTypeArguments()); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + if (ownerType != null) sb.append((ownerType instanceof Class) ? (((Class) ownerType).getName()) : ownerType.toString()).append("."); + sb.append(rawType.getName()); + + if (argTypes != null && argTypes.length > 0) { + sb.append("<"); + boolean first = true; + for (Type t : argTypes) { + if (!first) sb.append(", "); + sb.append(t.getTypeName()); + first = false; + } + sb.append(">"); + } + return sb.toString(); + } + }; + } + + private static Type createParameterizedType(final Class rawType, final Class... actualTypeArguments) { ClassLoader loader = TypeToken.class.getClassLoader(); String newDynName = TypeToken.class.getName().replace('.', '/') + "_Dyn" + System.currentTimeMillis(); for (;;) { @@ -44,11 +145,11 @@ public abstract class TypeToken { FieldVisitor fv; MethodVisitor mv; cw.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, "java/lang/Object", null); - String rawTypeDesc = jdk.internal.org.objectweb.asm.Type.getDescriptor((Class) rawType); + String rawTypeDesc = jdk.internal.org.objectweb.asm.Type.getDescriptor(rawType); StringBuilder sb = new StringBuilder(); sb.append(rawTypeDesc.substring(0, rawTypeDesc.length() - 1)).append('<'); - for (Type c : actualTypeArguments) { - sb.append(jdk.internal.org.objectweb.asm.Type.getDescriptor((Class) c)); + for (Class c : actualTypeArguments) { + sb.append(jdk.internal.org.objectweb.asm.Type.getDescriptor(c)); } sb.append(">;"); {