Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
gu.sql2java.RowMetaData Maven / Gradle / Ivy
package gu.sql2java;
import static com.google.common.base.Preconditions.*;
import static com.google.common.base.MoreObjects.*;
import static gu.sql2java.SimpleLog.*;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.ServiceLoader;
import java.util.concurrent.ExecutionException;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Objects;
import com.google.common.base.Predicate;
import com.google.common.base.Strings;
import com.google.common.base.Throwables;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableBiMap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Ordering;
import com.google.common.primitives.Ints;
import com.google.common.util.concurrent.UncheckedExecutionException;
/**
* meta data used to define a table
* @author guyadong
*
*/
public class RowMetaData implements IRowMetaData{
protected static final String UNKNOW_TABLENAME="UNKNOWN";
protected static final String UNKNOW_TABLETYPE="UNKNOWN";
public final String tablename;
public final String tableType;
public final Class extends BaseBean> beanType;
public final String coreClass;
public final Class extends TableManager>> managerInterfaceClass;
public final ImmutableList columnNames;
public final String columnFields;
public final String columnFullFields;
public final ImmutableList columnJavaNames;
public final ImmutableList getterMethods;
public final ImmutableList setterMethods;
public final ImmutableList> columnTypes;
private final ImmutableMap nameIndexsMap;
private final ImmutableMap javaNameIndexsMap;
public final int[] defaultColumnIdList;
public final int[] columnSizes;
public final int[] sqlTypes;
public final ImmutableMap> typesMap;
public final int columnCount;
public final int[] primaryKeyIds;
public final String[] primaryKeyNames;
public final int primaryKeyCount;
public final Class>[] primaryKeyTypes;
/** lazy load */
private volatile ImmutableMap junctionTablePkMap;
private final Map junctionTablePkStrMap;
public final Class> lockColumnType;
public final String lockColumnName;
/**
* tablename-ForeignKeyMetaData map
*/
public final Map foreignKeys;
/**
* universal name-ForeignKeyMetaData map
*/
public final Map foreignKeysRn;
public final Map indices;
public final Map indicesRn;
public final Function COLUMNID_FUN = new Function(){
@Override
public Integer apply(String input) {
return columnIDOf(input);
}};
public final Function COLUMNNAME_FUN = new Function(){
@Override
public String apply(Integer input) {
return columnNameOf(input);
}};
public final Function> COLUMNTYPE_FUN = new Function>(){
@Override
public Class> apply(String input) {
return columnTypeOf(input);
}};
/** lazy load */
private volatile ImmutableList importedKeys;
/** lazy load */
private volatile Map importKeysMap;
public final int autoincrementColumnId;
protected RowMetaData(
String tablename,
String tableType,
Class extends BaseBean> beanType,
String coreClass,
Class extends TableManager>> managerInterfaceClass,
List columnNames,
List columnJavaNames,
List getters,
List setters,
Class>[] columnTypes,
int[] columnSizes,
int[] sqlTypes,
List primaryKeyNames,
Map junctionTablePkMap,
Class> lockColumnType,
String lockColumnName, List foreignKeys, List indices, String autoincrement) {
columnJavaNames = firstNonNull(columnJavaNames,Collections.emptyList());
getters = firstNonNull(getters,Collections.emptyList());
setters = firstNonNull(setters,Collections.emptyList());
this.junctionTablePkStrMap = firstNonNull(junctionTablePkMap, Collections.emptyMap());
primaryKeyNames = firstNonNull(primaryKeyNames, Collections.emptyList());
foreignKeys = firstNonNull(foreignKeys, Collections.emptyList());
indices = firstNonNull(indices, Collections.emptyList());
autoincrement = firstNonNull(autoincrement, "");
this.tablename = checkNotNull(tablename,"tablename is null");
this.tableType = checkNotNull(tableType,"tableType is null");
this.beanType = checkNotNull(beanType,"beanType is null");
this.coreClass = coreClass;
this.managerInterfaceClass = managerInterfaceClass;
this.columnNames = ImmutableList.copyOf(checkNotNull(columnNames,"columnNames is null"));
this.columnJavaNames = ImmutableList.copyOf(columnJavaNames);
this.columnTypes = ImmutableList.copyOf(checkNotNull(columnTypes,"columnTypes is null"));
this.columnSizes = null == columnSizes ? null : Arrays.copyOf(columnSizes,columnSizes.length);
this.sqlTypes = Arrays.copyOf(checkNotNull(sqlTypes,"sqlTypes is null"),sqlTypes.length);
checkArgument(this.columnNames.size() == this.columnTypes.size() && this.columnTypes.size() == this.sqlTypes.length,
"MISMATCH LENGTH for input list");
checkArgument(this.columnJavaNames.isEmpty() || this.columnJavaNames.size() == this.sqlTypes.length,
"MISMATCH LENGTH for columnJavaNames");
checkArgument(getters.isEmpty() || getters.size() == this.sqlTypes.length,
"MISMATCH LENGTH for getters");
checkArgument(setters.isEmpty() || setters.size() == this.sqlTypes.length,
"MISMATCH LENGTH for setters");
ImmutableMap.Builder nameIndexBuilder = ImmutableMap.builder();
ImmutableMap.Builder javaNameIndexBuilder = ImmutableMap.builder();
ImmutableMap.Builder> nameTypeBuilder = ImmutableMap.builder();
this.defaultColumnIdList = new int[sqlTypes.length];
for(int i = 0; i < sqlTypes.length; ++i){
defaultColumnIdList[i] = i;
nameIndexBuilder.put(columnNames.get(i), i);
nameTypeBuilder.put(columnNames.get(i), columnTypes[i]);
if(!columnJavaNames.isEmpty()){
javaNameIndexBuilder.put(columnJavaNames.get(i), i);
}
}
columnFields = Joiner.on(",").join(columnNames);
columnFullFields = Joiner.on(",").join(Lists.transform(columnNames, new Function(){
@Override
public String apply(String input) {
if("UNKNOWN".equals(RowMetaData.this.tableType)){
return input;
}
return RowMetaData.this.tablename + "." + input;
}}));
this.nameIndexsMap = nameIndexBuilder.build();
this.autoincrementColumnId = firstNonNull(nameIndexsMap.get(autoincrement), -1).intValue();
this.javaNameIndexsMap = javaNameIndexBuilder.build();
this.typesMap = nameTypeBuilder.build();
this.columnCount = sqlTypes.length;
this.primaryKeyNames = primaryKeyNames.toArray(new String[0]);
this.primaryKeyCount = primaryKeyNames.size();
this.primaryKeyIds = new int[primaryKeyNames.size()];
for(int i = 0 ; i < primaryKeyIds.length; ++i){
String name = primaryKeyNames.get(i);
checkArgument(primaryKeyIds[i]>=0,"INVALID primary key name %s",name);
primaryKeyIds[i] = columnIDOf(name);
}
this.primaryKeyTypes = Lists.transform(primaryKeyNames, COLUMNTYPE_FUN).toArray(new Class>[0]);
this.lockColumnType = lockColumnType;
this.lockColumnName = lockColumnName;
LinkedHashMap fkBuilder = Maps.newLinkedHashMap();
LinkedHashMap fkRnameBuilder = Maps.newLinkedHashMap();
for(String fk:foreignKeys){
ForeignKeyMetaData data = new ForeignKeyMetaData(fk, tablename);
fkBuilder.put(data.name,data);
fkRnameBuilder.put(data.readableName,data);
}
this.foreignKeys = Collections.unmodifiableMap(fkBuilder);
this.foreignKeysRn = Collections.unmodifiableMap(fkRnameBuilder);
LinkedHashMap indexBuilder = Maps.newLinkedHashMap();
LinkedHashMap indexRnameBuilder = Maps.newLinkedHashMap();
for(String fk:indices){
IndexMetaData data = new IndexMetaData(fk, tablename);
indexBuilder.put(data.name,data);
indexRnameBuilder.put(data.readableName,data);
}
this.indices = Collections.unmodifiableMap(indexBuilder);
this.indicesRn = Collections.unmodifiableMap(indexRnameBuilder);
ImmutableList.Builder getterMethodBuilder = ImmutableList.builder();
ImmutableList.Builder setterMethodBuilder = ImmutableList.builder();
for(int i = 0; i < sqlTypes.length; ++i){
try {
if(!getters.isEmpty()){
getterMethodBuilder.add(beanType.getMethod(getters.get(i)));
}
if(!setters.isEmpty()){
setterMethodBuilder.add(beanType.getMethod(setters.get(i), columnTypes[i]));
}
} catch (Exception e) {
Throwables.throwIfUnchecked(e);
throw new RuntimeException(e);
}
}
this.getterMethods = getterMethodBuilder.build();
this.setterMethods = setterMethodBuilder.build();
}
/**
* return column name specified by column id
* @param columnId column id
* @return column name or null if columnId is invalid
*/
public String columnNameOf(int columnId){
try{
return columnNames.get(columnId);
} catch(IndexOutOfBoundsException e){
return null;
}
}
/**
* return column full name(with table name,such as tablename.columnname) specified by column id
* @param columnId column id
* @return column full name or null if columnId is invalid
*/
public String fullNameOf(int columnId){
try{
if(tablename.startsWith(UNKNOW_TABLENAME)){
return columnNames.get(columnId);
}
return tablename + "." + columnNames.get(columnId);
} catch(IndexOutOfBoundsException e){
return null;
}
}
/**
* return column ordinal id(base 0) specified by column name
* @param column column name or full name,or java field name
* @return column ordinal id(base 0) or -1 if column name is invalid
*/
public final int columnIDOf(String column){
if(null != column){
String prefix = tablename + ".";
if(column.startsWith(prefix)){
column = column.substring(prefix.length());
}
return firstNonNull(nameIndexsMap.get(column),
firstNonNull(javaNameIndexsMap.get(column), -1));
}
return -1;
}
/**
* return column ordinal id(base 0) specified by column names
* @param columns array of column name or full name,or java field name
* @return array of column ordinal id(base 0) or empty array if columns is null
* @see #columnIDOf(String)
*/
public final int[] columnIDsOf(String... columns){
return null == columns ? new int[0] : Ints.toArray(Lists.transform(Arrays.asList(columns), COLUMNID_FUN));
}
/**
* return column ordinal id(base 0) specified by column names
* @param columns collection of column name or full name,or java field name
* @return array of column ordinal id(base 0) or empty array if columns is null
* @see #columnIDOf(String)
*/
public final int[] columnIDsOf(Collection columns){
return null == columns ? new int[0] : Ints.toArray(Collections2.transform(columns, COLUMNID_FUN));
}
/**
* return column names by column names
* @param columnIds array of column id
* @return array of column name or empty array if columnIds is null
* @see #columnNameOf(int)
*/
public final List columnNamesOf(int... columnIds){
return null == columnIds ? Collections.emptyList() : Lists.transform(Ints.asList(columnIds), COLUMNNAME_FUN);
}
/**
* @param columnId column id
* @return java type of column,or NULL if columnId is invalid
*/
public Class> columnTypeOf(int columnId){
try{
return columnTypes.get(columnId);
} catch(IndexOutOfBoundsException e){
return null;
}
}
/**
* @param column column name
* @return java type of column,or NULL if column is invalid
*/
public Class> columnTypeOf(String column){
try{
return columnTypes.get(columnIDOf(column));
} catch(IndexOutOfBoundsException e){
return null;
}
}
/**
* @param columnId column id
* @return SQL type of column,or throw {@link IllegalArgumentException} if columnId is invalid
* @see java.sql.Types
*/
public int sqlTypeOf(int columnId){
try{
return sqlTypes[columnId];
} catch(IndexOutOfBoundsException e){
throw new IllegalArgumentException(String.format("INVALID columnID %d",columnId));
}
}
/**
* lazy load
*/
private final LoadingCache checkLinkedTableCache = CacheBuilder.newBuilder().build(
new CacheLoader(){
@Override
public Boolean load(final String tablename) throws Exception {
return Iterables.tryFind(getJunctionTablePkMap().values(), new Predicate() {
@Override
public boolean apply(Object[] input) {
return tablename.equals(input[0]);
}
}).isPresent();
}});
/**
* check if the table specified by tablename is linked table of current table
* @param tablename
* @return true if be linked table
*/
public boolean isLinkedTable(String tablename){
try {
return checkLinkedTableCache.get(tablename);
} catch (ExecutionException e) {
Throwables.throwIfUnchecked(e.getCause());
throw new RuntimeException(e);
}
}
/**
* @return junctionTablePkMap
*/
public ImmutableMap getJunctionTablePkMap() {
if(junctionTablePkMap == null){
synchronized (this) {
if(junctionTablePkMap == null){
ImmutableMap.Builder builder = ImmutableMap.builder();
for(Entry entry:junctionTablePkStrMap.entrySet()){
String[] values = entry.getValue().split("\\.");
String foreignTable = values[0];
int columnId = getMetaData(foreignTable).columnIDOf(values[1]);
checkArgument(columnId >=0,"INVALID foreign key description %s", entry.getValue());
builder.put(entry.getKey(), new Object[]{foreignTable,columnId});
}
this.junctionTablePkMap = builder.build();
}
}
}
return junctionTablePkMap;
}
/**
* lazy load
*/
private final LoadingCache> junctionMapCache = CacheBuilder.newBuilder().build(
new CacheLoader>(){
@Override
public Map load(final String linkedTableName) throws Exception {
Map m = Maps.filterValues(getJunctionTablePkMap(), new Predicate(){
@Override
public boolean apply(Object[] input) {
return input[0].equals(linkedTableName);
}});
return Maps.transformValues(m, new Function() {
@Override
public String apply(Object[] input) {
return getMetaData((String)input[0]).fullNameOf((Integer)input[1]);
}
});
}});
public Map junctionMapOf(String linkedTableName){
try {
return junctionMapCache.get(linkedTableName);
} catch (ExecutionException e) {
Throwables.throwIfUnchecked(e.getCause());
throw new RuntimeException(e);
}
}
/** lazy load */
private final LoadingCache> foreignKeyIdCache = CacheBuilder.newBuilder().build(
new CacheLoader>(){
@Override
public ImmutableBiMap load(String fkName) throws Exception {
ForeignKeyMetaData foreignkey = foreignKeys.get(fkName);
checkArgument(foreignkey != null,"INVALID foreign key name:%s",fkName);
ImmutableBiMap.Builder builder = ImmutableBiMap.builder();
for(Entry entry:foreignkey.columnMaps.entrySet()){
builder.put(columnIDOf(entry.getKey()), getMetaData(foreignkey.foreignTable).columnIDOf(entry.getValue()));
}
return builder.build();
}});
/**
*
* @param fkName foreign key name
* @return map of column id TO foreign table column id
*/
public ImmutableBiMap foreignKeyIdMapOf(String fkName){
try {
return foreignKeyIdCache.get(fkName);
} catch (ExecutionException e) {
Throwables.throwIfUnchecked(e.getCause());
throw new RuntimeException(e);
}
}
private volatile ImmutableList selfRefKeys = null;
public ImmutableList getSelfRefKeys(){
if(selfRefKeys == null){
synchronized (this) {
if(selfRefKeys == null){
selfRefKeys = ImmutableList.copyOf(Iterables.filter(foreignKeys.values(), new Predicate(){
@Override
public boolean apply(ForeignKeyMetaData input) {
return input.selfRef;
}}));
}
}
}
return selfRefKeys;
}
/**
* lazy load
*/
private final LoadingCache selfRefKeyRnCache = CacheBuilder.newBuilder().build(
new CacheLoader(){
@Override
public ForeignKeyMetaData load(final String readableName) throws Exception {
return Iterables.find(getSelfRefKeys(),new Predicate(){
@Override
public boolean apply(ForeignKeyMetaData input) {
return input.readableName.equals(readableName);
}});
}});
public ForeignKeyMetaData getSelfRefKeyByRn(String readableName){
try {
return selfRefKeyRnCache.getUnchecked(readableName);
} catch (UncheckedExecutionException e) {
if( e.getCause() instanceof NoSuchElementException){
throw new RuntimeException(logString("INVALID foreign key readableName %s",readableName));
}
throw e;
}
}
/**
* lazy load
*/
private final LoadingCache foreignKeyIdArrayCache = CacheBuilder.newBuilder().build(
new CacheLoader(){
@Override
public int[] load(String fkName) throws Exception {
ForeignKeyMetaData foreignkey = checkNotNull(foreignKeys.get(fkName),"INVALID foreign key name:%s",fkName);
return foreignkey.foreignKeyIdArray(COLUMNID_FUN);
}});
public int[] foreignKeyIdArrayOf(String fkName){
try {
return foreignKeyIdArrayCache.get(fkName);
} catch (ExecutionException | UncheckedExecutionException e) {
Throwables.throwIfUnchecked(e.getCause());
throw new RuntimeException(e);
}
}
public ForeignKeyMetaData getForeignKey(String fkName){
return checkNotNull(foreignKeys.get(fkName),"INVALID foreign key %s",fkName);
}
public ForeignKeyMetaData getForeignKeyByRn(String readableName){
return checkNotNull(foreignKeysRn.get(readableName),"INVALID foreign key readableName %s",readableName);
}
public List foreignKeysOf(final String foreignTable){
Iterable found = Iterables.filter(foreignKeys.values(),
new Predicate(){
@Override
public boolean apply(ForeignKeyMetaData input) {
return input.foreignTable.equals(foreignTable);
}});
return Lists.newArrayList(found);
}
public ImmutableList getImportedKeys(){
if(this.importedKeys == null){
synchronized (this) {
if(this.importedKeys == null){
ImmutableList.Builder builder = ImmutableList.builder();
for(RowMetaData metaData:tableMetadata.values()){
builder.addAll(Iterables.filter(metaData.foreignKeys.values(), new Predicate() {
@Override
public boolean apply(ForeignKeyMetaData input) {
return input.foreignTable.equals(tablename);
}
}));
}
this.importedKeys = builder.build();
}
}
}
return this.importedKeys;
}
public ForeignKeyMetaData getImportedKey(String fkName){
if(this.importKeysMap == null){
synchronized (this) {
if(this.importKeysMap == null){
LinkedHashMap map = Maps.newLinkedHashMap();
for(ForeignKeyMetaData key:getImportedKeys()){
map.put(key.name, key);
}
this.importKeysMap = Collections.unmodifiableMap(map);
}
}
}
return checkNotNull(importKeysMap.get(fkName),"INVALID fkName %s",fkName);
}
/** lazy load */
private volatile ImmutableList junctionTables = null;
private volatile ImmutableMap,RowMetaData> junctionTablesBeantypeMap = null;
public ImmutableList getJunctionTables(){
if(junctionTables == null){
synchronized (this) {
if(junctionTables == null){
ImmutableList.Builder builder = ImmutableList.builder();
for(ForeignKeyMetaData foreignKey:getImportedKeys()){
RowMetaData fkdata = getMetaData(foreignKey.ownerTable);
if(fkdata.isLinkedTable(tablename)){
builder.add(fkdata);
}
}
junctionTables = builder.build();
}
}
}
return junctionTables;
}
public ImmutableMap,RowMetaData> getJunctionTablesLinkedBeantypeMap(){
if(junctionTablesBeantypeMap == null){
synchronized (this) {
if(junctionTablesBeantypeMap == null){
junctionTablesBeantypeMap = Maps.uniqueIndex(getJunctionTables(), new Function>(){
@Override
public Class> apply(RowMetaData input) {
for(Object[] values:input.getJunctionTablePkMap().values()){
if(!tablename.equals(values[0])){
// return bean type of linked table
return RowMetaData.getMetaData((String) values[0]).beanType;
}
}
throw new IllegalStateException("NOT FOUND linked table");
}});
}
}
}
return junctionTablesBeantypeMap;
}
public RowMetaData getJunctionTableFor(Class> linkedBeanType){
return checkNotNull(getJunctionTablesLinkedBeantypeMap().get(linkedBeanType),"NOT FOUND metadata for %s",linkedBeanType);
}
public RowMetaData getJunctionTableFor(Type linkedBeanType){
if(linkedBeanType instanceof Class>){
Class> clazz = (Class>)linkedBeanType;
if(clazz.isArray()){
return getJunctionTableFor(clazz.getComponentType());
}
return getJunctionTableFor(clazz);
}
checkArgument(linkedBeanType instanceof ParameterizedType,"INVALID TYPE %s",linkedBeanType);
Type typeArg = ((ParameterizedType)linkedBeanType).getActualTypeArguments()[0];
return getJunctionTableFor(typeArg);
}
private volatile ImmutableList foreignKeysForListeners;
/**
* @return 返回 所有需要输出foreign key listener的 {@link ForeignKeyMetaData}对象
*/
public ImmutableList getForeignKeysForListener(){
// double check
if(foreignKeysForListeners == null){
synchronized (this) {
if(foreignKeysForListeners == null){
Collection c = Maps.filterEntries(foreignKeys,
new Predicate>(){
@Override
public boolean apply(Entry input) {
ForeignKeyMetaData fk = input.getValue();
return fk.updateRule.isNoAction()
&& !Strings.isNullOrEmpty(fk.deleteRule.eventOfDeleteRule);
}}).values();
// 排序输出
foreignKeysForListeners = ImmutableList.copyOf(Ordering.natural().onResultOf(new Function(){
@Override
public String apply(ForeignKeyMetaData input) {
return input.name;
}}).sortedCopy(c));
}
}
}
return foreignKeysForListeners;
}
private volatile ImmutableMap uniqueIndeices;
public ImmutableMap getUniqueIndices(){
// double check
if(uniqueIndeices == null){
synchronized (this) {
if(uniqueIndeices == null){
uniqueIndeices = ImmutableMap.copyOf(Maps.filterValues(indices, IndexMetaData.UNIQUE_FILTER));
}
}
}
return uniqueIndeices;
}
public IndexMetaData getIndexChecked(String indexName){
return checkNotNull(getUniqueIndices().get(indexName),"INVALID indexName %s",indexName);
}
public IndexMetaData getIndexCheckedByRn(String readableName){
return checkNotNull(indicesRn.get(readableName),"INVALID readableName %s",readableName);
}
/**
* lazy load
*/
private final LoadingCache indexKeyIdArrayCache = CacheBuilder.newBuilder().build(
new CacheLoader(){
@Override
public int[] load(String indexName) throws Exception {
return getIndexChecked(indexName).getColumnIds(COLUMNID_FUN);
}});
public int[] indexIdArray(String indexName){
try {
return indexKeyIdArrayCache.get(indexName);
} catch (ExecutionException | UncheckedExecutionException e) {
if(null != e.getCause()){
Throwables.throwIfUnchecked(e.getCause());
throw new RuntimeException(e.getCause());
}
Throwables.throwIfUnchecked(e);
throw new RuntimeException(e);
}
}
/**
* lazy load
*/
private final LoadingCache[]> indexTypeArrayCache = CacheBuilder.newBuilder().build(
new CacheLoader[]>(){
@Override
public Class>[] load(String indexName) throws Exception {
indexIdArray(indexName);
return getIndexChecked(indexName).getColumnTypes(COLUMNTYPE_FUN);
}});
public Class>[] indexTypeArray(String indexName){
try {
return indexTypeArrayCache.get(indexName);
} catch (ExecutionException | UncheckedExecutionException e) {
if(null != e.getCause()){
Throwables.throwIfUnchecked(e.getCause());
throw new RuntimeException(e.getCause());
}
Throwables.throwIfUnchecked(e);
throw new RuntimeException(e);
}
}
private class RowComparator implements Comparator {
/**
* Holds the column id on which the comparison is performed.
*/
private final int columnId;
/**
* Value that will contain the information about the order of the sort: normal or reversal.
*/
private final boolean bReverse;
private RowComparator(int columnId, boolean bReverse) {
checkArgument(columnTypeOf(columnId) != null,"INVALID column id %s",columnId);
checkArgument(Comparable.class.isAssignableFrom(columnTypeOf(columnId)),
"type of column %s for the field is not supported Comparable",columnNames.get(columnId));
this.columnId = columnId;
this.bReverse = bReverse;
}
@SuppressWarnings("unchecked")
@Override
public int compare(B o1, B o2) {
int iReturn = 0;
Object v1= o1.getValue(columnId);
Object v2= o2.getValue(columnId);
if(v1 ==null && v2 !=null){
iReturn = -1;
}else if(v1 ==null && v2 ==null){
iReturn = 0;
}else if(v1 !=null && v2 ==null){
iReturn = 1;
}else{
iReturn = ((Comparable)v1).compareTo(v2);
}
return bReverse ? (-1 * iReturn) : iReturn;
}
}
public Comparator comparatorOf(int columnId,boolean bReverse){
return new RowComparator(columnId,bReverse);
}
static final ImmutableMap tableMetadata = loadRowMetaData();
private static final ImmutableMap, RowMetaData> beanTypeMetadata = Maps.uniqueIndex(tableMetadata.values(),
new Function>(){
@Override
public Class> apply(RowMetaData input) {
return input.beanType;
}});
/**
* SPI(Service Provider Interface)机制加载 {@link IRowMetaData}所有实例
* @return 表名和 {@link RowMetaData}实例的映射对象
*/
private static ImmutableMap loadRowMetaData() {
ServiceLoader providers = ServiceLoader.load(IRowMetaData.class);
Iterator itor = providers.iterator();
IRowMetaData instance;
ImmutableMap.Builder builder = ImmutableMap.builder();
while(itor.hasNext()){
instance = itor.next();
if(instance instanceof RowMetaData){
RowMetaData rowMetaData = (RowMetaData)instance;
builder.put(rowMetaData.tablename, rowMetaData);
}
}
return builder.build();
}
/**
* 根据表名返回对应的 {@link RowMetaData}实例
* @param tablename 表名
* @return {@link RowMetaData}实例,找不到时抛出异常
*/
public static final RowMetaData getMetaData(String tablename) {
RowMetaData metaData = tableMetadata.get(tablename);
return checkNotNull(metaData,"INVALID TABLE NAME %s",tablename);
}
/**
* 根据beanType返回对应的 {@link RowMetaData}实例
* @param beanType 表名
* @return {@link RowMetaData}实例,找不到时抛出异常
*/
public static final RowMetaData getMetaData(Class> beanType) {
RowMetaData metaData = beanTypeMetadata.get(beanType);
return checkNotNull(metaData,"INVALID bean type %s",beanType);
}
/** lazy load */
private final static LoadingCache metaDataClassNameCache = CacheBuilder.newBuilder().build(
new CacheLoader(){
@Override
public RowMetaData load(final String beanClassSimpleName) throws Exception {
Class> clazz = Iterables.find(beanTypeMetadata.keySet(), new Predicate>() {
@Override
public boolean apply(Class> input) {
return input.getSimpleName().equals(beanClassSimpleName);
}
});
return beanTypeMetadata.get(clazz);
}});
public static final RowMetaData getRowMetaDataByBeanClassName(String beanClassSimpleName){
try {
return metaDataClassNameCache.getUnchecked(beanClassSimpleName);
} catch (UncheckedExecutionException e) {
throw new IllegalArgumentException(logString("INVALID beanClassSimpleName %s",beanClassSimpleName));
}
}
public static final ForeignKeyMetaData getForeignKey(String importeBeanName,String readableName){
RowMetaData importedTableMetaData = getRowMetaDataByBeanClassName(importeBeanName);
return importedTableMetaData.getForeignKeyByRn(readableName);
}
/** lazy load */
private static final LoadingCache coreClassNameCache = CacheBuilder.newBuilder().build(
new CacheLoader(){
@Override
public RowMetaData load(final String coreClassName) throws Exception {
return Iterables.find(tableMetadata.values(), new Predicate() {
@Override
public boolean apply(RowMetaData input) {
return Objects.equal(input.coreClass, coreClassName);
}
});
}});
public static final RowMetaData getRowMetaDataByCoreClassName(String coreClassName){
try {
return coreClassNameCache.getUnchecked(coreClassName);
} catch (UncheckedExecutionException e) {
throw new IllegalArgumentException(logString("INVALID coreClassName %s",coreClassName));
}
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((columnNames == null) ? 0 : columnNames.hashCode());
result = prime * result + ((tableType == null) ? 0 : tableType.hashCode());
result = prime * result + ((tablename == null) ? 0 : tablename.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof RowMetaData)) {
return false;
}
RowMetaData other = (RowMetaData) obj;
if (columnNames == null) {
if (other.columnNames != null) {
return false;
}
} else if (!columnNames.equals(other.columnNames)) {
return false;
}
if (tableType == null) {
if (other.tableType != null) {
return false;
}
} else if (!tableType.equals(other.tableType)) {
return false;
}
if (tablename == null) {
if (other.tablename != null) {
return false;
}
} else if (!tablename.equals(other.tablename)) {
return false;
}
return true;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("RowMetaData [tablename=");
builder.append(tablename);
builder.append(", tableType=");
builder.append(tableType);
builder.append(", columnNames=");
builder.append(columnNames);
builder.append("]");
return builder.toString();
}
}