001package gu.sql2java.generator; 002 003import java.io.File; 004import java.io.FileOutputStream; 005import java.io.IOException; 006import java.io.OutputStreamWriter; 007import java.io.PrintWriter; 008import java.io.StringWriter; 009import java.io.Writer; 010import java.lang.reflect.Field; 011import java.net.URLClassLoader; 012import java.util.ArrayList; 013import java.util.Collections; 014import java.util.Date; 015import java.util.Hashtable; 016import java.util.Iterator; 017import java.util.List; 018import java.util.Properties; 019import java.util.StringTokenizer; 020import java.util.Vector; 021import java.util.regex.Matcher; 022import java.util.regex.Pattern; 023 024import org.apache.velocity.VelocityContext; 025import org.apache.velocity.app.FieldMethodizer; 026import org.apache.velocity.app.Velocity; 027import org.apache.velocity.context.Context; 028import org.apache.velocity.exception.ParseErrorException; 029import org.apache.velocity.exception.ResourceNotFoundException; 030import org.apache.velocity.runtime.RuntimeSingleton; 031import org.apache.velocity.tools.generic.EscapeTool; 032import org.apache.velocity.tools.generic.SortTool; 033 034import com.google.common.base.Joiner; 035import com.google.common.base.Predicate; 036import com.google.common.base.Throwables; 037import com.google.common.collect.Iterables; 038import com.google.common.collect.Lists; 039import com.google.common.primitives.Primitives; 040 041import net.gdface.utils.ClassLoaderUtils; 042 043import static com.google.common.base.Preconditions.checkNotNull;; 044 045public class CodeWriter { 046 public static final String NEW_LINE = System.getProperty("line.separator"); 047 protected static final String DEFAULT_BINARY_TYPE = "byte[]"; 048 protected static final String DEFAULT_BITSTAE_TYPE = "int"; 049 protected static Properties props; 050 public static String MGR_CLASS; 051 protected static String dateClassName; 052 protected static String timeClassName; 053 protected static String timestampClassName; 054 /** type for byte array,default 'byte[]',defined in properties */ 055 public static String binaryClassName; 056 private static String bitStateClassName; 057 private static Class<?> bitStateClass; 058 private static int bitStateClassSize; 059 private static String bitStateConstSuffix; 060 protected static Database db; 061 protected static Hashtable<String, String> includeHash; 062 protected static Hashtable<String, String> excludeHash; 063 protected static String basePackage; 064 /** 参见 {@link Column#getPreparedStatementMethod(String, String)} */ 065 private static final ThreadLocal<Boolean> fillNull = new ThreadLocal<Boolean>(){ 066 @Override 067 protected Boolean initialValue() { 068 return true; 069 }}; 070 protected static String destDir; 071 protected static String optimisticLockType; 072 protected static String optimisticLockColumn; 073 public static String classPrefix; 074 protected VelocityContext vc; 075 public Table table; 076 protected VelocityContext current_vc; 077 String current_fullfilename = ""; 078 String current_filename = ""; 079 /** 是否保存当前文件标志,模板可以通过改写此标志,跳过模板生成 */ 080 boolean save_current_file = true; 081 private static String[] extLibdirs; 082 private static String[] extClasspath; 083 private static URLClassLoader extensionClassLoader; 084 public CodeWriter(Database db, Properties props) { 085 try { 086 CodeWriter.db = db; 087 CodeWriter.props = props; 088 dateClassName = getProperty("jdbc2java.date", "java.sql.Date"); 089 timeClassName = getProperty("jdbc2java.time", "java.sql.Time"); 090 timestampClassName = getProperty("jdbc2java.timestamp", "java.sql.Timestamp"); 091 binaryClassName = getProperty("binary.type", DEFAULT_BINARY_TYPE); 092 bitStateClassName = getProperty("bitstate.type", DEFAULT_BITSTAE_TYPE); 093 bitStateClass = bitStateClassOf(bitStateClassName); 094 bitStateClassSize = bitSizeOf(bitStateClass); 095 bitStateConstSuffix = constSuffixOf(bitStateClassName); 096 basePackage = getPropertyRequired("codewriter.package"); 097 extLibdirs = getPropertyExploded("extension.tools.libdirs"); 098 extClasspath = getPropertyExploded("extension.tools.classpath"); 099 classPrefix = props.getProperty("codewriter.classprefix"); 100 this.setDestinationFolder(getPropertyRequired("codewriter.destdir")); 101 excludeHash = this.setHash(props.getProperty("tables.exclude")); 102 if (excludeHash.size() != 0) { 103 System.out.println("Excluding the following tables: " + props.getProperty("tables.exclude")); 104 } 105 if ((CodeWriter.includeHash = this.setHash(props.getProperty("tables.include"))).size() != 0) { 106 System.out.println("Including only the following tables: " + props.getProperty("tables.include")); 107 } 108 optimisticLockType = props.getProperty("optimisticlock.type", "none"); 109 optimisticLockColumn = props.getProperty("optimisticlock.column"); 110 } catch (Exception e) { 111 System.err.println("Threw an exception in the CodeWriter constructor:" + e.getMessage()); 112 e.printStackTrace(); 113 } 114 } 115 116 public void setDestinationFolder(String destDir) throws Exception { 117 CodeWriter.destDir = destDir; 118 if (destDir == null) { 119 throw new Exception("Missing property: codewriter.destdir"); 120 } 121 File dir = new File(destDir); 122 try { 123 dir.mkdirs(); 124 } catch (Exception e) { 125 // empty catch block 126 } 127 if (!dir.isDirectory() || !dir.canWrite()) { 128 throw new Exception("Cannot write to: " + destDir); 129 } 130 } 131 132 private Hashtable<String, String> setHash(String str) { 133 if (str == null || str.trim().equals("")) { 134 return new Hashtable<String, String>(); 135 } 136 Hashtable<String, String> hash = new Hashtable<String, String>(); 137 StringTokenizer st = new StringTokenizer(str); 138 while (st.hasMoreTokens()) { 139 String val = st.nextToken().toLowerCase(); 140 hash.put(val, val); 141 } 142 return hash; 143 } 144 145 public boolean checkTable(Table newTable) throws Exception { 146 System.out.println(" checking table " + newTable.getName() + " ..."); 147 boolean error = false; 148 Column[] primaryKeys = newTable.getPrimaryKeys(); 149 if (newTable.getColumns().length == 0) { 150 System.err.println(" WARN : no column found !"); 151 error = false; 152 } 153 if (primaryKeys.length == 0) { 154 System.err.println(" WARN : No primary key is defined on table " + newTable.getName()); 155 System.err.println(" Tables without primary key are not fully supported"); 156 error = false; 157 } else if (primaryKeys.length > 1) { 158 System.err.print(" WARN : Composite primary key "); 159 for (int ii = 0; ii < primaryKeys.length; ++ii) { 160 System.err.print(primaryKeys[ii].getFullName() + ", "); 161 } 162 System.err.println(); 163 System.err.println(" Tables with composite primary key are not fully supported"); 164 } else { 165 String normalKey; 166 Column pk = primaryKeys[0]; 167 String pkName = pk.getName(); 168 if (!pkName.equalsIgnoreCase(normalKey = newTable.getName() + "_id")) { 169 System.err.println(" WARN : primary key should be of form <TABLE>_ID"); 170 System.err.println(" found " + pkName + " expected " + normalKey); 171 } 172 if (!pk.isColumnNumeric()) { 173 System.err.println(" WARN : primary key should be a number "); 174 System.err.println(" found " + pk.getJavaType()); 175 } 176 } 177 return error; 178 } 179 180 public void checkDatabase() throws Exception { 181 System.out.println("Checking database tables"); 182 boolean error = false; 183 Table[] tables = db.getTables(); 184 for (int i = 0; i < tables.length; ++i) { 185 if (!CodeWriter.authorizeProcess(tables[i].getName(), "tables.include", "tables.exclude") 186 || !this.checkTable(tables[i])) 187 continue; 188 error = true; 189 } 190 if (error) { 191 System.err.println( 192 " Failed : at least one of the mandatory rule for sql2java is followed by your schema."); 193 System.err.println(" Please check the documentation for more information"); 194 System.exit(-1); 195 } 196 System.out.println(" Passed."); 197 } 198 199 public synchronized void process() throws Exception { 200 if ("true".equalsIgnoreCase(getProperty("check.database"))) { 201 this.checkDatabase(); 202 } 203 if ("true".equalsIgnoreCase(getProperty("check.only.database"))) { 204 return; 205 } 206 Properties vprops = new Properties(); 207 vprops.put(Velocity.RESOURCE_LOADER,"class,file"); 208 vprops.put(Velocity.FILE_RESOURCE_LOADER_PATH, Joiner.on(',').join(this.getLoadingPathExt())); 209 vprops.put("file.resource.loader.class", Sql2javaFileResourceLoader.class.getName()); 210 211 vprops.put("class.resource.loader.description", "Velocity Classpath Resource Loader"); 212 vprops.put("class.resource.loader.class",Sql2javaClasspathResourceLoader.class.getName()); 213 vprops.put("class.resource.loader.prefix", Joiner.on(',').join(this.getClassLoadingPath())); 214 215 vprops.put(Velocity.VM_LIBRARY, "/templates/velocity/includes/macros.include.vm"); 216 vprops.put(Velocity.SET_NULL_ALLOWED, "true"); 217 vprops.put(Velocity.INPUT_ENCODING,"UTF-8"); 218 vprops.put(Velocity.OUTPUT_ENCODING,"UTF-8"); 219 Velocity.init(vprops); 220 this.vc = new VelocityContext(); 221 this.vc.put("CodeWriter", (Object) new FieldMethodizer((Object) this)); 222 this.vc.put("codewriter", (Object) this); 223 this.vc.put("esc", new EscapeTool()); 224 this.vc.put("sorter", new SortTool()); 225 this.vc.put("pkg", (Object) basePackage); 226 this.vc.put("extensionPkg",getExtensionPkg()); 227 this.vc.put("isGeneral", Boolean.TRUE); 228 this.vc.put("pkgPath", (Object) basePackage.replace('.', '/')); 229 this.vc.put("strUtil",StringUtilities.getInstance()); 230 this.vc.put("fecha", new Date()); 231 this.current_vc = new VelocityContext((Context) this.vc); 232 generate("velocity.templates"); 233 // 如果定义了扩展模板的输出文件夹就用它替换destDir,用完后恢复 234 String destDirExt = getProperty("codewriter.destdir.extension",""); 235 String oldDest = destDir; 236 if(!destDirExt.isEmpty()){ 237 destDir = destDirExt; 238 } 239 try{ 240 // 生成外部扩展模板代码 241 generate("velocity.templates.extension"); 242 }finally{ 243 destDir = oldDest; 244 } 245 } 246 private void generate(String propName) throws Exception{ 247 if(null == getProperty(propName)) 248 return; 249 String[] schema_templates = this.getSchemaTemplates(propName); 250 for (int i = 0; i < schema_templates.length; ++i) { 251 this.writeComponent(schema_templates[i]); 252 } 253 if ("true".equalsIgnoreCase(getProperty("write.only.per.schema.templates"))) { 254 return; 255 } 256 Table[] tables = db.getTables(); 257 for (int i2 = 0; i2 < tables.length; ++i2) { 258 if (!CodeWriter.authorizeProcess(tables[i2].getName(), "tables.include", "tables.exclude")) 259 continue; 260 this.writeTable(tables[i2], propName); 261 } 262 } 263 private void writeTable(Table currentTable, String propName) throws Exception { 264 if (currentTable.getColumns().length == 0) { 265 return; 266 } 267 this.current_vc = new VelocityContext((Context) this.vc); 268 this.table = currentTable; 269 this.current_vc.put("table", (Object) currentTable); 270 String[] table_templates = this.getTableTemplates(propName); 271 for (int i = 0; i < table_templates.length; ++i) { 272 this.writeComponent(table_templates[i]); 273 } 274 } 275 276 private String clearHeadOfLoadPath(String templateName){ 277 checkNotNull(templateName); 278 List<String> loadPath = getLoadingPathExt(); 279 File template= new File(templateName); 280 for(String path:loadPath){ 281 File pfile = new File(path); 282 try { 283 if(template.getCanonicalPath().startsWith(pfile.getCanonicalPath())){ 284 String tmpl = template.getCanonicalPath().replace(pfile.getCanonicalPath(), "").replace('\\', '/'); 285 if(Velocity.resourceExists(tmpl)){ 286 return tmpl; 287 } 288 } 289 } catch (IOException e) { 290 throw new RuntimeException(e); 291 } 292 } 293 return templateName; 294 } 295 private static final String PREFIX_DESTDIR = "destdir."; 296 private static final String PREFIX_PACKAGE = "package."; 297 private String backupDestDir; 298 private String backupExtensionPkg; 299 /** 300 * 改变脚本支持上下文<br> 301 * 如果为模板定义了目标输出文件夹('destdir.${template name}'属性),则使用指定的位置作为{@link #destDir}<br> 302 * 如果为模板定义包名('package.${template name}'属性),则使用指定的值为引擎上下文的'extensionPkg'属性值 303 * @param templateName 模板文件名 304 */ 305 private void changeContextIfNeeded(String templateName){ 306 String name = templateName.substring(templateName.lastIndexOf("/") + 1); 307 backupDestDir = destDir; 308 backupExtensionPkg = (String) this.vc.get("extensionPkg"); 309 destDir = getProperty(PREFIX_DESTDIR + name, destDir); 310 this.vc.put("extensionPkg",getProperty(PREFIX_PACKAGE + name, backupExtensionPkg)); 311 312 } 313 /** 314 * 恢复脚本支持上下文<br> 315 * 恢复{@link #destDir}的值,<br> 316 * 恢复引擎上下文的'extensionPkg'属性值<br> 317 * 需要与{@link #changeDestDirIfNeeded}成对调用 318 */ 319 private void restoreContext(){ 320 destDir = backupDestDir; 321 this.vc.put("extensionPkg",backupExtensionPkg); 322 } 323 324 public void writeComponent(String templateName) throws Exception { 325 try { 326 templateName = clearHeadOfLoadPath(templateName); 327 System.out.println("Generating template " + templateName); 328 Velocity.getTemplate((String) templateName); 329 } catch (ResourceNotFoundException rnfe) { 330 System.err.println("Aborted writing component:" + templateName 331 + (this.table != null 332 ? new StringBuffer().append(" for table:").append(this.table.getName()).toString() 333 : "") 334 + " because Velocity could not find the resource."); 335 return; 336 } catch (ParseErrorException pee) { 337 System.err.println("Aborted writing component:" + templateName 338 + (this.table != null 339 ? new StringBuffer().append(" for table:").append(this.table.getName()).toString() 340 : "") 341 + " because there was a parse error in the resource.\n" + pee.getLocalizedMessage()); 342 return; 343 } catch (Exception e) { 344 System.err.println("Aborted writing component:" + templateName 345 + (this.table != null 346 ? new StringBuffer().append(" for table:").append(this.table.getName()).toString() 347 : "") 348 + " there was an error initializing the template.\n" + e.getLocalizedMessage()); 349 return; 350 } 351 StringWriter sw = new StringWriter(); 352 // reset 353 save_current_file = true; 354 this.current_vc.put("template", new File(templateName).getName()); 355 try { 356 changeContextIfNeeded(templateName); 357 Velocity.mergeTemplate((String) templateName, (String) "UTF-8", (Context) this.current_vc, (Writer) sw); 358 } finally { 359 restoreContext(); 360 } 361 if(save_current_file){ 362 System.out.println(" .... writing to " + this.current_fullfilename); 363 File file = new File(this.current_fullfilename); 364 new File(file.getParent()).mkdirs(); 365 PrintWriter writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(this.current_fullfilename),"UTF-8")); 366 // 换行符归一化:所有换行符替换为当前系统的换行符 367 String content = Pattern.compile("(\r\n|\n|\r)", Pattern.MULTILINE).matcher(sw.toString()).replaceAll(NEW_LINE); 368 writer.write(content); 369 writer.flush(); 370 writer.close(); 371 System.out.println(" " + this.current_filename + " done."); 372 }else 373 System.out.println(" " + this.current_filename + " skip."); 374 } 375 376 public void setCurrentFilename(String relpath_or_package, String fn) throws Exception { 377 this.current_filename = relpath_or_package.replace('.', File.separatorChar) + File.separatorChar + fn; 378 this.current_fullfilename = destDir + File.separatorChar + relpath_or_package.replace('.', File.separatorChar) 379 + File.separatorChar + fn; 380 UserCodeParser uc = new UserCodeParser(this.current_fullfilename); 381 this.current_vc.put("userCode", (Object) uc); 382 } 383 384 public void setCurrentJavaFilename(String relpath_or_package, String fn) throws Exception { 385 this.setCurrentFilename("java" + File.separatorChar + relpath_or_package, fn); 386 } 387 388 public void log(String logStr) { 389 System.out.println(" " + logStr); 390 } 391 392 public static String getClassPrefix() { 393 return classPrefix; 394 } 395 396 public Database getDb() { 397 return db; 398 } 399 400 public List<Table> getTables() { 401 Table[] tabs = db.getTables(); 402 ArrayList<Table> tables = new ArrayList<Table>(tabs.length); 403 for (int i = 0; i < tabs.length; ++i) { 404 tables.add(tabs[i]); 405 } 406 return tables; 407 } 408 409 public Table getTable(String tableName) { 410 return db.getTable(tableName); 411 } 412 413 public List<Table> getRelationTables() { 414 Table[] tabs = db.getTables(); 415 ArrayList<Table> tables = new ArrayList<Table>(tabs.length); 416 for (int i = 0; i < tabs.length; ++i) { 417 if (!tabs[i].isRelationTable()) 418 continue; 419 tables.add(tabs[i]); 420 } 421 return tables; 422 } 423 424 public String tableName() { 425 if (this.table == null) { 426 return ""; 427 } 428 return this.table.getName(); 429 } 430 431 public Table getTable() { 432 return this.table; 433 } 434 435 public static String getProperty(String key) { 436 String s = props.getProperty(key); 437 return s != null ? s.trim() : s; 438 } 439 440 public static String getProperty(String key, String defaultVal) { 441 String s = props.getProperty(key, defaultVal); 442 return s != null ? s.trim() : s; 443 } 444 public static String getPropertyRequired(String property) { 445 return checkNotNull(getProperty(property),"Missing property %s",property).trim(); 446 } 447 public static String[] getPropertyExploded(String key) { 448 return getPropertyExploded(key, ""); 449 } 450 451 public static List<String> getPropertyExplodedAsList(String key) { 452 return getPropertyExplodedAsList(key, ""); 453 } 454 455 public static List<String> getPropertyExplodedAsList(String mkey, String defaultValue) { 456 String v = getProperty(mkey); 457 if (v == null) { 458 v = defaultValue; 459 } 460 return CodeWriter.getExplodedStringAsList(v); 461 } 462 463 public static String[] getPropertyExploded(String mkey, String defaultValue) { 464 return getPropertyExplodedAsList(mkey,defaultValue).toArray(new String[0]); 465 } 466 467 public static List<String> getExplodedStringAsList(String value) { 468 if (value == null) { 469 return Collections.emptyList(); 470 } 471 ArrayList<String> al = new ArrayList<String>(); 472 StringTokenizer st = new StringTokenizer(value, " ,;\t"); 473 while (st.hasMoreTokens()) { 474 al.add(st.nextToken().trim()); 475 } 476 return al; 477 } 478 479 public static String[] getExplodedString(String value) { 480 return getExplodedStringAsList(value).toArray(new String[0]); 481 } 482 483 public static boolean getPropertyBoolean(String value){ 484 try{ 485 Pattern p = Pattern.compile("yes|true|on",Pattern.CASE_INSENSITIVE); 486 Matcher m = p.matcher(getProperty(value,"")); 487 return m.matches(); 488 }catch(Exception e){ 489 return false; 490 } 491 } 492 public List<String> getClassLoadingPath() { 493 return getPropertyExplodedAsList("velocity.templates.loadingpath", "/templates/velocity/includes,/templates/velocity"); 494 } 495 496 public List<String> getLoadingPathExt() { 497 return getPropertyExplodedAsList("velocity.templates.loadingpath.extension", ""); 498 } 499 public String[] getSchemaTemplates(String property) { 500 return this.getTemplates(property, true); 501 } 502 503 public String[] getTableTemplates(String property) { 504 return this.getTemplates(property, false); 505 } 506 507 public String[] getTemplates(String property, boolean perShema) { 508 Vector<String> files = new Vector<String>(); 509 // 支持多个模板路径 510 for(String path:getPropertyExploded(property)){ 511 this.recurseTemplate(files, path, perShema); 512 } 513 return files.toArray(new String[files.size()]); 514 } 515 516 public Vector<String> recurseTemplate(Vector<String> files, String folder, boolean perSchema) { 517 Iterable<String> dirEntries; 518 String schemaOrTable = perSchema ? "perschema" : "pertable"; 519 try { 520 String content = (String) RuntimeSingleton.getContent(folder).getData(); 521 String[] entires = content.split("\n"); 522 dirEntries = Iterables.filter(Lists.newArrayList(entires),new Predicate<String>() { 523 524 @Override 525 public boolean apply(String filename) { 526 if (filename.endsWith("/")) { 527 return true; 528 } 529 if (!filename.endsWith(".vm")) { 530 return false; 531 } 532 return CodeWriter.authorizeProcess(filename, "template.file.include", 533 "template.file.exclude"); 534 } 535 }); 536 } catch (ResourceNotFoundException e) { 537 return files; 538 } 539 540 for (Iterator<String> itor = dirEntries.iterator();itor.hasNext();) { 541 String file = itor.next(); 542 if (file.endsWith(".vm")) { 543 if (!CodeWriter.authorizeFile(folder, schemaOrTable)) 544 continue; 545 files.add(StringUtilities.combinePath(folder,file)); 546 continue; 547 } 548 this.recurseTemplate(files, StringUtilities.combinePath(folder,file), perSchema); 549 } 550 return files; 551 } 552 public static boolean authorizeProcess(String autorizePattern, String includeProperty, String excludeProperty) { 553 boolean accept = true; 554 String[] include = CodeWriter.getPropertyExploded(includeProperty); 555 String[] exclude = CodeWriter.getPropertyExploded(excludeProperty); 556 if (include.length != 0) { 557 if (CodeWriter.isInArray((String[]) include, (String) autorizePattern)) { 558 Velocity.getLog().info("Processing " + autorizePattern + " (specified in " + includeProperty + ")"); 559 return true; 560 } 561 accept = false; 562 } 563 if (exclude.length != 0 && CodeWriter.isInArray((String[]) exclude, (String) autorizePattern)) { 564 Velocity.getLog().info("Skipping " + autorizePattern + " (specified in " + excludeProperty + ")"); 565 return false; 566 } 567 return accept; 568 } 569 570 public static boolean folderContainsPattern(String folder, String[] patterns) { 571 if (patterns == null || folder == null) { 572 return false; 573 } 574 for (int i = 0; i < patterns.length; ++i) { 575 String pattern = "/" + patterns[i].toLowerCase() + "/"; 576 if (folder.toLowerCase().indexOf(pattern) == -1) 577 continue; 578 return true; 579 } 580 return false; 581 } 582 583 public static boolean authorizeFile(String folder, String schemaOrTable) { 584 if (folder.toLowerCase().indexOf(schemaOrTable.toLowerCase()) == -1) { 585 return false; 586 } 587 String[] include = CodeWriter.getPropertyExploded("template.folder.include"); 588 String[] exclude = CodeWriter.getPropertyExploded("template.folder.exclude"); 589 if (include.length != 0) { 590 if (CodeWriter.folderContainsPattern(folder, include)) { 591 return true; 592 } 593 return false; 594 } 595 if (exclude.length != 0) { 596 if (CodeWriter.folderContainsPattern(folder, exclude)) { 597 return false; 598 } 599 return true; 600 } 601 return true; 602 } 603 604 static { 605 MGR_CLASS = "Manager"; 606 classPrefix = ""; 607 } 608 609 public static String getBinaryClassName() { 610 return binaryClassName; 611 } 612 613 public static String getBitStateClassName() { 614 return bitStateClassName; 615 } 616 public static String getBitStateClassWrapName() { 617 return Primitives.wrap(bitStateClass).getSimpleName(); 618 } 619 public Class<?> getBitStateClass() { 620 return bitStateClass; 621 } 622 public static int getBitStateClassSize() { 623 return bitStateClassSize; 624 } 625 private static Class<?> bitStateClassOf(String className) { 626 switch(className){ 627 case "byte": 628 return byte.class; 629 case "short": 630 return short.class; 631 case "int": 632 return int.class; 633 case "long": 634 return long.class; 635 } 636 throw new IllegalArgumentException("INVALID class name for state type [" + className + "]"); 637 } 638 private static int bitSizeOf(Class<?> clazz) { 639 try { 640 // access field such as Integer.SIZE 641 Field size = Primitives.wrap(clazz).getField("SIZE"); 642 return size.getInt(null); 643 } catch (Exception e) { 644 Throwables.throwIfUnchecked(e); 645 throw new RuntimeException(e); 646 } 647 } 648 649 private static String constSuffixOf(String className) { 650 if("byte".equals(className)){ 651 return ""; 652 } 653 if("shot".equals(className)){ 654 return ""; 655 } 656 if("int".equals(className)){ 657 return ""; 658 } 659 if("long".equals(className)){ 660 return "L"; 661 } 662 663 throw new IllegalArgumentException("INVALID class name for state type [" + className + "]"); 664 } 665 666 public static String getBitStateConstSuffix() { 667 return bitStateConstSuffix; 668 } 669 public static int getBitStateMask() { 670 return (1<<Integer.numberOfTrailingZeros(bitStateClassSize))-1; 671 } 672 673 public static String getBitStateMaskHex() { 674 return "0x"+Integer.toHexString(getBitStateMask()); 675 } 676 public static int getBitStateClassShift() { 677 return Integer.numberOfTrailingZeros(bitStateClassSize); 678 } 679 public static boolean binaryIsByteBuffer() { 680 return !DEFAULT_BINARY_TYPE.equals(binaryClassName); 681 } 682 683 public static String getExtensionPkg(){ 684 String extPkg = getProperty("codewriter.package.extension",""); 685 return extPkg.isEmpty()?basePackage : extPkg; 686 } 687 688 public void setSaveCurrentFile(boolean save_current_fullfile) { 689 this.save_current_file = save_current_fullfile; 690 } 691 692 private static Class<?> loadClass(String classname,ClassLoader classLoader) throws ClassNotFoundException{ 693 return null == classLoader? 694 Class.forName(classname) : Class.forName(classname,true,classLoader); 695 } 696 /** 697 * 读取 'extension.tools.libdirs','extension.tools.classpath'分别对应{@code libdirs,classpath}参数<br> 698 * 如果上述property都没有定义则抛出异常 699 * @param classname 700 * @return 701 * @throws ClassNotFoundException 702 * @see {@link #loadExtensionClass(String, boolean, String[], String[])} 703 */ 704 public static Class<?> loadExtensionClass(String classname) throws ClassNotFoundException{ 705 return loadClass(classname,getExtensionClassLoader()); 706 } 707 private static synchronized URLClassLoader getExtensionClassLoader(){ 708 if(null ==extensionClassLoader){ 709 if( 0 == extLibdirs.length && 0 == extClasspath.length) 710 throw new IllegalStateException("property 'extension.tools.libdirs' and 'extension.tools.classpath' is all undefined"); 711 extensionClassLoader = ClassLoaderUtils.makeURLClassLoader(CodeWriter.class.getClassLoader(),true, extLibdirs, extClasspath); 712 } 713 return extensionClassLoader; 714 } 715 /** 716 * 使用当前类的class loader加载工具对象 717 * @param classname 718 * @return 719 * @throws ClassNotFoundException 720 * @throws InstantiationException 721 * @throws IllegalAccessException 722 */ 723 public Object loadTool(String classname) throws ClassNotFoundException, InstantiationException, IllegalAccessException{ 724 Class<?> clazz = loadClass(classname,null); 725 return clazz.newInstance(); 726 } 727 728 private static boolean isInArray(String[] ar, String code) { 729 if (ar == null) { 730 return false; 731 } 732 for (int i = 0; i < ar.length; ++i) { 733 if (!code.equalsIgnoreCase(ar[i])) 734 continue; 735 return true; 736 } 737 return false; 738 } 739 740 /** 741 * 返回类的源文件位置 742 * @param baseDir 源文件夹 743 * @param clazz 744 * @return 745 */ 746 public static String getSourceFile(String baseDir,Class<?> clazz){ 747 if(null == baseDir || null == clazz )return null; 748 return baseDir + File.separatorChar + clazz.getName().replace('.', File.separatorChar) + ".java"; 749 } 750 public static Boolean getFillNull(){ 751 return fillNull.get(); 752 } 753 public static void setFillNull(Boolean fill){ 754 fillNull.set(fill); 755 } 756 757}