Files
redkale/com/wentch/redkale/convert/ObjectEncoder.java
地平线 ac6a2e57c6
2015-09-22 17:34:27 +08:00

215 lines
8.7 KiB
Java

/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.wentch.redkale.convert;
import com.wentch.redkale.util.Attribute;
import com.wentch.redkale.util.Attribute.Attributes;
import java.lang.reflect.*;
import java.util.*;
/**
*
* @author zhangjx
* @param <W>
* @param <T>
*/
@SuppressWarnings("unchecked")
public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
static final Type[] TYPEZERO = new Type[0];
protected final Type type;
protected final Class typeClass;
protected EnMember[] members;
protected Factory factory;
protected ObjectEncoder(Type type) {
this.type = type;
if (type instanceof ParameterizedType) {
final ParameterizedType pt = (ParameterizedType) type;
this.typeClass = (Class) pt.getRawType();
} else {
this.typeClass = (Class) type;
}
this.members = new EnMember[0];
}
static Type makeGenericType(final Type type, final Type[] virGenericTypes, final Type[] realGenericTypes) {
if (type instanceof Class) {
return type;
} else if (type instanceof ParameterizedType) {
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) {
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) {
for (int i = 0; i < virGenericTypes.length; i++) {
if (virGenericTypes[i] == type) return i >= realGenericTypes.length ? Object.class : realGenericTypes[i];
}
}
return type;
}
private static String readGetSetFieldName(Method method) {
if (method == null) return null;
String fname = method.getName();
if (!fname.startsWith("is") && !fname.startsWith("get") && !fname.startsWith("set")) 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;
}
static Attribute createAttribute(final Factory factory, Class clazz, final Field field, final Method getter, final Method setter) {
String fieldalias = null;
if (field != null) { // public field
ConvertColumnEntry ref = factory.findRef(field);
fieldalias = ref == null || ref.name().isEmpty() ? field.getName() : ref.name();
} else if (getter != null) {
ConvertColumnEntry ref = factory.findRef(getter);
String mfieldname = readGetSetFieldName(getter);
if (ref == null) {
try {
ref = factory.findRef(clazz.getDeclaredField(mfieldname));
} catch (Exception e) {
}
}
fieldalias = ref == null || ref.name().isEmpty() ? mfieldname : ref.name();
} else { // setter != null
ConvertColumnEntry ref = factory.findRef(setter);
String mfieldname = readGetSetFieldName(setter);
if (ref == null) {
try {
ref = factory.findRef(clazz.getDeclaredField(mfieldname));
} catch (Exception e) {
}
}
fieldalias = ref == null || ref.name().isEmpty() ? mfieldname : ref.name();
}
return Attributes.create(clazz, fieldalias, field, getter, setter);
}
public void init(final Factory factory) {
this.factory = factory;
if (type == Object.class) return;
//if (!(type instanceof Class)) throw new ConvertException("[" + type + "] is no a class");
final Class clazz = this.typeClass;
final Set<EnMember> 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));
}
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) {
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);
}
}
@Override
public final void convertTo(W out, T value) {
if (value == null) {
out.wirteClassName(null);
out.writeNull();
return;
}
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) + '}';
}
}