gu.sql2java.TableManagerDecorator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of sql2java-manager Show documentation
Show all versions of sql2java-manager Show documentation
sql2java manager class package for accessing database
package gu.sql2java;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.google.common.base.Function;
import com.google.common.base.Throwables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import static com.google.common.base.Preconditions.*;
import static gu.sql2java.NameUtilities.*;
import static com.google.common.base.MoreObjects.*;
import static gu.sql2java.SimpleLog.*;
import static gu.sql2java.Managers.*;
/**
* 基于{@link BaseTableManager}实例代理实现接口
*
* @author guyadong
*
* @param 接口类型
*/
public class TableManagerDecorator> implements InvocationHandler{
private final Class interfaceClass;
final BaseTableManager extends BaseBean> delegate;
private final Map invokers = Maps.newLinkedHashMap();
@SuppressWarnings("rawtypes")
private final Class extends BaseTableManager> implClass;
final RowMetaData metaData;
private static boolean debug = false;
/**
* 构造方法
*
* @param interfaceClass 接口类
* @param delegate 实现接口的实例
*/
TableManagerDecorator(Class interfaceClass, BaseTableManager extends BaseBean> delegate) {
checkType(interfaceClass,delegate);
this.interfaceClass = interfaceClass;
this.delegate = delegate;
this.implClass = delegate.getClass();
this.metaData = delegate.metaData;
try {
compile();
} catch (Exception e) {
Throwables.throwIfUnchecked(e);
throw new RuntimeException(e);
}
}
/**
* 构造方法
*
* @param interfaceClass 接口类
* @param tablename 接口类对应的表名
*/
TableManagerDecorator(Class interfaceClass, String tablename) {
this(interfaceClass,new BaseTableManager(tablename));
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return checkNotNull(invokers.get(method),"UNSUPPORT method %s",method).invoke(args);
}
/**
* @return 根据当前对象创建新的接口实例{@link Proxy}
*/
public final I proxyInstance(){
return interfaceClass.cast(Proxy.newProxyInstance(
interfaceClass.getClassLoader(),
new Class>[]{ interfaceClass},
this));
}
@Override
public String toString(){
StringBuffer builder = new StringBuffer();
String simulateClassName = interfaceClass.getSimpleName() + "Decorator";
String simulateTableManagerClass = BaseTableManager.class.getName() + "<" + metaData.beanType.getName() + ">";
builder.append("class ").append(simulateClassName).append(" implements ").append(interfaceClass.getName()).append("{\n");
builder.append(" private final ").append(simulateTableManagerClass).append(" delegate;\n");
builder.append(" public ").append(simulateClassName).append("(").append(simulateTableManagerClass).append(" delegate){\n");
builder.append(" this.delegate = delegate\n");
builder.append(" }\n");
for(Invoker invoker:invokers.values()){
builder.append(invoker);
}
builder.append("}\n");
return builder.toString();
}
/**
* 检查参数类型合法性,不匹配则抛出异常
* @param interfaceClass
* @param delegate
*/
private static void checkType(Class> interfaceClass, BaseTableManager> delegate){
checkArgument(interfaceClass != null, "interfaceClass is null");
checkArgument(delegate != null, "delegate is null");
checkArgument(delegate.metaData.managerInterfaceClass.equals(interfaceClass),
"MISMATCH interface class of delegate(%s) with %s",
delegate.metaData.managerInterfaceClass.getSimpleName(),
interfaceClass.getName());
}
/**
* 创建{@code interfaceClass}接口实例
* @param interfaceClass 接口类
* @param delegate 代理类实例
* @return {@code interfaceClass}接口实例
*/
static final >I makeInterfaceInstance(Class interfaceClass,BaseTableManager> delegate){
return new TableManagerDecorator(interfaceClass,delegate).proxyInstance();
}
/**
* 创建{@code interfaceClass}接口实例
* @param interfaceClass 接口类
* @param tablename 接口类对应的表名
* @return {@code interfaceClass}接口实例
*/
static final >I makeInterfaceInstance(Class interfaceClass,String tablename){
return new TableManagerDecorator(interfaceClass,tablename).proxyInstance();
}
/**
* 创建接口实例
* @param delegate 代理类实例
* @return 接口实例
*/
static final >TableManager> makeInterfaceInstance(BaseTableManager> delegate){
checkArgument(delegate != null ,"delegate is null");
checkArgument(delegate.metaData.managerInterfaceClass != null,"delegate.metaData.managerInterfaceClass is null");
return makeInterfaceInstance(delegate.metaData.managerInterfaceClass,delegate);
}
/**
* 创建接口实例
* @param tablename 接口类对应的表名
* @return 接口实例
*/
static final >TableManager> makeInterfaceInstance(String tablename){
return makeInterfaceInstance(getBaseTableManager(tablename));
}
/**
* 设置是否输出调试信息标志
* @param debug
*/
static void setDebug(boolean debug) {
TableManagerDecorator.debug = debug;
}
private static final String M_LOADBYPRIMARYKEY = "loadByPrimaryKey";
private static final String D_LOADBYPKS = "loadByPks";
private static final String M_LOADBYPRIMARYKEYCHECKED = "loadByPrimaryKeyChecked";
private static final String M_EXISTSPRIMARYKEY = "existsPrimaryKey";
private static final String M_CHECKDUPLICATE = "checkDuplicate";
private static final String D_CHECKDUPLICATEBYPK = "checkDuplicateByPk";
private static final String M_DELETEBYPRIMARYKEY = "deleteByPrimaryKey";
private static final String D_DELETEBYPKS = "deleteByPks";
private static final String M_TOPRIMARYKEYLIST = "toPrimaryKeyList";
private static final String P_ADDJUNCTION = "addJunction(With(\\w+))?";
private static final String D_ADDJUNCTION = "addJunction";
private static final String P_DELETEJUNCTION = "deleteJunction(With(\\w+))?";
private static final String D_DELETEJUNCTION = "deleteJunction";
private static final String P_GETIMPORTEDBEANS = "get(\\w+)sBy(\\w+)$";
private static final String D_GETIMPORTEDBEANS = "getImportedBeans";
private static final String P_GETIMPORTEDBEANSASLIST = "get(\\w+)sBy(\\w+)AsList";
private static final String D_GETIMPORTEDBEANSASLIST = "getImportedBeansAsList";
private static final String P_DELETEIMPORTEDBEANS = "delete(\\w+)sBy(\\w+)";
private static final String D_DELETEIMPORTEDBEANS = "deleteImportedBeans";
private static final String P_SETIMPORTEDBEANS = "set(\\w+)sBy(\\w+)";
private static final String D_SETIMPORTEDBEANS = "setImportedBeans";
private static final String M_SAVE = "save";
private static final String D_SAVEFULLY = "saveFully";
private static final String M_SAVEASTRANSACTION = "saveAsTransaction";
private static final String D_SAVEFULLYASTRANSACTION = "saveFullyAsTransaction";
private static final String P_GETREFERENCEDBEAN = "getReferencedBy(\\w+)";
private static final String D_GETREFERENCEDBEAN = "getReferencedBean";
private static final String P_SETREFERENCEDBEAN = "setReferencedBy(\\w+)";
private static final String D_SETREFERENCEDBEAN = "setReferencedBean";
private static final String P_LOADBYINDEX = "loadByIndex(\\w+)";
private static final String D_LOADBYINDEX = "loadByIndex";
private static final String P_LOADUNIQUEBYINDEXCHECKED = "loadByIndex(\\w+)Checked";
private static final String D_LOADUNIQUEBYINDEXCHECKED = "loadUniqueByIndexChecked";
private static final String D_LOADBYINDEXFORINDICES = "loadByIndexForIndices";
private static final String D_LOADUNIQUEBYINDEX = "loadUniqueByIndex";
private static final String P_LOADBYINDEXASLIST = "loadByIndex(\\w+)AsList";
private static final String D_LOADBYINDEXASLIST = "loadByIndexAsList";
private static final String P_DELETEBYINDEX = "deleteByIndex(\\w+)";
private static final String D_DELETEBYINDEX = "deleteByIndex";
private static final String P_LOADVIAJUNCTIONASLIST = "loadVia(\\w+)AsList";
private static final String D_LOADVIAJUNCTIONASLIST = "loadViaJunctionAsList";
private static final String P_LISTOFSELFREF = "listOf(\\w+)";
private static final String D_LISTOFSELFREF = "listOfSelfRef";
private static final String P_LEVELOFSELFREF = "levelOf(\\w+)";
private static final String D_LEVELOFSELFREF = "levelOfSelfRef";
private static final String P_ISCYCLEOFSELFREF = "isCycleOn(\\w+)";
private static final String D_ISCYCLEOFSELFREF = "isCycleOfSelfRef";
private static final String P_CHECKCYCLEOFSELFREF = "checkCycleOf(\\w+)";
private static final String D_CHECKCYCLEOFSELFREF = "checkCycleOfSelfRef";
private static final String P_TOPOFSELFREF = "topOf(\\w+)";
private static final String D_TOPOFSELFREF = "topOfSelfRef";
private static final String P_CHILDLISTOFSELFREF = "childListBy(\\w+)";
private static final String D_CHILDLISTOFSELFREF = "childListOfSelfRef";
private static final String P_CHILDRENOFSELFREF = "childrenBy(\\w+)";
private static final String D_CHILDRENOFSELFREF = "childrenOfSelfRef";
private static final String P_CHILDRENOFBEANSOFSELFREF = "childrenOfBeansBy(\\w+)";
private static final String D_CHILDRENOFBEANSOFSELFREF = "childrenOfBeansOfSelfRef";
private static final String P_CHILDRENOFPKSOFSELFREF = "childrenOfPksBy(\\w+)";
private static final String D_CHILDRENOFPKSOFSELFREF = "childrenOfPksOfSelfRef";
private static final Comparator METHOD_COMPARATOR = new Comparator() {
@Override
public int compare(Method o1, Method o2) {
return signatureOf(o1).compareTo(signatureOf(o2));
}
};
private static boolean declaredBySuper(Method method,Class> superClazz){
if(method.getDeclaringClass().equals(superClazz)){
return true;
}
for(Class> clazz:superClazz.getInterfaces()){
if(declaredBySuper(method,clazz)){
return true;
}
}
return false;
}
/**
* 向上递归查找指定的方法,找不到指定的方法则抛出异常
* @param clazz
* @param name
* @param parameterTypes
* @return 方法对象
* @throws NoSuchMethodException 找不到指定的方法
* @throws SecurityException
*/
private static Method recursiveGetDeclaredMethod(Class> clazz,String name, Class>... parameterTypes)
throws NoSuchMethodException, SecurityException {
try {
return clazz.getDeclaredMethod(name, parameterTypes);
} catch (NoSuchMethodException e) {
Class> superClass = clazz.getSuperclass();
if(null != superClass){
return recursiveGetDeclaredMethod(superClass,name,parameterTypes);
}
throw e;
}
}
/**
* 在代理类({@link #implClass})查找指定的方法,找不到指定的方法则抛出异常
* @param name
* @param parameterTypes
* @return 方法对象
* @throws NoSuchMethodException 找不到指定的方法
* @throws SecurityException
*/
private Method getDeclaredMethod(String name, Class>... parameterTypes)
throws NoSuchMethodException, SecurityException {
return recursiveGetDeclaredMethod(implClass, name, parameterTypes);
}
private NoSuchMethodException makeNoSuchMethodException(Method def){
return new NoSuchMethodException(logString("NO FOUND MATCHED METHOD for %s in %s",def,implClass));
}
private Invoker compile(Method def) throws NoSuchMethodException, SecurityException{
Method impl;
String name = def.getName();
if(declaredBySuper(def,TableManager.class)){
impl = BaseTableManager.class.getDeclaredMethod(name, def.getParameterTypes());
return new MethodInvoker(def, impl, delegate);
}
switch(name){
case M_LOADBYPRIMARYKEY:
return loadByPrimaryKey(def);
case M_LOADBYPRIMARYKEYCHECKED:
impl = getDeclaredMethod(M_LOADBYPRIMARYKEYCHECKED, Object[].class);
return new MethodInvoker(def, impl, delegate);
case M_EXISTSPRIMARYKEY:
impl = getDeclaredMethod(M_EXISTSPRIMARYKEY, Object[].class);
return new MethodInvoker(def, impl, delegate);
case M_CHECKDUPLICATE:
impl = getDeclaredMethod(D_CHECKDUPLICATEBYPK, Object.class);
return new MethodInvoker(def, impl, delegate);
case M_DELETEBYPRIMARYKEY:
return deleteByPrimaryKey(def);
case M_TOPRIMARYKEYLIST:
return toPrimaryKeyList(def);
case M_SAVE:
return saveFully(def);
case M_SAVEASTRANSACTION:
return saveFullyAsTransaction(def);
default:
if(name.matches(P_ADDJUNCTION)){
return addJunction(def);
}
if(name.matches(P_DELETEJUNCTION)){
return deleteJunction(def);
}
if(name.matches(P_GETIMPORTEDBEANSASLIST)){
return getImportedBeansAsList(def);
}
if(name.matches(P_GETIMPORTEDBEANS)){
return getImportedBeans(def);
}
if(name.matches(P_DELETEIMPORTEDBEANS)){
return deleteImportedBeans(def);
}
if(name.matches(P_SETIMPORTEDBEANS)){
return setImportedBeans(def);
}
if(name.matches(P_GETREFERENCEDBEAN)){
return getReferencedBean(def);
}
if(name.matches(P_SETREFERENCEDBEAN)){
return setReferencedBean(def);
}
if(name.matches(P_LOADBYINDEXASLIST)){
return loadByIndexAsList(def);
}
if(name.matches(P_LOADUNIQUEBYINDEXCHECKED)){
return loadUniqueByIndexChecked(def);
}
if(name.matches(P_LOADBYINDEX)){
return loadByIndex(def);
}
if(name.matches(P_DELETEBYINDEX)){
return deleteByIndex(def);
}
if(name.matches(P_LOADVIAJUNCTIONASLIST)){
return loadViaJunctionAsList(def);
}
if(name.matches(P_LISTOFSELFREF)){
return listOfSelfRef(def);
}
if(name.matches(P_LEVELOFSELFREF)){
return levelOfSelfRef(def);
}
if(name.matches(P_ISCYCLEOFSELFREF)){
return isCycleOfSelfRef(def);
}
if(name.matches(P_CHECKCYCLEOFSELFREF)){
return checkCycleOfSelfRef(def);
}
if(name.matches(P_TOPOFSELFREF)){
return topOfSelfRef(def);
}
if(name.matches(P_CHILDLISTOFSELFREF)){
return childListOfSelfRef(def);
}
if(name.matches(P_CHILDRENOFSELFREF)){
return childrenOfSelfRef(def);
}
if(name.matches(P_CHILDRENOFBEANSOFSELFREF)){
return childrenOfSelfRefForBeans(def);
}
if(name.matches(P_CHILDRENOFPKSOFSELFREF)){
return childrenOfSelfRefForPks(def);
}
throw new IllegalArgumentException(logString("NO SUCH METHOD maped %s",def.getName()));
}
}
private void addObjectInvoker(String methodName,Class>...parameterTypes) throws NoSuchMethodException, SecurityException{
Method method = Object.class.getMethod(methodName, parameterTypes);
ObjectInvoker objectInvoker = new ObjectInvoker(method);
invokers.put(method, objectInvoker);
if(debug){
log("{}",objectInvoker);
}
}
private void compile(Method[] methods) throws NoSuchMethodException, SecurityException{
Arrays.sort(methods,METHOD_COMPARATOR);
for(Method method : methods){
Invoker invokder = compile(method);
invokers.put(method, invokder);
// Invoker old = invokers.put(method, invokder);
// checkState(old == null,"duplicated entry for method %s",signatureOf(method));
if(debug){
log("{}",invokder);
}
}
}
private void compile() throws NoSuchMethodException, SecurityException{
addObjectInvoker("toString");
addObjectInvoker("hashCode");
addObjectInvoker("equals",Object.class);
compile(TableManager.class.getMethods());
/** 过滤所有桥接方法 */
Method[] noBridgeMethods = Arrays.stream(interfaceClass.getDeclaredMethods())
.filter(m->!m.isBridge()).toArray(Method[]::new);
compile(noBridgeMethods);
}
//////////////////////////////////////
// PRIMARY KEY METHODS
//////////////////////////////////////
private MethodInvoker loadByPrimaryKey(Method def) throws NoSuchMethodException, SecurityException{
Method impl;
Class>[] paramTypes = def.getParameterTypes();
checkArgument(paramTypes.length == metaData.primaryKeyCount,"only %s parameter required for %s",metaData.primaryKeyCount,def);
if(Arrays.equals(metaData.primaryKeyTypes, paramTypes)){
impl = getDeclaredMethod(M_LOADBYPRIMARYKEY, Object[].class);
}else {
if(metaData.primaryKeyCount == 1){
if(Collection.class.isAssignableFrom(paramTypes[0])){
impl = getDeclaredMethod(D_LOADBYPKS, Collection.class);
}else{
Class> pkType = metaData.columnTypeOf(metaData.primaryKeyIds[0]);
Object pkArray = Array.newInstance(pkType, 0);
if(paramTypes[0] == pkArray.getClass()){
impl = getDeclaredMethod(D_LOADBYPKS, Object[].class);
}else {
throw makeNoSuchMethodException(def);
}
}
}else{
throw makeNoSuchMethodException(def);
}
}
return new MethodInvoker(def, impl, delegate);
}
private MethodInvoker deleteByPrimaryKey(Method def) throws NoSuchMethodException, SecurityException{
Method impl;
Class>[] paramTypes = def.getParameterTypes();
checkArgument(paramTypes.length == metaData.primaryKeyCount,"%s parameter required for %s",metaData.primaryKeyCount,def);
if(Arrays.equals(metaData.primaryKeyTypes, paramTypes)){
impl = getDeclaredMethod(M_DELETEBYPRIMARYKEY, Object[].class);
}else {
if(Collection.class.isAssignableFrom(paramTypes[0])){
impl = getDeclaredMethod(D_DELETEBYPKS, Collection.class);
}else{
Class> pkType = metaData.columnTypeOf(metaData.primaryKeyIds[0]);
Object pkArray = Array.newInstance(pkType, 0);
if(paramTypes[0] == pkArray.getClass()){
impl = getDeclaredMethod(D_DELETEBYPKS, Object[].class);
}else {
throw makeNoSuchMethodException(def);
}
}
}
return new MethodInvoker(def, impl, delegate);
}
//////////////////////////////////////
// GET/SET IMPORTED KEY BEAN METHOD
//////////////////////////////////////
private MethodInvoker getImportedBeans(Method def)throws NoSuchMethodException, SecurityException{
Class>[] paramTypes = def.getParameterTypes();
String methodName = def.getName();
Pattern pattern = Pattern.compile(P_GETIMPORTEDBEANS);
Matcher matcher = pattern.matcher(methodName);
checkArgument(matcher.matches(),"INVALID method name pattern,%s required",P_GETIMPORTEDBEANS);
String importeBeanName = matcher.group(1);
String readableName = matcher.group(2);
ForeignKeyMetaData importedKey = RowMetaData.getForeignKey(importeBeanName,readableName, metaData.alias);
Method impl = getDeclaredMethod(D_GETIMPORTEDBEANS,
paramBuilder().add(importedKey.name.getClass(),paramTypes).normalizeLast(1, Object[].class).build());
return new MethodInvoker(def, impl, delegate, importedKey.name);
}
private MethodInvoker getImportedBeansAsList(Method def)throws NoSuchMethodException, SecurityException{
Class>[] paramTypes = def.getParameterTypes();
String methodName = def.getName();
switch(paramTypes.length){
case 1:{
// DO NOTHING
break;
}
case 3:{
if(BaseBean.class.isAssignableFrom(paramTypes[0]) && int.class == paramTypes[1] && int.class == paramTypes[2]){
// DO NOTHING
}else{
paramTypes = new Class>[]{Object[].class};
}
break;
}
default:{
paramTypes = new Class>[]{Object[].class};
break;
}
}
Pattern pattern = Pattern.compile(P_GETIMPORTEDBEANSASLIST);
Matcher matcher = pattern.matcher(methodName);
checkArgument(matcher.matches(),"INVALID method name pattern,%s required",P_GETIMPORTEDBEANSASLIST);
String importeBeanName = matcher.group(1);
String readableName = matcher.group(2);
ForeignKeyMetaData importedKey = RowMetaData.getForeignKey(importeBeanName,readableName, metaData.alias);
Method impl = getDeclaredMethod(D_GETIMPORTEDBEANSASLIST,
paramBuilder().add(importedKey.name.getClass(),paramTypes).genericNormalize(1,Object[].class).build());
return new MethodInvoker(def, impl, delegate, importedKey.name);
}
private MethodInvoker deleteImportedBeans(Method def)throws NoSuchMethodException, SecurityException{
Class>[] paramTypes = def.getParameterTypes();
String methodName = def.getName();
Pattern pattern = Pattern.compile(P_DELETEIMPORTEDBEANS);
Matcher matcher = pattern.matcher(methodName);
checkArgument(matcher.matches(),"INVALID method name pattern,%s required",P_DELETEIMPORTEDBEANS);
String importeBeanName = matcher.group(1);
String readableName = matcher.group(2);
ForeignKeyMetaData importedKey = RowMetaData.getForeignKey(importeBeanName,readableName, metaData.alias);
Method impl = getDeclaredMethod(D_DELETEIMPORTEDBEANS,
paramBuilder().add(importedKey.name.getClass(),paramTypes).normalizeLast(1, Object[].class).build());
return new MethodInvoker(def, impl, delegate, importedKey.name);
}
private MethodInvoker setImportedBeans(Method def)throws NoSuchMethodException, SecurityException{
Class>[] paramTypes = def.getParameterTypes();
String methodName = def.getName();
checkArgument(paramTypes.length == 2,"2 parameter required for %s",def.getName());
Pattern pattern = Pattern.compile(P_SETIMPORTEDBEANS);
Matcher matcher = pattern.matcher(methodName);
checkArgument(matcher.matches(),"INVALID method name pattern,%s required",P_SETIMPORTEDBEANS);
String importeBeanName = matcher.group(1);
String readableName = matcher.group(2);
ForeignKeyMetaData importedKey = RowMetaData.getForeignKey(importeBeanName,readableName, metaData.alias);
Method impl = getDeclaredMethod(D_SETIMPORTEDBEANS,
paramBuilder().add(importedKey.name.getClass(),wrapBaseBean(paramTypes)).build());
return new MethodInvoker(def, impl, delegate, importedKey.name);
}
//_____________________________________________________________________
//
// SAVE
//_____________________________________________________________________
private MethodInvoker saveFully(Method def)throws NoSuchMethodException, SecurityException{
Class>[] paramTypes = def.getParameterTypes();
int paramCount = metaData.foreignKeys.size() + metaData.getImportedKeys().size() + 1;
checkArgument(paramTypes.length == paramCount,"%s parameter required for %s",paramCount,def.getName());
Method impl = getDeclaredMethod(D_SAVEFULLY, BaseBean.class,Object[].class);
return new SaveFullyInvoker(def, impl);
}
private MethodInvoker saveFullyAsTransaction(Method def)throws NoSuchMethodException, SecurityException{
Class>[] paramTypes = def.getParameterTypes();
int paramCount = metaData.foreignKeys.size() + metaData.getImportedKeys().size() + 1;
checkArgument(paramTypes.length == paramCount,"%s parameter required for %s",paramCount,def.getName());
Method impl = getDeclaredMethod(D_SAVEFULLYASTRANSACTION, BaseBean.class,Object[].class);
return new SaveFullyInvoker(def, impl);
}
//////////////////////////////////////
// GET/SET FOREIGN KEY BEAN METHOD
//////////////////////////////////////
private MethodInvoker getReferencedBean(Method def)throws NoSuchMethodException, SecurityException{
Class>[] paramTypes = def.getParameterTypes();
String methodName = def.getName();
checkArgument(paramTypes.length == 1,"only 1 parameter required for %s",def.getName());
Pattern pattern = Pattern.compile(P_GETREFERENCEDBEAN);
Matcher matcher = pattern.matcher(methodName);
checkArgument(matcher.matches(),"INVALID method name pattern,%s required",P_GETREFERENCEDBEAN);
String readableName = matcher.group(1);
ForeignKeyMetaData foreignKey = metaData.getForeignKeyByRn(readableName);
Method impl = getDeclaredMethod(D_GETREFERENCEDBEAN, foreignKey.name.getClass(), BaseBean.class);
return new MethodInvoker(def, impl, delegate, foreignKey.name);
}
private MethodInvoker setReferencedBean(Method def)throws NoSuchMethodException, SecurityException{
Class>[] paramTypes = def.getParameterTypes();
String methodName = def.getName();
checkArgument(paramTypes.length == 2,"2 parameter required for %s",def.getName());
Pattern pattern = Pattern.compile(P_SETREFERENCEDBEAN);
Matcher matcher = pattern.matcher(methodName);
checkArgument(matcher.matches(),"INVALID method name pattern,%s required",P_SETREFERENCEDBEAN);
String readableName = matcher.group(1);
ForeignKeyMetaData foreignKey = metaData.getForeignKeyByRn(readableName);
Method impl = getDeclaredMethod(D_SETREFERENCEDBEAN,
paramBuilder().add(foreignKey.name.getClass(),wrapBaseBean(paramTypes)).build());
return new MethodInvoker(def, impl, delegate, foreignKey.name);
}
//_____________________________________________________________________
//
// USING INDICES
//_____________________________________________________________________
private MethodInvoker loadByIndex(Method def)throws NoSuchMethodException, SecurityException{
Method impl;
Class>[] paramTypes = def.getParameterTypes();
String methodName = def.getName();
Pattern pattern = Pattern.compile(P_LOADBYINDEX);
Matcher matcher = pattern.matcher(methodName);
checkArgument(matcher.matches(),"INVALID method name pattern,%s required",P_LOADBYINDEX);
String readableName = matcher.group(1);
IndexMetaData index = metaData.getIndexCheckedByRn(readableName);
if(index.unique){
Object indexArray = Array.newInstance(metaData.jdbcTypeOf(metaData.indexIdArray(index.name)[0]), 0);
if(paramTypes[0].equals(indexArray.getClass()) && index.columns.size() == 1){
impl = getDeclaredMethod(D_LOADBYINDEXFORINDICES, index.name.getClass(), Object[].class);
} else if(Collection.class.equals(paramTypes[0]) && index.columns.size() == 1){
impl = getDeclaredMethod(D_LOADBYINDEXFORINDICES, index.name.getClass(), Collection.class);
}else if(Arrays.equals(metaData.indexTypeArray(index.name), paramTypes)){
impl = getDeclaredMethod(D_LOADUNIQUEBYINDEX, index.name.getClass(), Object[].class);
} else{
throw makeNoSuchMethodException(def);
}
}else{
impl = getDeclaredMethod(D_LOADBYINDEX, index.name.getClass(), Object[].class);
}
return new MethodInvoker(def, impl, delegate, index.name);
}
private MethodInvoker loadUniqueByIndexChecked(Method def)throws NoSuchMethodException, SecurityException{
Method impl;
Class>[] paramTypes = def.getParameterTypes();
String methodName = def.getName();
Pattern pattern = Pattern.compile(P_LOADUNIQUEBYINDEXCHECKED);
Matcher matcher = pattern.matcher(methodName);
checkArgument(matcher.matches(),"INVALID method name pattern,%s required",P_LOADUNIQUEBYINDEXCHECKED);
String readableName = matcher.group(1);
IndexMetaData index = metaData.getIndexCheckedByRn(readableName);
if(Arrays.equals(metaData.indexTypeArray(index.name), paramTypes)){
impl = getDeclaredMethod(D_LOADUNIQUEBYINDEXCHECKED, index.name.getClass(), Object[].class);
} else{
throw makeNoSuchMethodException(def);
}
return new MethodInvoker(def, impl, delegate, index.name);
}
private MethodInvoker loadByIndexAsList(Method def)throws NoSuchMethodException, SecurityException{
String methodName = def.getName();
Pattern pattern = Pattern.compile(P_LOADBYINDEXASLIST);
Matcher matcher = pattern.matcher(methodName);
checkArgument(matcher.matches(),"INVALID method name pattern,%s required",P_LOADBYINDEXASLIST);
String readableName = matcher.group(1);
IndexMetaData index = metaData.getIndexCheckedByRn(readableName);
Method impl = getDeclaredMethod(D_LOADBYINDEXASLIST, index.name.getClass(), Object[].class);
return new MethodInvoker(def, impl, delegate, index.name);
}
private MethodInvoker deleteByIndex(Method def)throws NoSuchMethodException, SecurityException{
String methodName = def.getName();
Pattern pattern = Pattern.compile(P_DELETEBYINDEX);
Matcher matcher = pattern.matcher(methodName);
checkArgument(matcher.matches(),"INVALID method name pattern,%s required",P_DELETEBYINDEX);
String readableName = matcher.group(1);
IndexMetaData index = metaData.getIndexCheckedByRn(readableName);
Method impl = getDeclaredMethod(D_DELETEBYINDEX, index.name.getClass(), Object[].class);
return new MethodInvoker(def, impl, delegate, index.name);
}
//_____________________________________________________________________
//
// MANY TO MANY: LOAD OTHER BEAN VIA JUNCTION TABLE
//_____________________________________________________________________
private MethodInvoker loadViaJunctionAsList(Method def)throws NoSuchMethodException, SecurityException{
Class>[] paramTypes = def.getParameterTypes();
String methodName = def.getName();
checkArgument(paramTypes.length == 1 || paramTypes.length == 3,"1 or 3 parameter required for %s",def.getName());
Pattern pattern = Pattern.compile(P_LOADVIAJUNCTIONASLIST);
Matcher matcher = pattern.matcher(methodName);
checkArgument(matcher.matches(),"INVALID method name pattern,%s required",P_LOADVIAJUNCTIONASLIST);
String coreClassName = matcher.group(1);
String junctionTable = RowMetaData.getRowMetaDataByCoreClassName(coreClassName, metaData.alias).tablename;
paramBuilder().add(junctionTable.getClass(),wrapBaseBean(paramTypes)).build();
Method impl = getDeclaredMethod(D_LOADVIAJUNCTIONASLIST,
paramBuilder().add(junctionTable.getClass(),wrapBaseBean(paramTypes)).build());
return new MethodInvoker(def, impl, delegate, junctionTable);
}
private MethodInvoker addJunction(Method def) throws NoSuchMethodException, SecurityException{
String name = def.getName();
Type[] gTypes = def.getGenericParameterTypes();
Class>[] paramTypes = def.getParameterTypes();
checkArgument(paramTypes.length == 2,"only 2 parameter required for %s",name);
RowMetaData junctionTable = metaData.getJunctionTableFor(gTypes[1]);
Method impl = getDeclaredMethod(D_ADDJUNCTION,
paramBuilder().add(junctionTable.tablename.getClass(),wrapBaseBean(paramTypes)).build());
return new MethodInvoker(def, impl, delegate, junctionTable.tablename);
}
private MethodInvoker deleteJunction(Method def) throws NoSuchMethodException, SecurityException{
Type[] gTypes = def.getGenericParameterTypes();
Class>[] paramTypes = def.getParameterTypes();
checkArgument(paramTypes.length == 2,"only 2 parameter required for %s",def.getName());
RowMetaData junctionTable = metaData.getJunctionTableFor(gTypes[1]);
Method impl = getDeclaredMethod(D_DELETEJUNCTION,
paramBuilder().add(junctionTable.tablename.getClass(),wrapBaseBean(paramTypes)).build());
return new MethodInvoker(def, impl, delegate, junctionTable.tablename);
}
private MethodInvoker toPrimaryKeyList(Method def) throws NoSuchMethodException, SecurityException{
Method impl;
Class>[] paramTypes = def.getParameterTypes();
Class> pkType = metaData.columnTypeOf(metaData.primaryKeyIds[0]);
checkArgument(paramTypes.length == 1,"only 1 parameter required for %s",def.getName());
if(Collection.class.isAssignableFrom(paramTypes[0])){
impl = getDeclaredMethod(M_TOPRIMARYKEYLIST, Class.class,Collection.class);
}else{
Object beanArray = Array.newInstance(metaData.beanType, 0);
if(paramTypes[0] == beanArray.getClass()){
impl = getDeclaredMethod(M_TOPRIMARYKEYLIST, Class.class,BaseBean[].class);
}else {
throw makeNoSuchMethodException(def);
}
}
return new MethodInvoker(def, impl, delegate, pkType);
}
//_____________________________________________________________________
//
// SELF-REFERENCE
//_____________________________________________________________________
private MethodInvoker listOfSelfRef(Method def) throws NoSuchMethodException, SecurityException{
Class>[] paramTypes = def.getParameterTypes();
String methodName = def.getName();
checkArgument(paramTypes.length == 1,"only 1 parameter required for %s",def.getName());
Pattern pattern = Pattern.compile(P_LISTOFSELFREF);
Matcher matcher = pattern.matcher(methodName);
checkArgument(matcher.matches(),"INVALID method name pattern,%s required",P_LISTOFSELFREF);
String readableName = matcher.group(1);
ForeignKeyMetaData selfRefKey = metaData.getSelfRefKeyByRn(readableName);
Method impl = getDeclaredMethod(D_LISTOFSELFREF,
paramBuilder().add(selfRefKey.name.getClass(),paramTypes).genericNormalize(1, Object[].class).build());
return new MethodInvoker(def, impl, delegate, selfRefKey.name);
}
private MethodInvoker levelOfSelfRef(Method def) throws NoSuchMethodException, SecurityException{
Class>[] paramTypes = def.getParameterTypes();
String methodName = def.getName();
checkArgument(paramTypes.length == 1,"only 1 parameter required for %s",def.getName());
Pattern pattern = Pattern.compile(P_LEVELOFSELFREF);
Matcher matcher = pattern.matcher(methodName);
checkArgument(matcher.matches(),"INVALID method name pattern,%s required",P_LEVELOFSELFREF);
String readableName = matcher.group(1);
ForeignKeyMetaData selfRefKey = metaData.getSelfRefKeyByRn(readableName);
Method impl = getDeclaredMethod(D_LEVELOFSELFREF,
paramBuilder().add(selfRefKey.name.getClass(),paramTypes).genericNormalize(1, Object[].class).build());
return new MethodInvoker(def, impl, delegate, selfRefKey.name);
}
private MethodInvoker isCycleOfSelfRef(Method def) throws NoSuchMethodException, SecurityException{
Class>[] paramTypes = def.getParameterTypes();
String methodName = def.getName();
checkArgument(paramTypes.length == 1,"only 1 parameter required for %s",def.getName());
Pattern pattern = Pattern.compile(P_ISCYCLEOFSELFREF);
Matcher matcher = pattern.matcher(methodName);
checkArgument(matcher.matches(),"INVALID method name pattern,%s required",P_ISCYCLEOFSELFREF);
String readableName = matcher.group(1);
ForeignKeyMetaData selfRefKey = metaData.getSelfRefKeyByRn(readableName);
Method impl = getDeclaredMethod(D_ISCYCLEOFSELFREF,
paramBuilder().add(selfRefKey.name.getClass(),paramTypes).genericNormalize(1, Object[].class).build());
return new MethodInvoker(def, impl, delegate, selfRefKey.name);
}
private MethodInvoker checkCycleOfSelfRef(Method def) throws NoSuchMethodException, SecurityException{
Class>[] paramTypes = def.getParameterTypes();
String methodName = def.getName();
checkArgument(paramTypes.length == 1,"only 1 parameter required for %s",def.getName());
Pattern pattern = Pattern.compile(P_CHECKCYCLEOFSELFREF);
Matcher matcher = pattern.matcher(methodName);
checkArgument(matcher.matches(),"INVALID method name pattern,%s required",P_CHECKCYCLEOFSELFREF);
String readableName = matcher.group(1);
ForeignKeyMetaData selfRefKey = metaData.getSelfRefKeyByRn(readableName);
Method impl = getDeclaredMethod(D_CHECKCYCLEOFSELFREF,
paramBuilder().add(selfRefKey.name.getClass(),paramTypes).genericNormalize(1, Object.class).build());
return new MethodInvoker(def, impl, delegate, selfRefKey.name);
}
private MethodInvoker topOfSelfRef(Method def) throws NoSuchMethodException, SecurityException{
Class>[] paramTypes = def.getParameterTypes();
String methodName = def.getName();
checkArgument(paramTypes.length == 1,"only 1 parameter required for %s",def.getName());
Pattern pattern = Pattern.compile(P_TOPOFSELFREF);
Matcher matcher = pattern.matcher(methodName);
checkArgument(matcher.matches(),"INVALID method name pattern,%s required",P_TOPOFSELFREF);
String readableName = matcher.group(1);
ForeignKeyMetaData selfRefKey = metaData.getSelfRefKeyByRn(readableName);
Method impl = getDeclaredMethod(D_TOPOFSELFREF,
paramBuilder().add(selfRefKey.name.getClass(),paramTypes).genericNormalize(1, Object[].class).build());
return new MethodInvoker(def, impl, delegate, selfRefKey.name);
}
private MethodInvoker childListOfSelfRef(Method def) throws NoSuchMethodException, SecurityException{
return methodOfRecursionOfSelfRef(def,P_CHILDLISTOFSELFREF,D_CHILDLISTOFSELFREF, Object[].class);
}
private MethodInvoker childrenOfSelfRef(Method def) throws NoSuchMethodException, SecurityException{
return methodOfRecursionOfSelfRef(def,P_CHILDRENOFSELFREF,D_CHILDRENOFSELFREF, Object[].class);
}
private MethodInvoker childrenOfSelfRefForBeans(Method def) throws NoSuchMethodException, SecurityException{
return methodOfRecursionOfSelfRef(def,P_CHILDRENOFBEANSOFSELFREF,D_CHILDRENOFBEANSOFSELFREF, null);
}
private MethodInvoker childrenOfSelfRefForPks(Method def) throws NoSuchMethodException, SecurityException{
return methodOfRecursionOfSelfRef(def,P_CHILDRENOFPKSOFSELFREF,D_CHILDRENOFPKSOFSELFREF, null);
}
private MethodInvoker methodOfRecursionOfSelfRef(Method def,String regex,String delegateName, Class> normalizeFirstArgType) throws NoSuchMethodException, SecurityException{
Class>[] paramTypes = def.getParameterTypes();
String methodName = def.getName();
checkArgument(paramTypes.length == 1,"only 1 parameter required for %s",def.getName());
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(methodName);
checkArgument(matcher.matches(),"INVALID method name pattern,%s required",regex);
String readableName = matcher.group(1);
ForeignKeyMetaData selfRefKey = metaData.getSelfRefKeyByRn(readableName);
Method impl = getDeclaredMethod(delegateName,
paramBuilder().add(selfRefKey.name.getClass(),paramTypes).genericNormalize(1, normalizeFirstArgType).build());
return new MethodInvoker(def, impl, delegate, selfRefKey.name);
}
private static final boolean isVoid(Class> clazz){
return "void".equals(clazz.getName());
}
private static final Class> wrapBaseBean(Class> type){
if(null != type){
if(type.isArray()){
Class> componentType = wrapBaseBean(type.getComponentType());
if(componentType != type.getComponentType()){
return Array.newInstance(componentType, 0).getClass();
}
return type;
}else{
if(BaseBean.class.isAssignableFrom(type)){
return BaseBean.class;
}
return type;
}
}
return type;
}
private static final Class>[] wrapBaseBean(Class>... types){
if(null != types){
for(int i=0;i> builder = Lists.newLinkedList();
ParamTypeBuilder add(Class>type){
builder.add(type);
return this;
}
ParamTypeBuilder add(Class>[]types,int start){
builder.addAll(Arrays.asList(Arrays.copyOfRange(types, start, types.length)));
return this;
}
ParamTypeBuilder add(Class> type,Class> ...types){
builder.add(type);
builder.addAll(Arrays.asList(types));
return this;
}
/**
* 对象索引指定的类型进行泛型归一化
* 如果为{@link BaseBean}的子类则改为{@link BaseBean},否则改为{@code normalClass}
* @param index
* @param normalizeClass 归一化类型
* @return 当前对象
*/
ParamTypeBuilder genericNormalize(int index,Class> normalizeClass){
try {
Class> type = builder.get(index);
if(BaseBean.class.isAssignableFrom(type)){
builder.set(index, BaseBean.class);
}else if(null != normalizeClass){
builder.set(index, normalizeClass);
}
} catch (IndexOutOfBoundsException e) {
throw new IllegalArgumentException(logString("INVALID index %s for parameter types array", index));
}
return this;
}
/**
* 对象索引指定的类型进行泛型归一化
* 如果为{@link BaseBean}的子类则改为{@link BaseBean},否则改为{@code normalClass},
* 删除{@code index}之后的所有元素
* @param index
* @param normalizeClass 归一化类型
* @return 当前对象
*/
ParamTypeBuilder normalizeLast(int index,Class> normalizeClass){
try {
Class> type = builder.get(index);
if(BaseBean.class.isAssignableFrom(type)){
builder.set(index, BaseBean.class);
}else{
builder.set(index, normalizeClass);
}
// 删除index之后续的所有元素
while(builder.size() > index+1){
builder.remove(index + 1);
}
} catch (IndexOutOfBoundsException e) {
throw new IllegalArgumentException(logString("INVALID index %s for parameter types array", index));
}
return this;
}
Class>[] build(){
return builder.toArray(new Class>[0]);
}
}
private static ParamTypeBuilder paramBuilder(){
return new ParamTypeBuilder();
}
/**
* 调用执行方法调用,剥离封装在{@link InvocationTargetException}中的方法调用异常直接抛出
* @param method 方法对象(不可为{@code null})
* @param obj 方法调用对象
* @param input 方法调用参数
* @return 方法调用返回值
* @throws Throwable
*/
private static Object stripedInvoke(Method method,Object obj,Object... input) throws Throwable {
try {
return method.invoke(obj, input);
} catch (InvocationTargetException e) {
Throwable te = e.getTargetException();
if(te != null){
// if(debug){
//// log("InvocationTargetException:"+te.toString(), te);
// log("InvocationTargetException:"+te.toString());
// }
/** 剥离出方法调用中产生的异常直接抛出 */
throw te;
}else{
log(e.toString());
throw e;
}
}
}
/**
* 方法调用接口
* @author guyadong
*/
interface Invoker {
static final Object[] EMPTY_OBJECT_ARRAY = new Object[]{};
/**
* 执行方法调用
* @param input 输入参数数组
* @return 调用返回值
* @throws Throwable 方法调用抛出异常
*/
Object invoke(Object[] input) throws Throwable;
}
private class ObjectInvoker implements Invoker{
final Method method;
ObjectInvoker(Method method) {
this.method = method;
}
@Override
public Object invoke(Object[] input) throws Throwable {
return stripedInvoke(method, delegate, firstNonNull(input,EMPTY_OBJECT_ARRAY));
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("\n");
builder.append(" @Override\n");
builder.append(" public ").append(signatureOf(method,true,true)).append("{\n");
builder.append(" ");
if(!isVoid(method.getReturnType())){
builder.append("return ");
}
builder.append("delegate.").append(method.getName()).append("(");
Class>[] paramTypes = method.getParameterTypes();
for(int j = 0; j < paramTypes.length;++j){
if(j > 0){
builder.append(",");
}
builder.append("arg").append(j);
}
builder.append(");\n");
builder.append(" }\n");
return builder.toString();
}
}
/**
* 方法调用对象,用于封装执行方法调用时的所有信息
* @author guyadong
*
*/
private class MethodInvoker implements Invoker {
/** 接口方法 */
final Method def;
/** {@link #manager}中与接口方法({@link #def})对应的实现方法 */
final Method impl;
/** 执行方法调用的对象 */
protected final BaseTableManager extends BaseBean> manager;
/** 执行方法调用时除原有传入参数之外的附加参数列表(排在原输入参数之前) */
protected final Object[] additionalParams;
/** 调用参数转换器,用于生成调用方法({@link #impl})的参数 */
private final Function