1 /** 2 * Redistribution and use of this software and associated documentation 3 * ("Software"), with or without modification, are permitted provided 4 * that the following conditions are met: 5 * 6 * 1. Redistributions of source code must retain copyright 7 * statements and notices. Redistributions must also contain a 8 * copy of this document. 9 * 10 * 2. Redistributions in binary form must reproduce the 11 * above copyright notice, this list of conditions and the 12 * following disclaimer in the documentation and/or other 13 * materials provided with the distribution. 14 * 15 * 3. The name "Exolab" must not be used to endorse or promote 16 * products derived from this Software without prior written 17 * permission of Intalio, Inc. For written permission, 18 * please contact info@codehaus.org. 19 * 20 * 4. Products derived from this Software may not be called "Exolab" 21 * nor may "Exolab" appear in their names without prior written 22 * permission of Intalio, Inc. Exolab is a registered 23 * trademark of Intalio, Inc. 24 * 25 * 5. Due credit should be given to the Exolab Project 26 * (http://www.codehaus.org/). 27 * 28 * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS 29 * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT 30 * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 31 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 32 * INTALIO, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 33 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 34 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 35 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 37 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 38 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 39 * OF THE POSSIBILITY OF SUCH DAMAGE. 40 * 41 * Copyright 2001-2002 (C) Intalio, Inc. All Rights Reserved. 42 * 43 * $Id$ 44 */ 45 package org.codehaus.modello.plugin.java.javasource; 46 47 /* 48 * Copyright (c) 2004, Codehaus.org 49 * 50 * Permission is hereby granted, free of charge, to any person obtaining a copy of 51 * this software and associated documentation files (the "Software"), to deal in 52 * the Software without restriction, including without limitation the rights to 53 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 54 * of the Software, and to permit persons to whom the Software is furnished to do 55 * so, subject to the following conditions: 56 * 57 * The above copyright notice and this permission notice shall be included in all 58 * copies or substantial portions of the Software. 59 * 60 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 61 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 62 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 63 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 64 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 65 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 66 * SOFTWARE. 67 */ 68 69 import java.io.File; 70 import java.nio.file.Files; 71 import java.util.ArrayList; 72 import java.util.Collections; 73 import java.util.Enumeration; 74 import java.util.List; 75 76 /** 77 * This class represents the basic Java "structure" for a Java 78 * source file. This is the base class for JClass and JInterface. 79 * 80 * This is a useful utility when creating in memory source code. 81 * The code in this package was modelled after the Java Reflection API 82 * as much as possible to reduce the learning curve. 83 * 84 * @author <a href="mailto:skopp@riege.de">Martin Skopp</a> 85 * @author <a href="mailto:kvisco@intalio.com">Keith Visco</a> 86 * @version $Revision$ $Date$ 87 */ 88 public abstract class JStructure extends JType { 89 90 /** 91 * The Id for Source control systems 92 * I needed to separate this line to prevent CVS from 93 * expanding it here! ;-) 94 */ 95 static final String DEFAULT_HEADER = "$" + "Id$"; 96 97 /** 98 * The source control version for listed in the JavaDoc 99 * I needed to separate this line to prevent CVS from 100 * expanding it here! ;-) 101 */ 102 static final String version = "$" + "Revision$ $" + "Date$"; 103 104 /** 105 * The source header 106 */ 107 private JComment header = null; 108 109 /** 110 * List of imported classes and packages 111 */ 112 private List<String> imports = null; 113 114 /** 115 * The set of interfaces implemented/extended by this JStructure 116 */ 117 private List<String> interfaces = null; 118 119 /** 120 * The Javadoc for this JStructure 121 */ 122 private JDocComment jdc = null; 123 124 /** 125 * The JModifiers for this JStructure, which allows us to 126 * change the resulting qualifiers 127 */ 128 private JModifiers modifiers = null; 129 130 /** 131 * The package to which this JStructure belongs 132 */ 133 private final String packageName; 134 135 private JAnnotations annotations = null; 136 137 /** 138 * Creates a new JStructure with the given name. 139 * 140 * @param name the name of the JStructure. 141 * @throws java.lang.IllegalArgumentException when the given name 142 * is not a valid Class name. 143 */ 144 protected JStructure(String name) throws IllegalArgumentException { 145 super(name); 146 147 // -- verify name is a valid java class name 148 if (!isValidClassName(name)) { 149 String lname = getLocalName(); 150 String err = "'" + lname + "' is "; 151 if (JNaming.isKeyword(lname)) err += "a reserved word and may not be used as " + " a class name."; 152 else err += "not a valid Java identifier."; 153 154 throw new IllegalArgumentException(err); 155 } 156 this.packageName = getPackageFromClassName(name); 157 imports = new ArrayList<String>(); 158 interfaces = new ArrayList<String>(); 159 jdc = new JDocComment(); 160 modifiers = new JModifiers(); 161 // -- initialize default Java doc 162 jdc.addDescriptor(JDocDescriptor.createVersionDesc(version)); 163 } // -- JStructure 164 165 /** 166 * Adds the given JField to this JStructure. 167 * <p> 168 * This method is implemented by subclasses and 169 * should only accept the proper fields for the 170 * subclass otherwise an IllegalArgumentException 171 * will be thrown. For example a JInterface will 172 * only accept static fields. 173 * <p> 174 * @param jField, the JField to add 175 * @exception java.lang.IllegalArgumentException when the given 176 * JField has a name of an existing JField 177 */ 178 public abstract void addField(JField jField) throws IllegalArgumentException; 179 180 /** 181 * Adds the given JMember to this JStructure. 182 * <p> 183 * This method is implemented by subclasses and 184 * should only accept the proper types for the 185 * subclass otherwise an IllegalArgumentException 186 * will be thrown. 187 * <p> 188 * @param jMember the JMember to add to this JStructure. 189 * @throws java.lang.IllegalArgumentException when the given 190 * JMember has the same name of an existing JField 191 * or JMethod respectively. 192 */ 193 public abstract void addMember(JMember jMember) throws IllegalArgumentException; 194 195 /** 196 * Adds the given import to this JStructure 197 * 198 * @param className the className of the class to import. 199 */ 200 public void addImport(String className) { 201 if (className == null) return; 202 if (className.length() == 0) return; 203 204 // -- getPackageName 205 String pkgName = getPackageFromClassName(className); 206 207 if (pkgName != null) { 208 if (pkgName.equals(this.packageName)) return; 209 210 // -- XXX: Fix needed for this... 211 // -- This may cause issues if the current package 212 // -- defines any classes that have the same name 213 // -- name as the java.lang package. 214 if ("java.lang".equals(pkgName)) return; 215 216 // -- for readabilty keep import list sorted, and make sure 217 // -- we do not include more than one of the same import 218 for (int i = 0; i < imports.size(); i++) { 219 String imp = imports.get(i); 220 if (imp.equals(className)) return; 221 if (imp.compareTo(className) > 0) { 222 imports.add(i, className); 223 return; 224 } 225 } 226 imports.add(className); 227 } 228 } // -- addImport 229 230 /** 231 * Adds the given interface to the list of interfaces this 232 * JStructure inherits method declarations from, and either 233 * implements (JClass) or extends (JInterface). 234 * 235 * @param interfaceName the name of the interface to "inherit" 236 * method declarations from. 237 */ 238 public void addInterface(String interfaceName) { 239 if (!interfaces.contains(interfaceName)) interfaces.add(interfaceName); 240 } // -- addInterface 241 242 /** 243 * Adds the given interface to the list of interfaces this 244 * JStructure inherits method declarations from, and either 245 * implements (JClass) or extends (JInterface). 246 * 247 * @param jInterface the JInterface to inherit from. 248 */ 249 public void addInterface(JInterface jInterface) { 250 if (jInterface == null) return; 251 String interfaceName = jInterface.getName(); 252 if (!interfaces.contains(interfaceName)) { 253 interfaces.add(interfaceName); 254 } 255 } // -- addInterface 256 257 /** 258 * Adds the given JMethodSignature to this JClass 259 * 260 * @param jMethodSig the JMethodSignature to add. 261 * @throws java.lang.IllegalArgumentException when the given 262 * JMethodSignature conflicts with an existing 263 * method signature. 264 */ 265 /* 266 public void addMethod(JMethodSignature jMethodSig) 267 throws IllegalArgumentException 268 { 269 if (jMethodSig == null) { 270 String err = "The JMethodSignature cannot be null."; 271 throw new IllegalArgumentException(err); 272 } 273 274 //-- XXXX: check method name and signatures *add later* 275 276 //-- keep method list sorted for esthetics when printing 277 //-- START SORT :-) 278 boolean added = false; 279 short modifierVal = 0; 280 JModifiers modifiers = jMethodSig.getModifiers(); 281 for (int i = 0; i < methods.size(); i++) { 282 JMethodSignature tmp = (JMethodSignature) methods.elementAt(i); 283 //-- first compare modifiers 284 if (tmp.getModifiers().isProtected()) { 285 if (!modifiers.isProtected()) { 286 methods.insertElementAt(jMethodSig, i); 287 added = true; 288 break; 289 } 290 } 291 //-- compare names 292 if (jMethodSig.getName().compareTo(tmp.getName()) < 0) { 293 methods.insertElementAt(jMethodSig, i); 294 added = true; 295 break; 296 } 297 } 298 //-- END SORT 299 if (!added) methods.addElement(jMethodSig); 300 301 //-- check parameter packages to make sure we have them 302 //-- in our import list 303 304 String[] pkgNames = jMethodSig.getParameterClassNames(); 305 for (int i = 0; i < pkgNames.length; i++) { 306 addImport(pkgNames[i]); 307 } 308 //-- check return type to make sure it's included in the 309 //-- import list 310 JType jType = jMethodSig.getReturnType(); 311 if (jType != null) { 312 while (jType.isArray()) 313 jType = jType.getComponentType(); 314 315 if (!jType.isPrimitive()) 316 addImport(jType.getName()); 317 } 318 //-- check exceptions 319 JClass[] exceptions = jMethodSig.getExceptions(); 320 for (int i = 0; i < exceptions.length; i++) { 321 addImport(exceptions[i].getName()); 322 } 323 } //-- addMethod 324 */ 325 /** 326 * Returns the field with the given name, or null if no field 327 * was found with the given name. 328 * 329 * @param name the name of the field to return. 330 * @return the field with the given name, or null if no field 331 * was found with the given name. 332 */ 333 public abstract JField getField(String name); 334 335 /** 336 * Returns an array of all the JFields of this JStructure 337 * 338 * @return an array of all the JFields of this JStructure 339 */ 340 public abstract JField[] getFields(); 341 342 /** 343 * Returns the name of the file that this JStructure would be 344 * printed to, given a call to #print. 345 * 346 * @param destDir the destination directory. This may be null. 347 * @return the name of the file that this JInterface would be 348 * printed as, given a call to #print. 349 */ 350 public String getFilename(String destDir) { 351 352 String filename = getLocalName() + ".java"; 353 354 // -- Convert Java package to path string 355 String javaPackagePath = ""; 356 if ((packageName != null) && (packageName.length() > 0)) { 357 javaPackagePath = packageName.replace('.', File.separatorChar); 358 } 359 360 // -- Create fully qualified path (including 'destDir') to file 361 File pathFile; 362 if (destDir == null) pathFile = new File(javaPackagePath); 363 else pathFile = new File(destDir, javaPackagePath); 364 if (!pathFile.exists()) { 365 pathFile.mkdirs(); 366 } 367 368 // -- Prefix filename with path 369 if (pathFile.toString().length() > 0) filename = pathFile.toString() + File.separator + filename; 370 371 return filename; 372 } // -- getFilename 373 374 /** 375 * Returns the JComment header to display at the top of the source file 376 * for this JStructure, or null if no header was set. 377 * 378 * @return the JComment header or null if none exists. 379 */ 380 public JComment getHeader() { 381 return this.header; 382 } // -- getHeader 383 384 /** 385 * Returns an Enumeration of imported package and 386 * class names for this JStructure. 387 * 388 * @return the Enumeration of imports. May be empty. 389 */ 390 public Enumeration<String> getImports() { 391 return Collections.enumeration(imports); 392 } // -- getImports 393 394 /** 395 * Returns an Enumeration of interface names that this 396 * JStructure inherits from. 397 * 398 * @return the Enumeration of interface names for this 399 * JStructure. May be empty. 400 */ 401 public Enumeration<String> getInterfaces() { 402 return Collections.enumeration(interfaces); 403 } // -- getInterfaces 404 405 /** 406 * Returns the Java Doc comment for this JStructure 407 * 408 * @return the JDocComment for this JStructure 409 */ 410 public JDocComment getJDocComment() { 411 return jdc; 412 } // -- getJDocComment 413 414 /** 415 * Returns an array of all the JMethodSignatures of this JInterface. 416 * 417 * @return an array of all the JMethodSignatures of this JInterface. 418 */ 419 /* 420 public JMethodSignature[] getMethods() { 421 JMethodSignature[] marray = new JMethodSignature[methods.size()]; 422 methods.copyInto(marray); 423 return marray; 424 } //-- getMethods 425 */ 426 427 /** 428 * Returns the JMethodSignature with the given name, 429 * and occuring at or after the given starting index. 430 * 431 * @param name the name of the JMethodSignature to return. 432 * @param startIndex the starting index to begin searching 433 * from. 434 * @return the JMethodSignature, or null if not found. 435 */ 436 /* 437 public JMethodSignature getMethod(String name, int startIndex) { 438 for (int i = startIndex; i < methods.size(); i++) { 439 JMethodSignature jMethod = (JMethodSignature)methods.elementAt(i); 440 if (jMethod.getName().equals(name)) return jMethod; 441 } 442 return null; 443 } //-- getMethod 444 */ 445 446 /** 447 * Returns the JMethodSignature at the given index. 448 * 449 * @param index the index of the JMethodSignature to return. 450 * @return the JMethodSignature at the given index. 451 */ 452 /* 453 public JMethodSignature getMethod(int index) { 454 return (JMethodSignature)methods.elementAt(index); 455 } //-- getMethod 456 */ 457 458 /** 459 * Returns the JModifiers which allows the qualifiers to be changed. 460 * 461 * @return the JModifiers for this JStructure. 462 */ 463 public JModifiers getModifiers() { 464 return modifiers; 465 } // -- getModifiers 466 467 /** 468 * Returns the name of the package that this JStructure is a member 469 * of. 470 * 471 * @return the name of the package that this JStructure is a member 472 * of, or null if there is no current package name defined. 473 */ 474 public String getPackageName() { 475 return this.packageName; 476 } // -- getPackageName 477 478 /** 479 * Returns the name of the interface. 480 * 481 * @param stripPackage a boolean that when true indicates that only 482 * the local name (no package) should be returned. 483 * @return the name of the class. 484 */ 485 public String getName(boolean stripPackage) { 486 String name = super.getName(); 487 if (stripPackage) { 488 int period = name.lastIndexOf("."); 489 if (period > 0) name = name.substring(period + 1); 490 } 491 return name; 492 } // -- getName 493 494 /** 495 * Returns true if the given classname exists in the imports 496 * of this JStructure 497 * 498 * @param classname the class name to check for 499 * @return true if the given classname exists in the imports list 500 */ 501 public boolean hasImport(String classname) { 502 return imports.contains(classname); 503 } // -- hasImport 504 505 public boolean removeImport(String className) { 506 boolean result = false; 507 if (className == null) return result; 508 if (className.length() == 0) return result; 509 510 return imports.remove(className); 511 } // -- removeImport 512 513 public boolean isAbstract() { 514 return modifiers.isAbstract(); 515 } 516 517 public static boolean isValidClassName(String name) { 518 519 if (name == null) return false; 520 521 // -- ignore package information, for now 522 int period = name.lastIndexOf("."); 523 if (period > 0) name = name.substring(period + 1); 524 525 return JNaming.isValidJavaIdentifier(name); 526 } // -- isValidClassName 527 528 /** 529 * Prints the source code for this JStructure in the current 530 * working directory. Sub-directories will be created if necessary 531 * for the package. 532 */ 533 public void print() { 534 print((String) null, (String) null); 535 } // -- printSrouce 536 537 /** 538 * Prints the source code for this JStructure to the destination 539 * directory. Sub-directories will be created if necessary for the 540 * package. 541 * 542 * @param destDir the destination directory 543 * @param lineSeparator the line separator to use at the end of each line. 544 * If null, then the default line separator for the runtime platform will 545 * be used. 546 */ 547 public void print(String destDir, String lineSeparator) { 548 549 // String name = getLocalName(); 550 551 // -- open output file 552 String filename = getFilename(destDir); 553 554 File file = new File(filename); 555 JSourceWriter jsw = null; 556 try { 557 jsw = new JSourceWriter(Files.newBufferedWriter(file.toPath())); 558 } catch (java.io.IOException ioe) { 559 System.out.println("unable to create class file: " + filename); 560 return; 561 } 562 if (lineSeparator == null) { 563 lineSeparator = System.getProperty("line.separator"); 564 } 565 jsw.setLineSeparator(lineSeparator); 566 print(jsw); 567 jsw.close(); 568 } // -- print 569 570 /** 571 * Prints the source code for this JStructure to the given 572 * JSourceWriter. 573 * 574 * @param jsw the JSourceWriter to print to. 575 */ 576 public abstract void print(JSourceWriter jsw); 577 578 /** 579 * A utility method that prints the header to the given 580 * JSourceWriter 581 * 582 * @param jsw the JSourceWriter to print to. 583 */ 584 public void printHeader(JSourceWriter jsw) { 585 586 if (jsw == null) { 587 throw new IllegalArgumentException("argument 'jsw' should not be null."); 588 } 589 590 // -- write class header 591 JComment header = getHeader(); 592 if (header != null) header.print(jsw); 593 else { 594 jsw.writeln("/*"); 595 jsw.writeln(" * " + DEFAULT_HEADER); 596 jsw.writeln(" */"); 597 } 598 jsw.writeln(); 599 jsw.flush(); 600 } // -- printHeader 601 602 /** 603 * A utility method that prints the imports to the given 604 * JSourceWriter 605 * 606 * @param jsw the JSourceWriter to print to. 607 */ 608 public void printImportDeclarations(JSourceWriter jsw) { 609 610 if (jsw == null) { 611 throw new IllegalArgumentException("argument 'jsw' should not be null."); 612 } 613 614 // -- print imports 615 if (imports.size() > 0) { 616 jsw.writeln(" //---------------------------------/"); 617 jsw.writeln(" //- Imported classes and packages -/"); 618 jsw.writeln("//---------------------------------/"); 619 jsw.writeln(); 620 for (String imp : imports) { 621 jsw.write("import "); 622 jsw.write(imp); 623 jsw.writeln(';'); 624 } 625 jsw.writeln(); 626 jsw.flush(); 627 } 628 } // -- printImportDeclarations 629 630 /** 631 * A utility method that prints the packageDeclaration to 632 * the given JSourceWriter 633 * 634 * @param jsw the JSourceWriter to print to. 635 */ 636 public void printPackageDeclaration(JSourceWriter jsw) { 637 638 if (jsw == null) { 639 throw new IllegalArgumentException("argument 'jsw' should not be null."); 640 } 641 642 // -- print package name 643 if ((packageName != null) && (packageName.length() > 0)) { 644 jsw.write("package "); 645 jsw.write(packageName); 646 jsw.writeln(';'); 647 jsw.writeln(); 648 } 649 jsw.flush(); 650 } // -- printPackageDeclaration 651 652 /** 653 * Prints the source code for this JStructure to the given 654 * JSourceWriter. 655 * 656 * @param jsw the JSourceWriter to print to. 657 * 658 * public abstract void print(JSourceWriter jsw); 659 * 660 * 661 * StringBuilder buffer = new StringBuilder(); 662 * 663 * 664 * printHeader(); 665 * printPackageDeclaration(); 666 * printImportDeclarations(); 667 * 668 * //------------/ 669 * //- Java Doc -/ 670 * //------------/ 671 * 672 * jdc.print(jsw); 673 * 674 * //-- print class information 675 * //-- we need to add some JavaDoc API adding comments 676 * 677 * buffer.setLength(0); 678 * 679 * if (modifiers.isPrivate()) { 680 * buffer.append("private "); 681 * } 682 * else if (modifiers.isPublic()) { 683 * buffer.append("public "); 684 * } 685 * 686 * if (modifiers.isAbstract()) { 687 * buffer.append("abstract "); 688 * } 689 * 690 * buffer.append("interface "); 691 * buffer.append(getLocalName()); 692 * buffer.append(' '); 693 * if (interfaces.size() > 0) { 694 * boolean endl = false; 695 * if (interfaces.size() > 1) { 696 * jsw.writeln(buffer.toString()); 697 * buffer.setLength(0); 698 * endl = true; 699 * } 700 * buffer.append("extends "); 701 * for (int i = 0; i < interfaces.size(); i++) { 702 * if (i > 0) buffer.append(", "); 703 * buffer.append(interfaces.elementAt(i)); 704 * } 705 * if (endl) { 706 * jsw.writeln(buffer.toString()); 707 * buffer.setLength(0); 708 * } 709 * else buffer.append(' '); 710 * } 711 * 712 * buffer.append('{'); 713 * jsw.writeln(buffer.toString()); 714 * buffer.setLength(0); 715 * jsw.writeln(); 716 * 717 * jsw.indent(); 718 * 719 * //-- print method signatures 720 * 721 * if (methods.size() > 0) { 722 * jsw.writeln(); 723 * jsw.writeln(" //-----------/"); 724 * jsw.writeln(" //- Methods -/"); 725 * jsw.writeln("//-----------/"); 726 * jsw.writeln(); 727 * } 728 * 729 * for (int i = 0; i < methods.size(); i++) { 730 * JMethodSignature signature = (JMethodSignature) methods.elementAt(i); 731 * signature.print(jsw); 732 * jsw.writeln(';'); 733 * } 734 * 735 * jsw.unindent(); 736 * jsw.writeln('}'); 737 * jsw.flush(); 738 * jsw.close(); 739 * } //-- printSource 740 */ 741 742 /** 743 * Sets the header comment for this JStructure 744 * 745 * @param comment the comment to display at the top of the source file 746 * when printed 747 */ 748 public void setHeader(JComment comment) { 749 this.header = comment; 750 } // -- setHeader 751 752 // ---------------------/ 753 // - Protected Methods -/ 754 // ---------------------/ 755 756 protected int getInterfaceCount() { 757 return interfaces.size(); 758 } 759 760 /** 761 * Prints the given source string to the JSourceWriter using the given prefix at 762 * the beginning of each new line. 763 * 764 * @param prefix the prefix for each new line. 765 * @param source the source code to print 766 * @param jsw the JSourceWriter to print to. 767 */ 768 protected static void printlnWithPrefix(String prefix, String source, JSourceWriter jsw) { 769 jsw.write(prefix); 770 if (source == null) return; 771 772 char[] chars = source.toCharArray(); 773 int lastIdx = 0; 774 for (int i = 0; i < chars.length; i++) { 775 char ch = chars[i]; 776 if (ch == '\n') { 777 // -- free buffer 778 jsw.write(chars, lastIdx, (i - lastIdx) + 1); 779 lastIdx = i + 1; 780 if (i < chars.length) { 781 jsw.write(prefix); 782 } 783 } 784 } 785 // -- free buffer 786 if (lastIdx < chars.length) { 787 jsw.write(chars, lastIdx, chars.length - lastIdx); 788 } 789 jsw.writeln(); 790 } // -- printlnWithPrefix 791 792 /** 793 * Returns the package name from the given class name 794 * 795 * @param className the className 796 * @return the package of the class, otherwise {@code null} 797 */ 798 protected static String getPackageFromClassName(String className) { 799 int idx = -1; 800 if ((idx = className.lastIndexOf('.')) > 0) { 801 return className.substring(0, idx); 802 } 803 return null; 804 } // -- getPackageFromClassName 805 806 /** 807 * @return the annotations 808 */ 809 public JAnnotations getAnnotations() { 810 return annotations; 811 } 812 813 /** 814 * @param annotation the annotation to append 815 */ 816 public void appendAnnotation(String annotation) { 817 if (annotations == null) { 818 annotations = new JAnnotations(); 819 } 820 annotations.appendAnnotation(annotation); 821 } 822 823 /** 824 * @param annotations the annotations to set 825 */ 826 public void setAnnotations(JAnnotations annotations) { 827 this.annotations = annotations; 828 } 829 } // -- JStructure