Files
redkale/src/main/java/org/redkale/convert/ConvertFactory.java
2023-02-01 19:17:32 +08:00

1342 lines
55 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* 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 org.redkale.convert;
import java.io.File;
import java.lang.reflect.*;
import java.math.*;
import java.net.*;
import java.nio.ByteBuffer;
import java.nio.channels.CompletionHandler;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util.concurrent.locks.ReentrantLock;
import java.util.regex.Pattern;
import java.util.stream.*;
import org.redkale.annotation.ConstructorParameters;
import org.redkale.convert.bson.BsonConvert;
import org.redkale.convert.ext.*;
import org.redkale.convert.json.JsonConvert;
import org.redkale.util.*;
/**
* 序列化模块的工厂类用于注册自定义的序列化类型获取Convert
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类
* @param <W> Writer输出的子类
*/
@SuppressWarnings("unchecked")
public abstract class ConvertFactory<R extends Reader, W extends Writer> {
private static final AtomicBoolean loaderInited = new AtomicBoolean();
private static Convert defProtobufConvert;
private final ConvertFactory parent;
protected Convert<R, W> convert;
protected boolean tiny; //String类型值为""Boolean类型值为false时是否需要输出 默认为false
private final Encodeable<W, ?> anyEncoder = new AnyEncoder(this);
//-----------------------------------------------------------------------------------
private final ConcurrentHashMap<Class, Creator> creators = new ConcurrentHashMap();
private final ConcurrentHashMap<String, Class> entitys = new ConcurrentHashMap();
private final ConcurrentHashMap<Type, Map<String, SimpledCoder<R, W, ?>>> fieldCoders = new ConcurrentHashMap();
private final ConcurrentHashMap<Type, Decodeable<R, ?>> decoders = new ConcurrentHashMap();
private final ConcurrentHashMap<Type, Encodeable<W, ?>> encoders = new ConcurrentHashMap();
private final ConcurrentHashMap<AccessibleObject, ConvertColumnEntry> columnEntrys = new ConcurrentHashMap();
private final Set<Class> skipIgnores = new HashSet();
final Set<String> ignoreMapColumns = new HashSet();
final ReentrantLock ignoreMapColumnLock = new ReentrantLock();
//key:需要屏蔽的字段value排除的字段名
private final ConcurrentHashMap<Class, Set<String>> ignoreAlls = new ConcurrentHashMap();
private boolean skipAllIgnore = false;
protected ConvertFactory(ConvertFactory<R, W> parent, boolean tiny) {
this.tiny = tiny;
this.parent = parent;
if (parent == null) {
//---------------------------------------------------------
this.register(boolean.class, BoolSimpledCoder.instance);
this.register(Boolean.class, BoolSimpledCoder.instance);
this.register(byte.class, ByteSimpledCoder.instance);
this.register(Byte.class, ByteSimpledCoder.instance);
this.register(short.class, ShortSimpledCoder.instance);
this.register(Short.class, ShortSimpledCoder.instance);
this.register(char.class, CharSimpledCoder.instance);
this.register(Character.class, CharSimpledCoder.instance);
this.register(int.class, IntSimpledCoder.instance);
this.register(Integer.class, IntSimpledCoder.instance);
this.register(long.class, LongSimpledCoder.instance);
this.register(Long.class, LongSimpledCoder.instance);
this.register(float.class, FloatSimpledCoder.instance);
this.register(Float.class, FloatSimpledCoder.instance);
this.register(double.class, DoubleSimpledCoder.instance);
this.register(Double.class, DoubleSimpledCoder.instance);
this.register(Number.class, NumberSimpledCoder.instance);
this.register(String.class, StringSimpledCoder.instance);
this.register(StringWrapper.class, StringWrapperSimpledCoder.instance);
this.register(CharSequence.class, CharSequenceSimpledCoder.instance);
this.register(StringBuilder.class, CharSequenceSimpledCoder.StringBuilderSimpledCoder.instance);
this.register(java.util.Date.class, DateSimpledCoder.instance);
this.register(java.time.Instant.class, InstantSimpledCoder.instance);
this.register(java.time.LocalDate.class, LocalDateSimpledCoder.instance);
this.register(java.time.LocalTime.class, LocalTimeSimpledCoder.instance);
this.register(java.time.LocalDateTime.class, LocalDateTimeSimpledCoder.instance);
this.register(java.time.Duration.class, DurationSimpledCoder.instance);
this.register(AtomicInteger.class, AtomicIntegerSimpledCoder.instance);
this.register(AtomicLong.class, AtomicLongSimpledCoder.instance);
this.register(BigInteger.class, BigIntegerSimpledCoder.instance);
this.register(BigDecimal.class, BigDecimalSimpledCoder.instance);
this.register(InetAddress.class, InetAddressSimpledCoder.instance);
this.register(LongAdder.class, LongAdderSimpledCoder.instance);
this.register(Uint128.class, Uint128SimpledCoder.instance);
this.register(Class.class, TypeSimpledCoder.instance);
this.register(InetSocketAddress.class, InetAddressSimpledCoder.InetSocketAddressSimpledCoder.instance);
this.register(Pattern.class, PatternSimpledCoder.instance);
this.register(File.class, FileSimpledCoder.instance);
this.register(Throwable.class, ThrowableSimpledCoder.instance);
this.register(CompletionHandler.class, CompletionHandlerSimpledCoder.instance);
this.register(URL.class, URLSimpledCoder.instance);
this.register(URI.class, URISimpledCoder.instance);
//---------------------------------------------------------
this.register(ByteBuffer.class, ByteBufferSimpledCoder.instance);
this.register(boolean[].class, BoolArraySimpledCoder.instance);
this.register(byte[].class, ByteArraySimpledCoder.instance);
this.register(short[].class, ShortArraySimpledCoder.instance);
this.register(char[].class, CharArraySimpledCoder.instance);
this.register(int[].class, IntArraySimpledCoder.instance);
this.register(IntStream.class, IntArraySimpledCoder.IntStreamSimpledCoder.instance);
this.register(long[].class, LongArraySimpledCoder.instance);
this.register(LongStream.class, LongArraySimpledCoder.LongStreamSimpledCoder.instance);
this.register(float[].class, FloatArraySimpledCoder.instance);
this.register(double[].class, DoubleArraySimpledCoder.instance);
this.register(DoubleStream.class, DoubleArraySimpledCoder.DoubleStreamSimpledCoder.instance);
this.register(String[].class, StringArraySimpledCoder.instance);
//---------------------------------------------------------
this.register(AnyValue.class, Creator.create(AnyValue.DefaultAnyValue.class));
this.register(HttpCookie.class, new Creator<HttpCookie>() {
@Override
@ConstructorParameters({"name", "value"})
public HttpCookie create(Object... params) {
return new HttpCookie((String) params[0], (String) params[1]);
}
});
try {
Class sqldateClass = Thread.currentThread().getContextClassLoader().loadClass("java.sql.Date");
Invoker<Object, Object> sqldateInvoker = Invoker.create(sqldateClass, "valueOf", String.class);
this.register(sqldateClass, new SimpledCoder<R, W, Object>() {
@Override
public void convertTo(W out, Object value) {
out.writeSmallString(value == null ? null : value.toString());
}
@Override
public Object convertFrom(R in) {
String t = in.readSmallString();
return t == null ? null : sqldateInvoker.invoke(null, t);
}
});
Class sqltimeClass = Thread.currentThread().getContextClassLoader().loadClass("java.sql.Time");
Invoker<Object, Object> sqltimeInvoker = Invoker.create(sqltimeClass, "valueOf", String.class);
this.register(sqltimeClass, new SimpledCoder<R, W, Object>() {
@Override
public void convertTo(W out, Object value) {
out.writeSmallString(value == null ? null : value.toString());
}
@Override
public Object convertFrom(R in) {
String t = in.readSmallString();
return t == null ? null : sqltimeInvoker.invoke(null, t);
}
});
Class timestampClass = Thread.currentThread().getContextClassLoader().loadClass("java.sql.Timestamp");
Invoker<Object, Object> timestampInvoker = Invoker.create(timestampClass, "valueOf", String.class);
this.register(timestampClass, new SimpledCoder<R, W, Object>() {
@Override
public void convertTo(W out, Object value) {
out.writeSmallString(value == null ? null : value.toString());
}
@Override
public Object convertFrom(R in) {
String t = in.readSmallString();
return t == null ? null : timestampInvoker.invoke(null, t);
}
});
} catch (Throwable t) {
}
}
}
public ConvertFactory parent() {
return this.parent;
}
public static Convert findConvert(ConvertType type) {
if (type == null) {
return null;
}
if (type == ConvertType.JSON) {
return JsonConvert.root();
}
if (type == ConvertType.BSON) {
return BsonConvert.root();
}
if (loaderInited.get()) {
if (type == ConvertType.PROTOBUF) {
return defProtobufConvert;
}
}
if (loaderInited.compareAndSet(false, true)) {
Iterator<ConvertProvider> it = ServiceLoader.load(ConvertProvider.class).iterator();
RedkaleClassLoader.putServiceLoader(ConvertProvider.class);
while (it.hasNext()) {
ConvertProvider cl = it.next();
RedkaleClassLoader.putReflectionPublicConstructors(cl.getClass(), cl.getClass().getName());
if (cl.type() == ConvertType.PROTOBUF) {
defProtobufConvert = cl.convert();
}
}
}
return type == ConvertType.PROTOBUF ? defProtobufConvert : null;
}
protected static boolean getSystemPropertyBoolean(String key, String parentkey, boolean defvalue) {
return Boolean.parseBoolean(System.getProperty(key, System.getProperty(parentkey, String.valueOf(defvalue))));
}
public abstract ConvertType getConvertType();
public abstract boolean isReversible(); //是否可逆的
public abstract boolean isFieldSort(); //当ConvertColumn.index相同时是否按字段名称排序
public abstract ConvertFactory createChild();
public abstract ConvertFactory createChild(boolean tiny);
protected SimpledCoder createEnumSimpledCoder(Class enumClass) {
return new EnumSimpledCoder(this, enumClass);
}
protected Type formatObjectType(Type type) {
if (type instanceof Class) {
Class<?> clazz = (Class) type;
ConvertImpl ci = clazz.getAnnotation(ConvertImpl.class);
if (ci != null && ci.value() != Object.class) {
if (!clazz.isAssignableFrom(ci.value())) {
throw new ConvertException("@" + ConvertImpl.class.getSimpleName() + ".value(" + ci.value() + ") must be " + clazz + "'s subclass");
}
if (!Modifier.isAbstract(clazz.getModifiers()) && !Modifier.isInterface(clazz.getModifiers())) {
throw new ConvertException("@" + ConvertImpl.class.getSimpleName() + " must at interface or abstract class, but " + clazz + " not");
}
Class impl = ci.value();
if (Modifier.isAbstract(impl.getModifiers()) || Modifier.isInterface(impl.getModifiers())) {
throw new ConvertException("@" + ConvertImpl.class.getSimpleName() + " at class " + impl + " cannot be interface or abstract class");
}
return impl;
}
}
return type;
}
protected <E> Encodeable<W, E> createDyncEncoder(Type type) {
return null;
}
protected ObjectDecoder createObjectDecoder(Type type) {
return new ObjectDecoder(type);
}
protected <E> Decodeable<R, E> createMultiImplDecoder(Class[] types) {
return null;
}
protected <E> ObjectEncoder<W, E> createObjectEncoder(Type type) {
return new ObjectEncoder(type);
}
protected <E> Decodeable<R, E> createMapDecoder(Type type) {
return new MapDecoder(this, type);
}
protected <E> Encodeable<W, E> createMapEncoder(Type type) {
return new MapEncoder(this, type);
}
protected <E> Decodeable<R, E> createArrayDecoder(Type type) {
return new ArrayDecoder(this, type);
}
protected <E> Encodeable<W, E> createArrayEncoder(Type type) {
return new ArrayEncoder(this, type);
}
protected <E> Decodeable<R, E> createCollectionDecoder(Type type) {
return new CollectionDecoder(this, type);
}
protected <E> Encodeable<W, E> createCollectionEncoder(Type type) {
return new CollectionEncoder(this, type);
}
protected <E> Decodeable<R, E> createStreamDecoder(Type type) {
return new StreamDecoder(this, type);
}
protected <E> Encodeable<W, E> createStreamEncoder(Type type) {
return new StreamEncoder(this, type);
}
public Convert getConvert() {
return convert;
}
public ConvertFactory tiny(boolean tiny) {
this.tiny = tiny;
return this;
}
public boolean isConvertDisabled(AccessibleObject element) {
ConvertDisabled[] ccs = element.getAnnotationsByType(ConvertDisabled.class);
if (ccs.length == 0 && element instanceof Method) {
final Method method = (Method) element;
String fieldName = readGetSetFieldName(method);
if (fieldName != null) {
try {
ccs = method.getDeclaringClass().getDeclaredField(fieldName).getAnnotationsByType(ConvertDisabled.class);
} catch (Exception e) { //说明没有该字段,忽略异常
}
}
}
final ConvertType ct = this.getConvertType();
for (ConvertDisabled ref : ccs) {
if (ref.type().contains(ct)) {
return true;
}
}
return false;
}
public ConvertColumnEntry findRef(Class clazz, AccessibleObject element) {
if (element == null) {
return null;
}
ConvertColumnEntry en = this.columnEntrys.get(element);
Set<String> onlyColumns = ignoreAlls.get(clazz);
if (en != null && onlyColumns == null) {
return en;
}
final ConvertType ct = this.getConvertType();
ConvertColumn[] ccs = element.getAnnotationsByType(ConvertColumn.class);
String fieldName = null;
if (ccs.length == 0 && element instanceof Method) {
final Method method = (Method) element;
fieldName = readGetSetFieldName(method);
if (fieldName != null) {
Class mclz = method.getDeclaringClass();
do {
try {
ccs = mclz.getDeclaredField(fieldName).getAnnotationsByType(ConvertColumn.class);
break;
} catch (Exception e) { //说明没有该字段,忽略异常
}
} while (mclz != Object.class && (mclz = mclz.getSuperclass()) != Object.class);
}
}
if (onlyColumns != null && fieldName == null) {
if (element instanceof Method) {
fieldName = readGetSetFieldName((Method) element);
} else if (element instanceof Field) {
fieldName = ((Field) element).getName();
}
}
if (ccs.length == 0 && onlyColumns != null && fieldName != null) {
if (!onlyColumns.contains(fieldName)) {
return new ConvertColumnEntry(fieldName, true);
}
}
for (ConvertColumn ref : ccs) {
if (ref.type().contains(ct)) {
String realName = ref.name().isEmpty() ? fieldName : ref.name();
if (onlyColumns != null && fieldName != null) {
if (!onlyColumns.contains(realName)) {
return new ConvertColumnEntry(realName, true);
}
}
ConvertColumnEntry entry = new ConvertColumnEntry(ref);
if (skipAllIgnore) {
entry.setIgnore(false);
return entry;
}
if (skipIgnores.isEmpty()) {
if (onlyColumns != null && realName != null && onlyColumns.contains(realName)) {
entry.setIgnore(false);
}
return entry;
}
if (skipIgnores.contains(((Member) element).getDeclaringClass())) {
entry.setIgnore(false);
}
return entry;
}
}
return null;
}
static Field readGetSetField(Method method) {
String name = readGetSetFieldName(method);
if (name == null) {
return null;
}
try {
return method.getDeclaringClass().getDeclaredField(name);
} catch (Exception e) {
return null;
}
}
static String readGetSetFieldName(Method method) {
if (method == null) {
return null;
}
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; //record类会直接用field名作为method名
}
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;
}
final String getEntityAlias(Class clazz) {
if (clazz == String.class) {
return "A";
}
if (clazz == int.class) {
return "I";
}
if (clazz == Integer.class) {
return "i";
}
if (clazz == long.class) {
return "J";
}
if (clazz == Long.class) {
return "j";
}
if (clazz == byte.class) {
return "B";
}
if (clazz == Byte.class) {
return "b";
}
if (clazz == boolean.class) {
return "Z";
}
if (clazz == Boolean.class) {
return "z";
}
if (clazz == short.class) {
return "S";
}
if (clazz == Short.class) {
return "s";
}
if (clazz == char.class) {
return "C";
}
if (clazz == Character.class) {
return "c";
}
if (clazz == float.class) {
return "F";
}
if (clazz == Float.class) {
return "f";
}
if (clazz == double.class) {
return "D";
}
if (clazz == Double.class) {
return "d";
}
if (clazz == String[].class) {
return "[A";
}
if (clazz == int[].class) {
return "[I";
}
if (clazz == long[].class) {
return "[J";
}
if (clazz == byte[].class) {
return "[B";
}
if (clazz == boolean[].class) {
return "[Z";
}
if (clazz == short[].class) {
return "[S";
}
if (clazz == char[].class) {
return "[C";
}
if (clazz == float[].class) {
return "[F";
}
if (clazz == double[].class) {
return "[D";
}
ConvertEntity ce = (ConvertEntity) clazz.getAnnotation(ConvertEntity.class);
if (ce != null && findEntityAlias(ce.value()) == null) {
entitys.put(ce.value(), clazz);
}
return ce == null ? clazz.getName() : ce.value();
}
final Class getEntityAlias(String name) {
if ("A".equals(name)) {
return String.class;
}
if ("I".equals(name)) {
return int.class;
}
if ("i".equals(name)) {
return Integer.class;
}
if ("J".equals(name)) {
return long.class;
}
if ("j".equals(name)) {
return Long.class;
}
if ("B".equals(name)) {
return byte.class;
}
if ("b".equals(name)) {
return Byte.class;
}
if ("Z".equals(name)) {
return boolean.class;
}
if ("z".equals(name)) {
return Boolean.class;
}
if ("S".equals(name)) {
return short.class;
}
if ("s".equals(name)) {
return Short.class;
}
if ("C".equals(name)) {
return char.class;
}
if ("c".equals(name)) {
return Character.class;
}
if ("F".equals(name)) {
return float.class;
}
if ("f".equals(name)) {
return Float.class;
}
if ("D".equals(name)) {
return double.class;
}
if ("d".equals(name)) {
return Double.class;
}
if ("[A".equals(name)) {
return String[].class;
}
if ("[I".equals(name)) {
return int[].class;
}
if ("[J".equals(name)) {
return long[].class;
}
if ("[B".equals(name)) {
return byte[].class;
}
if ("[Z".equals(name)) {
return boolean[].class;
}
if ("[S".equals(name)) {
return short[].class;
}
if ("[C".equals(name)) {
return char[].class;
}
if ("[F".equals(name)) {
return float[].class;
}
if ("[D".equals(name)) {
return double[].class;
}
Class clazz = findEntityAlias(name);
try {
return clazz == null ? Thread.currentThread().getContextClassLoader().loadClass(name) : clazz;
} catch (Exception ex) {
throw new ConvertException("convert entity is " + name, ex);
}
}
ConvertFactory columnFactory(Class type, ConvertCoder[] coders, boolean encode) {
if (coders == null || coders.length < 1) {
return this;
}
final ConvertType ct = this.getConvertType();
List<Encodeable> encoderList = null;
List<Decodeable> decoderList = null;
Class readerOrWriterClass = (Class) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[encode ? 1 : 0];
for (ConvertCoder ann : coders) {
if (!ann.type().contains(ct)) {
continue;
}
Class colType = type;
if (ann.column() != Object.class) {
colType = ann.column();
}
if (encode) {
Class<? extends Encodeable> enClazz = ann.encoder();
if (enClazz != Encodeable.class) {
try {
boolean skip = false;
RedkaleClassLoader.putReflectionPublicMethods(enClazz.getName());
for (Method method : enClazz.getMethods()) {
if (method.isBridge()) {
continue;
}
if ("convertTo".equals(method.getName()) && method.getParameterCount() == 2 && Writer.class.isAssignableFrom(method.getParameterTypes()[0])) {
skip = !method.getParameterTypes()[0].isAssignableFrom(readerOrWriterClass);
break;
}
}
if (skip) {
continue;
}
Encodeable encoder = null;
try {
Field instanceField = enClazz.getField("instance");
if (instanceField.getType() == enClazz && Modifier.isStatic(instanceField.getModifiers())) {
RedkaleClassLoader.putReflectionField("instance", instanceField);
encoder = (Encodeable) instanceField.get(null);
}
} catch (Exception e) {
}
if (encoder == null) {
Creator<? extends Encodeable> creator = Creator.create(enClazz);
Class[] paramTypes = creator.paramTypes();
if (paramTypes.length == 0) {
encoder = creator.create();
} else if (paramTypes.length == 1) {
if (Type.class.isAssignableFrom(paramTypes[0])) {
encoder = creator.create((Object) colType);
} else if (ConvertFactory.class.isAssignableFrom(paramTypes[0])) {
encoder = creator.create(this);
} else {
throw new ConvertException(enClazz + " not found public empty-parameter Constructor");
}
} else if (paramTypes.length == 2) {
if (ConvertFactory.class.isAssignableFrom(paramTypes[0]) && Type.class.isAssignableFrom(paramTypes[1])) {
encoder = creator.create(this, colType);
} else if (Type.class.isAssignableFrom(paramTypes[0]) && ConvertFactory.class.isAssignableFrom(paramTypes[1])) {
encoder = creator.create(colType, this);
} else {
throw new ConvertException(enClazz + " not found public empty-parameter Constructor");
}
} else {
throw new ConvertException(enClazz + " not found public empty-parameter Constructor");
}
RedkaleClassLoader.putReflectionPublicConstructors(enClazz, enClazz.getName());
}
if (encoderList == null) {
encoderList = new ArrayList<>();
}
encoderList.add(encoder);
} catch (Throwable t) {
throw new ConvertException(t);
}
}
} else {
Class<? extends Decodeable> deClazz = ann.decoder();
if (deClazz != Decodeable.class) {
try {
boolean skip = false;
RedkaleClassLoader.putReflectionPublicMethods(deClazz.getName());
for (Method method : deClazz.getMethods()) {
if (method.isBridge()) {
continue;
}
if ("convertFrom".equals(method.getName()) && method.getParameterCount() == 1 && Reader.class.isAssignableFrom(method.getParameterTypes()[0])) {
skip = !method.getParameterTypes()[0].isAssignableFrom(readerOrWriterClass);
break;
}
}
if (skip) {
continue;
}
Decodeable decoder = null;
try {
Field instanceField = deClazz.getField("instance");
if (instanceField.getType() == deClazz && Modifier.isStatic(instanceField.getModifiers())) {
RedkaleClassLoader.putReflectionField("instance", instanceField);
decoder = (Decodeable) instanceField.get(null);
}
} catch (Exception e) {
}
if (decoder == null) {
Creator<? extends Decodeable> creator = Creator.create(deClazz);
Class[] paramTypes = creator.paramTypes();
if (paramTypes.length == 0) {
decoder = creator.create();
} else if (paramTypes.length == 1) {
if (Type.class.isAssignableFrom(paramTypes[0])) {
decoder = creator.create((Object) colType);
} else if (ConvertFactory.class.isAssignableFrom(paramTypes[0])) {
decoder = creator.create(this);
} else {
throw new ConvertException(deClazz + " not found public empty-parameter Constructor");
}
} else if (paramTypes.length == 2) {
if (ConvertFactory.class.isAssignableFrom(paramTypes[0]) && Type.class.isAssignableFrom(paramTypes[1])) {
decoder = creator.create(this, colType);
} else if (Type.class.isAssignableFrom(paramTypes[0]) && ConvertFactory.class.isAssignableFrom(paramTypes[1])) {
decoder = creator.create(colType, this);
} else {
throw new ConvertException(deClazz + " not found public empty-parameter Constructor");
}
} else {
throw new ConvertException(deClazz + " not found public empty-parameter Constructor");
}
RedkaleClassLoader.putReflectionPublicConstructors(deClazz, deClazz.getName());
}
if (decoderList == null) {
decoderList = new ArrayList<>();
}
decoderList.add(decoder);
} catch (Throwable t) {
throw new ConvertException(t);
}
}
}
}
if (encoderList == null && decoderList == null) {
return this;
}
ConvertFactory child = createChild();
if (encode) {
for (Encodeable item : encoderList) {
child.register(item.getType(), item);
if (item instanceof ObjectEncoder) {
((ObjectEncoder) item).init(child);
}
}
} else {
for (Decodeable item : decoderList) {
child.register(item.getType(), item);
if (item instanceof ObjectDecoder) {
((ObjectDecoder) item).init(child);
}
}
}
return child;
}
private Class findEntityAlias(String name) {
Class clazz = entitys.get(name);
return parent == null ? clazz : parent.findEntityAlias(name);
}
/**
* 使所有类的所有被声明为ConvertColumn.ignore = true 的字段或方法变为ConvertColumn.ignore = false
*
* @param skipIgnore 是否忽略Ignore注解
*/
public final void registerSkipAllIgnore(final boolean skipIgnore) {
this.skipAllIgnore = skipIgnore;
}
/**
* 使所有类的所有被声明为ConvertColumn.ignore = true 的字段或方法变为ConvertColumn.ignore = false
*
* @param skipIgnore 忽略ignore
*
* @return 自身
*/
public ConvertFactory<R, W> skipAllIgnore(final boolean skipIgnore) {
this.skipAllIgnore = skipIgnore;
return this;
}
/**
* 使该类所有被声明为ConvertColumn.ignore = true 的字段或方法变为ConvertColumn.ignore = false
*
* @param type 指定的类
*/
public final void registerSkipIgnore(final Class type) {
skipIgnores.add(type);
}
/**
* 屏蔽指定类所有字段,仅仅保留指定字段 <br>
* <b>注意: 该配置优先级高于skipAllIgnore和ConvertColumnEntry配置</b>
*
* @param type 指定的类
* @param excludeColumns 需要排除的字段名
*/
public final void registerIgnoreAll(final Class type, String... excludeColumns) {
ignoreAlls.computeIfAbsent(type, t -> new CopyOnWriteArraySet<>()).addAll(Arrays.asList(excludeColumns));
}
public final void registerIgnoreAll(final Class type, Collection<String> excludeColumns) {
ignoreAlls.computeIfAbsent(type, t -> new CopyOnWriteArraySet<>()).addAll(excludeColumns);
}
public final void register(final Class type, boolean ignore, String... columns) {
if (type == Map.class) {
ignoreMapColumnLock.lock();
try {
if (ignore) {
for (String column : columns) {
ignoreMapColumns.add(column);
}
} else {
for (String column : columns) {
ignoreMapColumns.remove(column);
}
}
} finally {
ignoreMapColumnLock.unlock();
}
return;
}
for (String column : columns) {
register(type, column, new ConvertColumnEntry(column, ignore));
}
}
public final void register(final Class type, boolean ignore, Collection<String> columns) {
if (type == Map.class) {
ignoreMapColumnLock.lock();
try {
if (ignore) {
for (String column : columns) {
ignoreMapColumns.add(column);
}
} else {
for (String column : columns) {
ignoreMapColumns.remove(column);
}
}
} finally {
ignoreMapColumnLock.unlock();
}
return;
}
for (String column : columns) {
register(type, column, new ConvertColumnEntry(column, ignore));
}
}
public final boolean register(final Class type, String column, String alias) {
return register(type, column, new ConvertColumnEntry(alias));
}
public final boolean register(final Class type, String column, ConvertColumnEntry entry) {
if (type == null || column == null || entry == null) {
return false;
}
Field field = null;
try {
field = type.getDeclaredField(column);
} catch (Exception e) {
}
String get = "get";
if (field != null && (field.getType() == boolean.class || field.getType() == Boolean.class)) {
get = "is";
}
char[] cols = column.toCharArray();
cols[0] = Character.toUpperCase(cols[0]);
final String bigColumn = new String(cols);
try {
register(type.getMethod(get + bigColumn), entry);
} catch (NoSuchMethodException mex) {
if (get.length() >= 3) { //get
try {
register(type.getMethod("is" + bigColumn), entry);
} catch (Exception ex) {
}
}
} catch (Exception ex) {
}
try {
register(type.getMethod("set" + bigColumn, field.getType()), entry);
} catch (Exception ex) {
}
return field == null ? true : register(field, entry);
}
public final <E> boolean register(final AccessibleObject field, final ConvertColumnEntry entry) {
if (field == null || entry == null) {
return false;
}
this.columnEntrys.put(field, entry);
return true;
}
public final void reloadCoder(final Type type) {
this.register(type, this.createDecoder(type));
this.register(type, this.createEncoder(type));
}
public final void reloadCoder(final Type type, final Class clazz) {
this.register(type, this.createDecoder(type, clazz, false));
this.register(type, this.createEncoder(type, clazz, false));
}
public final <E> void register(final Class<E> clazz, final Creator<? extends E> creator) {
creators.put(clazz, creator);
}
public final <T> Creator<T> findCreator(Class<T> type) {
Creator<T> creator = creators.get(type);
if (creator != null) {
return creator;
}
return this.parent == null ? null : this.parent.findCreator(type);
}
public final <T> Creator<T> loadCreator(Class<T> type) {
Creator result = findCreator(type);
if (result == null) {
result = Creator.create(type);
if (result != null) {
creators.put(type, result);
}
}
return result;
}
//----------------------------------------------------------------------
public final <E> Encodeable<W, E> getAnyEncoder() {
return (Encodeable<W, E>) anyEncoder;
}
public final <E> void register(final Type clazz, final SimpledCoder<R, W, E> coder) {
decoders.put(clazz, coder);
encoders.put(clazz, coder);
}
public final <E> void register(final Type clazz, final Decodeable<R, E> decoder, final Encodeable<W, E> encoder) {
decoders.put(clazz, decoder);
encoders.put(clazz, encoder);
}
public final <E> void register(final Type clazz, final Decodeable<R, E> decoder) {
decoders.put(clazz, decoder);
}
public final <E> void register(final Type clazz, final Encodeable<W, E> encoder) {
encoders.put(clazz, encoder);
}
//coder = null表示删除该字段的指定SimpledCoder
public final <E> void register(final Class clazz, final String field, final SimpledCoder<R, W, E> coder) {
if (field == null || clazz == null) {
return;
}
try {
clazz.getDeclaredField(field);
} catch (Exception e) {
throw new ConvertException(clazz + " not found field(" + field + ")");
}
if (coder == null) {
Map map = this.fieldCoders.get(clazz);
if (map != null) {
map.remove(field);
}
} else {
this.fieldCoders.computeIfAbsent(clazz, c -> new ConcurrentHashMap<>()).put(field, coder);
}
}
public final <E> SimpledCoder<R, W, E> findFieldCoder(final Type clazz, final String field) {
if (field == null) {
return null;
}
Map<String, SimpledCoder<R, W, ?>> map = this.fieldCoders.get(clazz);
if (map == null) {
return parent == null ? null : parent.findFieldCoder(clazz, field);
}
return (SimpledCoder) map.get(field);
}
public final <E> Decodeable<R, E> findDecoder(final Type type) {
Decodeable<R, E> rs = (Decodeable<R, E>) decoders.get(type);
if (rs != null) {
return rs;
}
return this.parent == null ? null : this.parent.findDecoder(type);
}
public final <E> Encodeable<W, E> findEncoder(final Type type) {
Encodeable<W, E> rs = (Encodeable<W, E>) encoders.get(type);
if (rs != null) {
return rs;
}
return this.parent == null ? null : this.parent.findEncoder(type);
}
public final <E> Decodeable<R, E> loadDecoder(final Type type) {
Decodeable<R, E> decoder = findDecoder(type);
if (decoder != null) {
return decoder;
}
if (type instanceof GenericArrayType) {
return createArrayDecoder(type);
}
Class clazz;
if (type instanceof ParameterizedType) {
final ParameterizedType pts = (ParameterizedType) type;
clazz = (Class) (pts).getRawType();
} else if (type instanceof TypeVariable) { // e.g. <? extends E>
final TypeVariable tv = (TypeVariable) type;
Class cz = tv.getBounds().length == 0 ? Object.class : null;
for (Type f : tv.getBounds()) {
if (f instanceof Class) {
cz = (Class) f;
break;
}
}
clazz = cz;
if (cz == null) {
throw new ConvertException("not support the type (" + type + ")");
}
} else if (type instanceof WildcardType) { // e.g. <? extends Serializable>
final WildcardType wt = (WildcardType) type;
Class cz = null;
for (Type f : wt.getUpperBounds()) {
if (f instanceof Class) {
cz = (Class) f;
break;
}
}
clazz = cz;
if (cz == null) {
throw new ConvertException("not support the type (" + type + ")");
}
} else if (type instanceof Class) {
clazz = (Class) type;
} else {
throw new ConvertException("not support the type (" + type + ")");
}
//此处不能再findDecoder否则type与class不一致, 如: RetResult 和 RetResult<Integer>
return createDecoder(type, clazz, false);
}
public final <E> Decodeable<R, E> createDecoder(final Type type) {
return createDecoder(type, false);
}
public final <E> Decodeable<R, E> createDecoder(final Type type, boolean skipCustomMethod) {
Class clazz;
if (type instanceof ParameterizedType) {
final ParameterizedType pts = (ParameterizedType) type;
clazz = (Class) (pts).getRawType();
} else if (type instanceof Class) {
clazz = (Class) type;
} else {
throw new ConvertException("not support the type (" + type + ")");
}
return createDecoder(type, clazz, skipCustomMethod);
}
private <E> Decodeable<R, E> createDecoder(final Type type, final Class clazz, boolean skipCustomMethod) {
Decodeable<R, E> decoder = null;
ObjectDecoder od = null;
if (clazz.isEnum()) {
decoder = createEnumSimpledCoder(clazz);
} else if (clazz.isArray()) {
decoder = createArrayDecoder(type);
} else if (Collection.class.isAssignableFrom(clazz)) {
decoder = createCollectionDecoder(type);
} else if (Stream.class.isAssignableFrom(clazz)) {
decoder = createStreamDecoder(type);
} else if (Map.class.isAssignableFrom(clazz)) {
decoder = createMapDecoder(type);
} else if (CompletionHandler.class.isAssignableFrom(clazz)) {
decoder = CompletionHandlerSimpledCoder.instance;
} else if (Optional.class == clazz) {
decoder = new OptionalCoder(this, type);
} else if (clazz == Object.class) {
od = createObjectDecoder(type);
decoder = od;
} else if (!clazz.getName().startsWith("java.")
|| java.net.HttpCookie.class == clazz
|| java.util.AbstractMap.SimpleEntry.class == clazz
|| clazz.getName().startsWith("java.awt.geom.Point2D")) {
Decodeable simpleCoder = null;
if (!skipCustomMethod) {
for (Class subclazz : getSuperClasses(clazz)) {
for (final Method method : subclazz.getDeclaredMethods()) {
if (!Modifier.isStatic(method.getModifiers())) {
continue;
}
Class[] paramTypes = method.getParameterTypes();
if (paramTypes.length != 1 && paramTypes.length != 2) {
continue;
}
if (paramTypes[0] != ConvertFactory.class && paramTypes[0] != this.getClass()) {
continue;
}
if (paramTypes.length == 2 && paramTypes[1] != Class.class && paramTypes[1] != Type.class) {
continue;
}
if (!Decodeable.class.isAssignableFrom(method.getReturnType())) {
continue;
}
if (Modifier.isPrivate(method.getModifiers()) && subclazz != clazz) {
continue; //声明private的只能被自身类使用
}
try {
method.setAccessible(true);
simpleCoder = (Decodeable) (paramTypes.length == 2 ? (paramTypes[1] == Type.class ? method.invoke(null, this, type) : method.invoke(null, this, clazz)) : method.invoke(null, this));
RedkaleClassLoader.putReflectionDeclaredMethods(subclazz.getName());
RedkaleClassLoader.putReflectionMethod(subclazz.getName(), method);
break;
} catch (Exception e) {
e.printStackTrace();
}
}
if (simpleCoder != null) {
break;
}
}
}
if (simpleCoder == null) {
if (type instanceof Class) {
Class<?> typeclz = (Class) type;
ConvertImpl ci = typeclz.getAnnotation(ConvertImpl.class);
if (ci != null && ci.types().length > 0) {
for (Class sub : ci.types()) {
if (!typeclz.isAssignableFrom(sub)) {
throw new ConvertException("@" + ConvertImpl.class.getSimpleName() + ".types(" + sub + ") must be " + typeclz + "'s subclass");
}
}
decoder = createMultiImplDecoder(ci.types());
}
}
if (decoder == null) {
Type impl = formatObjectType(type);
od = createObjectDecoder(impl);
decoder = od;
}
} else {
decoder = simpleCoder;
}
}
if (decoder == null) {
throw new ConvertException("not support the type (" + type + ")");
}
register(type, decoder);
if (od != null) {
od.init(this);
}
return decoder;
}
public final <E> Encodeable<W, E> loadEncoder(final Type type) {
Encodeable<W, E> encoder = findEncoder(type);
if (encoder != null) {
return encoder;
}
if (type instanceof GenericArrayType) {
return createArrayEncoder(type);
}
Class clazz;
if (type instanceof ParameterizedType) {
final ParameterizedType pts = (ParameterizedType) type;
clazz = (Class) (pts).getRawType();
} else if (type instanceof TypeVariable) {
TypeVariable tv = (TypeVariable) type;
Type t = Object.class;
if (tv.getBounds().length == 1) {
t = tv.getBounds()[0];
}
if (!(t instanceof Class)) {
t = Object.class;
}
clazz = (Class) t;
} else if (type instanceof Class) {
clazz = (Class) type;
} else {
throw new ConvertException("not support the type (" + type + ")");
}
//此处不能再findEncoder否则type与class不一致, 如: RetResult 和 RetResult<Integer>
return createEncoder(type, clazz, false);
}
public final <E> Encodeable<W, E> createEncoder(final Type type) {
return createEncoder(type, false);
}
public final <E> Encodeable<W, E> createEncoder(final Type type, boolean skipCustomMethod) {
Class clazz;
if (type instanceof ParameterizedType) {
final ParameterizedType pts = (ParameterizedType) type;
clazz = (Class) (pts).getRawType();
} else if (type instanceof Class) {
clazz = (Class) type;
} else {
throw new ConvertException("not support the type (" + type + ")");
}
return createEncoder(type, clazz, skipCustomMethod);
}
private <E> Encodeable<W, E> createEncoder(final Type type, final Class clazz, boolean skipCustomMethod) {
Encodeable<W, E> encoder = null;
ObjectEncoder oe = null;
if (clazz.isEnum()) {
encoder = createEnumSimpledCoder(clazz);
} else if (clazz.isArray()) {
encoder = createArrayEncoder(type);
} else if (Collection.class.isAssignableFrom(clazz)) {
encoder = createCollectionEncoder(type);
} else if (Stream.class.isAssignableFrom(clazz)) {
encoder = createStreamEncoder(type);
} else if (Map.class.isAssignableFrom(clazz)) {
encoder = createMapEncoder(type);
} else if (Optional.class == clazz) {
encoder = new OptionalCoder(this, type);
} else if (clazz == Object.class) {
return (Encodeable<W, E>) this.anyEncoder;
} else if (!clazz.getName().startsWith("java.") || java.net.HttpCookie.class == clazz
|| java.util.Map.Entry.class == clazz || java.util.AbstractMap.SimpleEntry.class == clazz) {
Encodeable simpleCoder = null;
if (!skipCustomMethod) {
for (Class subclazz : getSuperClasses(clazz)) {
for (final Method method : subclazz.getDeclaredMethods()) {
if (!Modifier.isStatic(method.getModifiers())) {
continue;
}
Class[] paramTypes = method.getParameterTypes();
if (paramTypes.length != 1 && paramTypes.length != 2) {
continue;
}
if (paramTypes[0] != ConvertFactory.class && paramTypes[0] != this.getClass()) {
continue;
}
if (paramTypes.length == 2 && paramTypes[1] != Class.class && paramTypes[1] != Type.class) {
continue;
}
if (!Encodeable.class.isAssignableFrom(method.getReturnType())) {
continue;
}
if (Modifier.isPrivate(method.getModifiers()) && subclazz != clazz) {
continue; //声明private的只能被自身类使用
}
try {
method.setAccessible(true);
simpleCoder = (Encodeable) (paramTypes.length == 2 ? (paramTypes[1] == Type.class ? method.invoke(null, this, type) : method.invoke(null, this, clazz)) : method.invoke(null, this));
RedkaleClassLoader.putReflectionDeclaredMethods(subclazz.getName());
RedkaleClassLoader.putReflectionMethod(subclazz.getName(), method);
break;
} catch (Exception e) {
e.printStackTrace();
}
}
if (simpleCoder != null) {
break;
}
}
}
if (simpleCoder == null) {
Type impl = formatObjectType(type);
encoder = createDyncEncoder(impl);
if (encoder == null) {
oe = createObjectEncoder(impl);
encoder = oe;
}
} else {
encoder = simpleCoder;
}
}
if (encoder == null) {
throw new ConvertException("not support the type (" + type + ")");
}
register(type, encoder);
if (oe != null) {
oe.init(this);
}
return encoder;
}
private Set<Class> getSuperClasses(final Class clazz) {
Set<Class> set = new LinkedHashSet<>();
set.add(clazz);
Class recursClass = clazz;
while ((recursClass = recursClass.getSuperclass()) != null) {
if (recursClass == Object.class) {
break;
}
set.addAll(getSuperClasses(recursClass));
}
for (Class sub : clazz.getInterfaces()) {
set.addAll(getSuperClasses(sub));
}
return set;
}
}