001package gu.sql2java; 002 003import static com.google.common.base.Preconditions.*; 004import static com.google.common.base.MoreObjects.*; 005 006import java.lang.reflect.Method; 007import java.util.Arrays; 008import java.util.Collection; 009import java.util.Collections; 010import java.util.Comparator; 011import java.util.Iterator; 012import java.util.List; 013import java.util.Map; 014import java.util.Map.Entry; 015import java.util.ServiceLoader; 016import java.util.concurrent.ExecutionException; 017 018import com.google.common.base.Function; 019import com.google.common.base.Joiner; 020import com.google.common.base.Predicate; 021import com.google.common.base.Strings; 022import com.google.common.base.Throwables; 023import com.google.common.cache.CacheBuilder; 024import com.google.common.cache.CacheLoader; 025import com.google.common.cache.LoadingCache; 026import com.google.common.collect.Collections2; 027import com.google.common.collect.ImmutableBiMap; 028import com.google.common.collect.ImmutableList; 029import com.google.common.collect.ImmutableMap; 030import com.google.common.collect.Iterables; 031import com.google.common.collect.Lists; 032import com.google.common.collect.Maps; 033import com.google.common.collect.Ordering; 034import com.google.common.primitives.Ints; 035import com.google.common.util.concurrent.UncheckedExecutionException; 036 037/** 038 * meta data used to define a table 039 * @author guyadong 040 * 041 */ 042public class RowMetaData implements IRowMetaData{ 043 protected static final String UNKNOW_TABLENAME="UNKNOWN"; 044 protected static final String UNKNOW_TABLETYPE="UNKNOWN"; 045 public final String tablename; 046 public final String tableType; 047 public final Class<? extends BaseBean> beanType; 048 public final ImmutableList<String> columnNames; 049 public final String columnFields; 050 public final String columnFullFields; 051 public final ImmutableList<String> columnJavaNames; 052 public final ImmutableList<Method> getterMethods; 053 public final ImmutableList<Method> setterMethods; 054 public final ImmutableList<Class<?>> columnTypes; 055 private final ImmutableMap<String, Integer> nameIndexsMap; 056 private final ImmutableMap<String, Integer> javaNameIndexsMap; 057 public final int[] defaultColumnIdList; 058 public final int[] sqlTypes; 059 public final ImmutableMap<String, Class<?>> typesMap; 060 061 public final int columnCount; 062 public final int[] primaryKeyIds; 063 public final String[] primaryKeyNames; 064 public final int primaryKeyCount; 065 /** lazy load */ 066 private volatile ImmutableMap<String, Object[]> junctionTablePkMap; 067 private final Map<String, String> junctionTablePkStrMap; 068 public final Class<?> lockColumnType; 069 public final String lockColumnName; 070 public final ImmutableMap<String,ForeignKeyMetaData> foreignKeys; 071 public final ImmutableMap<String, IndexMetaData> indices; 072 public final Function<String, Integer> COLUMNID_FUN = new Function<String, Integer>(){ 073 074 @Override 075 public Integer apply(String input) { 076 return columnIDOf(input); 077 }}; 078 public final Function<Integer,String> COLUMNNAME_FUN = new Function<Integer,String>(){ 079 080 @Override 081 public String apply(Integer input) { 082 return columnNameOf(input); 083 }}; 084 /** lazy load */ 085 private volatile ImmutableList<ForeignKeyMetaData> importedKeys; 086 /** lazy load */ 087 private volatile ImmutableMap<String, ForeignKeyMetaData> importKeysMap; 088 public final int autoincrementColumnId; 089 protected RowMetaData( 090 String tablename, 091 String tableType, 092 Class<? extends BaseBean> beanType, 093 List<String> columnNames, 094 List<String> columnJavaNames, 095 List<String> getters, 096 List<String> setters, 097 Class<?>[] columnTypes, 098 int[] sqlTypes, 099 List<String> primaryKeyNames, 100 Map<String, String> junctionTablePkMap, 101 Class<?> lockColumnType, 102 String lockColumnName, 103 List<String> foreignKeys, 104 List<String> indices, 105 String autoincrement) { 106 columnJavaNames = firstNonNull(columnJavaNames,Collections.<String>emptyList()); 107 getters = firstNonNull(getters,Collections.<String>emptyList()); 108 setters = firstNonNull(setters,Collections.<String>emptyList()); 109 this.junctionTablePkStrMap = firstNonNull(junctionTablePkMap, Collections.<String,String>emptyMap()); 110 primaryKeyNames = firstNonNull(primaryKeyNames, Collections.<String>emptyList()); 111 foreignKeys = firstNonNull(foreignKeys, Collections.<String>emptyList()); 112 indices = firstNonNull(indices, Collections.<String>emptyList()); 113 autoincrement = firstNonNull(autoincrement, ""); 114 this.tablename = checkNotNull(tablename,"tablename is null"); 115 this.tableType = checkNotNull(tableType,"tableType is null"); 116 this.beanType = checkNotNull(beanType,"beanType is null"); 117 this.columnNames = ImmutableList.copyOf(checkNotNull(columnNames,"columnNames is null")); 118 this.columnJavaNames = ImmutableList.copyOf(columnJavaNames); 119 this.columnTypes = ImmutableList.copyOf(checkNotNull(columnTypes,"columnTypes is null")); 120 this.sqlTypes = Arrays.copyOf(checkNotNull(sqlTypes,"sqlTypes is null"),sqlTypes.length); 121 checkArgument(this.columnNames.size() == this.columnTypes.size() && this.columnTypes.size() == this.sqlTypes.length, 122 "MISMATCH LENGTH for input list"); 123 checkArgument(this.columnJavaNames.isEmpty() || this.columnJavaNames.size() == this.sqlTypes.length, 124 "MISMATCH LENGTH for columnJavaNames"); 125 checkArgument(getters.isEmpty() || getters.size() == this.sqlTypes.length, 126 "MISMATCH LENGTH for getters"); 127 checkArgument(setters.isEmpty() || setters.size() == this.sqlTypes.length, 128 "MISMATCH LENGTH for setters"); 129 130 ImmutableMap.Builder<String, Integer> nameIndexBuilder = ImmutableMap.builder(); 131 ImmutableMap.Builder<String, Integer> javaNameIndexBuilder = ImmutableMap.builder(); 132 ImmutableMap.Builder<String, Class<?>> nameTypeBuilder = ImmutableMap.builder(); 133 this.defaultColumnIdList = new int[sqlTypes.length]; 134 for(int i = 0; i < sqlTypes.length; ++i){ 135 defaultColumnIdList[i] = i; 136 nameIndexBuilder.put(columnNames.get(i), i); 137 nameTypeBuilder.put(columnNames.get(i), columnTypes[i]); 138 if(!columnJavaNames.isEmpty()){ 139 javaNameIndexBuilder.put(columnJavaNames.get(i), i); 140 } 141 } 142 columnFields = Joiner.on(",").join(columnNames); 143 columnFullFields = Joiner.on(",").join(Lists.transform(columnNames, new Function<String,String>(){ 144 145 @Override 146 public String apply(String input) { 147 if("UNKNOWN".equals(RowMetaData.this.tableType)){ 148 return input; 149 } 150 return RowMetaData.this.tablename + "." + input; 151 }})); 152 153 this.nameIndexsMap = nameIndexBuilder.build(); 154 this.autoincrementColumnId = firstNonNull(nameIndexsMap.get(autoincrement), -1).intValue(); 155 156 this.javaNameIndexsMap = javaNameIndexBuilder.build(); 157 this.typesMap = nameTypeBuilder.build(); 158 this.columnCount = sqlTypes.length; 159 this.primaryKeyNames = primaryKeyNames.toArray(new String[0]); 160 161 this.primaryKeyCount = primaryKeyNames.size(); 162 this.primaryKeyIds = new int[primaryKeyNames.size()]; 163 for(int i = 0 ; i < primaryKeyIds.length; ++i){ 164 String name = primaryKeyNames.get(i); 165 checkArgument(primaryKeyIds[i]>=0,"INVALID primary key name %s",name); 166 primaryKeyIds[i] = columnIDOf(name); 167 } 168 this.lockColumnType = lockColumnType; 169 this.lockColumnName = lockColumnName; 170 ImmutableMap.Builder<String,ForeignKeyMetaData> fkBuilder = ImmutableMap.builder(); 171 for(String fk:foreignKeys){ 172 ForeignKeyMetaData data = new ForeignKeyMetaData(fk, tablename); 173 fkBuilder.put(data.name,data); 174 } 175 this.foreignKeys = fkBuilder.build(); 176 ImmutableMap.Builder<String,IndexMetaData> indexBuilder = ImmutableMap.builder(); 177 for(String fk:indices){ 178 IndexMetaData data = new IndexMetaData(fk, tablename); 179 indexBuilder.put(data.name,data); 180 } 181 this.indices = indexBuilder.build(); 182 183 ImmutableList.Builder<Method> getterMethodBuilder = ImmutableList.builder(); 184 ImmutableList.Builder<Method> setterMethodBuilder = ImmutableList.builder(); 185 186 for(int i = 0; i < sqlTypes.length; ++i){ 187 try { 188 if(!getters.isEmpty()){ 189 getterMethodBuilder.add(beanType.getMethod(getters.get(i))); 190 } 191 if(!setters.isEmpty()){ 192 setterMethodBuilder.add(beanType.getMethod(setters.get(i), columnTypes[i])); 193 } 194 } catch (Exception e) { 195 Throwables.throwIfUnchecked(e); 196 throw new RuntimeException(e); 197 } 198 } 199 200 this.getterMethods = getterMethodBuilder.build(); 201 this.setterMethods = setterMethodBuilder.build(); 202 } 203 /** 204 * return column name specified by column id 205 * @param columnId column id 206 * @return column name or null if columnId is invalid 207 */ 208 public String columnNameOf(int columnId){ 209 try{ 210 return columnNames.get(columnId); 211 } catch(IndexOutOfBoundsException e){ 212 return null; 213 } 214 } 215 /** 216 * return column full name(with table name,such as tablename.columnname) specified by column id 217 * @param columnId column id 218 * @return column full name or null if columnId is invalid 219 */ 220 public String fullNameOf(int columnId){ 221 try{ 222 if(tablename.startsWith(UNKNOW_TABLENAME)){ 223 return columnNames.get(columnId); 224 } 225 return tablename + "." + columnNames.get(columnId); 226 } catch(IndexOutOfBoundsException e){ 227 return null; 228 } 229 } 230 /** 231 * return column ordinal id(base 0) specified by column name 232 * @param column column name or full name,or java field name 233 * @return column ordinal id(base 0) or -1 if column name is invalid 234 */ 235 public final int columnIDOf(String column){ 236 if(null != column){ 237 String prefix = tablename + "."; 238 if(column.startsWith(prefix)){ 239 column = column.substring(prefix.length()); 240 } 241 return firstNonNull(nameIndexsMap.get(column), 242 firstNonNull(javaNameIndexsMap.get(column), -1)); 243 } 244 return -1; 245 } 246 247 /** 248 * return column ordinal id(base 0) specified by column names 249 * @param columns array of column name or full name,or java field name 250 * @return array of column ordinal id(base 0) or empty array if columns is null 251 * @see #columnIDOf(String) 252 */ 253 public final int[] columnIDsOf(String... columns){ 254 return null == columns ? new int[0] : Ints.toArray(Lists.transform(Arrays.asList(columns), COLUMNID_FUN)); 255 } 256 /** 257 * return column ordinal id(base 0) specified by column names 258 * @param columns collection of column name or full name,or java field name 259 * @return array of column ordinal id(base 0) or empty array if columns is null 260 * @see #columnIDOf(String) 261 */ 262 public final int[] columnIDsOf(Collection<String> columns){ 263 return null == columns ? new int[0] : Ints.toArray(Collections2.transform(columns, COLUMNID_FUN)); 264 } 265 /** 266 * return column names by column names 267 * @param columnIds array of column id 268 * @return array of column name or empty array if columnIds is null 269 * @see #columnNameOf(int) 270 */ 271 public final List<String> columnNamesOf(int... columnIds){ 272 return null == columnIds ? Collections.<String>emptyList() : Lists.transform(Ints.asList(columnIds), COLUMNNAME_FUN); 273 } 274 /** 275 * @param columnId column id 276 * @return java type of column,or NULL if columnId is invalid 277 */ 278 public Class<?> columnTypeOf(int columnId){ 279 try{ 280 return columnTypes.get(columnId); 281 } catch(IndexOutOfBoundsException e){ 282 return null; 283 } 284 } 285 /** 286 * @param column column name 287 * @return java type of column,or NULL if column is invalid 288 */ 289 public Class<?> columnTypeOf(String column){ 290 try{ 291 return columnTypes.get(columnIDOf(column)); 292 } catch(IndexOutOfBoundsException e){ 293 return null; 294 } 295 } 296 297 /** 298 * @param columnId column id 299 * @return SQL type of column,or throw {@link IllegalArgumentException} if columnId is invalid 300 * @see java.sql.Types 301 */ 302 public int sqlTypeOf(int columnId){ 303 try{ 304 return sqlTypes[columnId]; 305 } catch(IndexOutOfBoundsException e){ 306 throw new IllegalArgumentException(String.format("INVALID columnID %d",columnId)); 307 } 308 } 309 310 /** 311 * lazy load 312 */ 313 private final LoadingCache<String,Boolean> checkLinkedTableCache = CacheBuilder.newBuilder().build( 314 new CacheLoader<String,Boolean>(){ 315 316 @Override 317 public Boolean load(final String tablename) throws Exception { 318 return Iterables.tryFind(getJunctionTablePkMap().values(), new Predicate<Object[]>() { 319 320 @Override 321 public boolean apply(Object[] input) { 322 return tablename.equals(input[0]); 323 } 324 }).isPresent(); 325 }}); 326 327 /** 328 * check if the table specified by tablename is linked table of current table 329 * @param tablename 330 * @return true if be linked table 331 */ 332 public boolean isLinkedTable(String tablename){ 333 try { 334 return checkLinkedTableCache.get(tablename); 335 } catch (ExecutionException e) { 336 Throwables.throwIfUnchecked(e.getCause()); 337 throw new RuntimeException(e); 338 } 339 } 340 /** 341 * @return junctionTablePkMap 342 */ 343 public ImmutableMap<String, Object[]> getJunctionTablePkMap() { 344 if(junctionTablePkMap == null){ 345 synchronized (this) { 346 if(junctionTablePkMap == null){ 347 ImmutableMap.Builder<String, Object[]> builder = ImmutableMap.builder(); 348 for(Entry<String, String> entry:junctionTablePkStrMap.entrySet()){ 349 String[] values = entry.getValue().split("\\."); 350 String foreignTable = values[0]; 351 int columnId = getMedaData(foreignTable).columnIDOf(values[1]); 352 checkArgument(columnId >=0,"INVALID foreign key description %s", entry.getValue()); 353 builder.put(entry.getKey(), new Object[]{foreignTable,columnId}); 354 } 355 this.junctionTablePkMap = builder.build(); 356 } 357 } 358 } 359 return junctionTablePkMap; 360 } 361 362 /** 363 * lazy load 364 */ 365 private final LoadingCache<String,Map<String, String>> junctionMapCache = CacheBuilder.newBuilder().build( 366 new CacheLoader<String,Map<String, String>>(){ 367 368 @Override 369 public Map<String, String> load(final String linkedTableName) throws Exception { 370 Map<String, Object[]> m = Maps.filterValues(getJunctionTablePkMap(), new Predicate<Object[]>(){ 371 372 @Override 373 public boolean apply(Object[] input) { 374 return input[0].equals(linkedTableName); 375 }}); 376 return Maps.transformValues(m, new Function<Object[],String>() { 377 378 @Override 379 public String apply(Object[] input) { 380 return getMedaData((String)input[0]).fullNameOf((Integer)input[1]); 381 } 382 }); 383 }}); 384 385 public Map<String, String> junctionMapOf(String linkedTableName){ 386 try { 387 return junctionMapCache.get(linkedTableName); 388 } catch (ExecutionException e) { 389 Throwables.throwIfUnchecked(e.getCause()); 390 throw new RuntimeException(e); 391 } 392 } 393 /** lazy load */ 394 private final LoadingCache<String,ImmutableBiMap<Integer,Integer>> foreignKeyIdCache = CacheBuilder.newBuilder().build( 395 new CacheLoader<String, ImmutableBiMap<Integer,Integer>>(){ 396 397 @Override 398 public ImmutableBiMap<Integer, Integer> load(String fkName) throws Exception { 399 ForeignKeyMetaData foreignkey = foreignKeys.get(fkName); 400 checkArgument(foreignkey != null,"INVALID foreign key name:%s",fkName); 401 ImmutableBiMap.Builder<Integer, Integer> builder = ImmutableBiMap.builder(); 402 for(Entry<String, String> entry:foreignkey.columnMaps.entrySet()){ 403 builder.put(columnIDOf(entry.getKey()), getMedaData(foreignkey.foreignTable).columnIDOf(entry.getValue())); 404 } 405 return builder.build(); 406 }}); 407 408 /** 409 * 410 * @param fkName foreign key name 411 * @return map of column id TO foreign table column id 412 */ 413 public ImmutableBiMap<Integer, Integer> foreignKeyIdMapOf(String fkName){ 414 try { 415 return foreignKeyIdCache.get(fkName); 416 } catch (ExecutionException e) { 417 Throwables.throwIfUnchecked(e.getCause()); 418 throw new RuntimeException(e); 419 } 420 } 421 422 /** 423 * lazy load 424 */ 425 private final LoadingCache<String,int[]> foreignKeyIdArrayCache = CacheBuilder.newBuilder().build( 426 new CacheLoader<String,int[]>(){ 427 428 @Override 429 public int[] load(String fkName) throws Exception { 430 ForeignKeyMetaData foreignkey = checkNotNull(foreignKeys.get(fkName),"INVALID foreign key name:%s",fkName); 431 return foreignkey.foreignKeyIdArray(COLUMNID_FUN); 432 }}); 433 434 public int[] foreignKeyIdArrayOf(String fkName){ 435 try { 436 return foreignKeyIdArrayCache.get(fkName); 437 } catch (ExecutionException | UncheckedExecutionException e) { 438 Throwables.throwIfUnchecked(e.getCause()); 439 throw new RuntimeException(e); 440 } 441 } 442 public List<ForeignKeyMetaData> foreignKeysOf(final String foreignTable){ 443 Iterable<ForeignKeyMetaData> found = Iterables.filter(foreignKeys.values(), 444 new Predicate<ForeignKeyMetaData>(){ 445 @Override 446 public boolean apply(ForeignKeyMetaData input) { 447 return input.foreignTable.equals(foreignTable); 448 }}); 449 return Lists.newArrayList(found); 450 } 451 452 public ImmutableList<ForeignKeyMetaData> getImportedKeys(){ 453 if(this.importedKeys == null){ 454 synchronized (this) { 455 if(this.importedKeys == null){ 456 ImmutableList.Builder<ForeignKeyMetaData> builder = ImmutableList.builder(); 457 for(RowMetaData metaData:tableMetadata.values()){ 458 builder.addAll(Iterables.filter(metaData.foreignKeys.values(), new Predicate<ForeignKeyMetaData>() { 459 460 @Override 461 public boolean apply(ForeignKeyMetaData input) { 462 return input.foreignTable.equals(tablename); 463 } 464 })); 465 } 466 this.importedKeys = builder.build(); 467 } 468 } 469 } 470 return this.importedKeys; 471 } 472 473 public ForeignKeyMetaData getImportedKey(String fkName){ 474 if(this.importKeysMap == null){ 475 synchronized (this) { 476 if(this.importKeysMap == null){ 477 this.importKeysMap = Maps.uniqueIndex(getImportedKeys(), new Function<ForeignKeyMetaData, String>() { 478 479 @Override 480 public String apply(ForeignKeyMetaData input) { 481 return input.name; 482 } 483 }); 484 } 485 } 486 } 487 return checkNotNull(importKeysMap.get(fkName),"invalid ikIndex %s",fkName); 488 } 489 490 private volatile ImmutableList<ForeignKeyMetaData> foreignKeysForListeners; 491 /** 492 * @return 返回 所有需要输出foreign key listener的 {@link ForeignKeyMetaData}对象 493 */ 494 public ImmutableList<ForeignKeyMetaData> getForeignKeysForListener(){ 495 // double check 496 if(foreignKeysForListeners == null){ 497 synchronized (this) { 498 if(foreignKeysForListeners == null){ 499 Collection<ForeignKeyMetaData> c = Maps.filterEntries(foreignKeys, 500 new Predicate<Entry<String, ForeignKeyMetaData>>(){ 501 @Override 502 public boolean apply(Entry<String, ForeignKeyMetaData> input) { 503 ForeignKeyMetaData fk = input.getValue(); 504 return fk.updateRule.isNoAction() 505 && !Strings.isNullOrEmpty(fk.deleteRule.eventOfDeleteRule); 506 }}).values(); 507 // 排序输出 508 foreignKeysForListeners = ImmutableList.copyOf(Ordering.natural().onResultOf(new Function<ForeignKeyMetaData,String>(){ 509 @Override 510 public String apply(ForeignKeyMetaData input) { 511 return input.name; 512 }}).sortedCopy(c)); 513 } 514 } 515 } 516 return foreignKeysForListeners; 517 } 518 private volatile ImmutableMap<String, IndexMetaData> uniqueIndeices; 519 public ImmutableMap<String, IndexMetaData> getUniqueIndices(){ 520 // double check 521 if(uniqueIndeices == null){ 522 synchronized (this) { 523 if(uniqueIndeices == null){ 524 uniqueIndeices = ImmutableMap.copyOf(Maps.filterValues(indices, IndexMetaData.UNIQUE_FILTER)); 525 } 526 } 527 } 528 return uniqueIndeices; 529 } 530 531 public IndexMetaData getIndexChecked(String indexName){ 532 return checkNotNull(getUniqueIndices().get(indexName),"INVALID indexName %s",indexName); 533 } 534 /** 535 * lazy load 536 */ 537 private final LoadingCache<String,int[]> indexKeyIdArrayCache = CacheBuilder.newBuilder().build( 538 new CacheLoader<String,int[]>(){ 539 @Override 540 public int[] load(String indexName) throws Exception { 541 return getIndexChecked(indexName).getColumnIds(COLUMNID_FUN); 542 }}); 543 public int[] indexIdArray(String indexName){ 544 try { 545 return indexKeyIdArrayCache.get(indexName); 546 } catch (ExecutionException | UncheckedExecutionException e) { 547 if(null != e.getCause()){ 548 Throwables.throwIfUnchecked(e.getCause()); 549 throw new RuntimeException(e.getCause()); 550 } 551 Throwables.throwIfUnchecked(e); 552 throw new RuntimeException(e); 553 } 554 } 555 private class RowComparator<B extends BaseBean> implements Comparator<B> { 556 /** 557 * Holds the column id on which the comparison is performed. 558 */ 559 private final int columnId; 560 /** 561 * Value that will contain the information about the order of the sort: normal or reversal. 562 */ 563 private final boolean bReverse; 564 565 private RowComparator(int columnId, boolean bReverse) { 566 checkArgument(columnTypeOf(columnId) != null,"INVALID column id %s",columnId); 567 checkArgument(Comparable.class.isAssignableFrom(columnTypeOf(columnId)), 568 "type of column %s for the field is not supported Comparable",columnNames.get(columnId)); 569 this.columnId = columnId; 570 this.bReverse = bReverse; 571 } 572 573 @SuppressWarnings("unchecked") 574 @Override 575 public int compare(B o1, B o2) { 576 int iReturn = 0; 577 Object v1= o1.getValue(columnId); 578 Object v2= o2.getValue(columnId); 579 if(v1 ==null && v2 !=null){ 580 iReturn = -1; 581 }else if(v1 ==null && v2 ==null){ 582 iReturn = 0; 583 }else if(v1 !=null && v2 ==null){ 584 iReturn = 1; 585 }else{ 586 iReturn = ((Comparable<Object>)v1).compareTo(v2); 587 } 588 return bReverse ? (-1 * iReturn) : iReturn; 589 } 590 } 591 592 public <B extends BaseBean> Comparator<B> comparatorOf(int columnId,boolean bReverse){ 593 return new RowComparator<B>(columnId,bReverse); 594 } 595 596 private static final ImmutableMap<String, RowMetaData> tableMetadata = loadRowMetaData(); 597 private static final ImmutableMap<Class<?>, RowMetaData> beanTypeMetadata = Maps.uniqueIndex(tableMetadata.values(), 598 new Function<RowMetaData,Class<?>>(){ 599 600 @Override 601 public Class<?> apply(RowMetaData input) { 602 return input.beanType; 603 }});; 604 605 /** 606 * SPI(Service Provider Interface)机制加载 {@link IRowMetaData}所有实例 607 * @return 表名和 {@link RowMetaData}实例的映射对象 608 */ 609 private static ImmutableMap<String, RowMetaData> loadRowMetaData() { 610 ServiceLoader<IRowMetaData> providers = ServiceLoader.load(IRowMetaData.class); 611 Iterator<IRowMetaData> itor = providers.iterator(); 612 IRowMetaData instance; 613 ImmutableMap.Builder<String, RowMetaData> builder = ImmutableMap.builder(); 614 while(itor.hasNext()){ 615 instance = itor.next(); 616 if(instance instanceof RowMetaData){ 617 RowMetaData rowMetaData = (RowMetaData)instance; 618 builder.put(rowMetaData.tablename, rowMetaData); 619 } 620 } 621 return builder.build(); 622 } 623 /** 624 * 根据表名返回对应的 {@link RowMetaData}实例 625 * @param tablename 表名 626 * @return {@link RowMetaData}实例,找不到时抛出异常 627 */ 628 public static final RowMetaData getMedaData(String tablename) { 629 RowMetaData metaData = tableMetadata.get(tablename); 630 return checkNotNull(metaData,"INVALID TABLE NAME %s",tablename); 631 } 632 /** 633 * 根据beanType返回对应的 {@link RowMetaData}实例 634 * @param beanType 表名 635 * @return {@link RowMetaData}实例,找不到时抛出异常 636 */ 637 public static final RowMetaData getMedaData(Class<?> beanType) { 638 RowMetaData metaData = beanTypeMetadata.get(beanType); 639 return checkNotNull(metaData,"INVALID bean type %s",beanType); 640 } 641 642 643 @Override 644 public int hashCode() { 645 final int prime = 31; 646 int result = 1; 647 result = prime * result + ((columnNames == null) ? 0 : columnNames.hashCode()); 648 result = prime * result + ((tableType == null) ? 0 : tableType.hashCode()); 649 result = prime * result + ((tablename == null) ? 0 : tablename.hashCode()); 650 return result; 651 } 652 653 @Override 654 public boolean equals(Object obj) { 655 if (this == obj) { 656 return true; 657 } 658 if (obj == null) { 659 return false; 660 } 661 if (!(obj instanceof RowMetaData)) { 662 return false; 663 } 664 RowMetaData other = (RowMetaData) obj; 665 if (columnNames == null) { 666 if (other.columnNames != null) { 667 return false; 668 } 669 } else if (!columnNames.equals(other.columnNames)) { 670 return false; 671 } 672 if (tableType == null) { 673 if (other.tableType != null) { 674 return false; 675 } 676 } else if (!tableType.equals(other.tableType)) { 677 return false; 678 } 679 if (tablename == null) { 680 if (other.tablename != null) { 681 return false; 682 } 683 } else if (!tablename.equals(other.tablename)) { 684 return false; 685 } 686 return true; 687 } 688 @Override 689 public String toString() { 690 StringBuilder builder = new StringBuilder(); 691 builder.append("RowMetaData [tablename="); 692 builder.append(tablename); 693 builder.append(", tableType="); 694 builder.append(tableType); 695 builder.append(", columnNames="); 696 builder.append(columnNames); 697 builder.append("]"); 698 return builder.toString(); 699 } 700 701}