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