All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.exolab.javasource.JStructure Maven / Gradle / Ivy

/**
 * Redistribution and use of this software and associated documentation
 * ("Software"), with or without modification, are permitted provided
 * that the following conditions are met:
 *
 * 1. Redistributions of source code must retain copyright
 *    statements and notices.  Redistributions must also contain a
 *    copy of this document.
 *
 * 2. Redistributions in binary form must reproduce the
 *    above copyright notice, this list of conditions and the
 *    following disclaimer in the documentation and/or other
 *    materials provided with the distribution.
 *
 * 3. The name "Exolab" must not be used to endorse or promote
 *    products derived from this Software without prior written
 *    permission of Intalio, Inc.  For written permission,
 *    please contact [email protected].
 *
 * 4. Products derived from this Software may not be called "Exolab"
 *    nor may "Exolab" appear in their names without prior written
 *    permission of Intalio, Inc. Exolab is a registered
 *    trademark of Intalio, Inc.
 *
 * 5. Due credit should be given to the Exolab Project
 *    (http://www.exolab.org/).
 *
 * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
 * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
 * INTALIO, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Copyright 2001-2002 (C) Intalio, Inc. All Rights Reserved.
 *
 * $Id: JStructure.java 6623 2006-12-28 23:13:20Z wguttmn $
 */
package org.exolab.javasource;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Vector;

/**
 * This class represents the basic Java "structure" for a Java source file. This
 * is the base class for JClass and JInterface.
 * 

* This is a useful utility when creating in memory source code. The code in * this package was modelled after the Java Reflection API as much as possible * to reduce the learning curve. * * @author Martin Skopp * @author Keith Visco * @version $Revision: 6623 $ $Date: 2005-12-13 14:58:48 -0700 (Tue, 13 Dec 2005) $ */ public abstract class JStructure extends JType implements JAnnotatedElement { /** * The Id for Source control systems. *

* Note: I needed to break the String into two parts to prevent CVS from * expanding it here! ;-) */ private static final String DEFAULT_HEADER = "$" + "Id$"; /** * The source control version for listed in the JavaDoc *

* Note: I needed to break the String into parts to prevent CVS from * expanding it here! ;-) */ private static final String DEFAULT_VERSION = "$" + "Revision$ $" + "Date$"; /** A standard complaint for a bad parameter. */ private static final String JSW_SHOULD_NOT_BE_NULL = "argument 'jsw' should not be null."; /** * The source header. */ private JComment _header = null; /** * List of imported classes and packages. */ private Vector _imports = null; /** * The set of interfaces implemented/extended by this JStructure. */ private Vector _interfaces = null; /** * The Javadoc for this JStructure. */ private JDocComment _jdc = null; /** * The JModifiers for this JStructure, which allows us to change the * resulting qualifiers. */ private JModifiers _modifiers = null; /** * The package to which this JStructure belongs. */ private String _packageName = null; /** * Implementation of JAnnoatedElement to delagate to. */ private JAnnotatedElementHelper _annotatedElement = null; /** * Creates a new JStructure with the given name. * * @param name the name of the JStructure. */ protected JStructure(final String name) { super(name); //-- verify name is a valid java class name if (!isValidClassName(name)) { String lname = getLocalName(); String err = "'" + lname + "' is "; if (JNaming.isKeyword(lname)) { err += "a reserved word and may not be used as a class name."; } else { err += "not a valid Java identifier."; } throw new IllegalArgumentException(err); } this._packageName = JNaming.getPackageFromClassName(name); _imports = new Vector(); _interfaces = new Vector(); _jdc = new JDocComment(); _modifiers = new JModifiers(); _annotatedElement = new JAnnotatedElementHelper(); //-- initialize default Java doc _jdc.addDescriptor(JDocDescriptor.createVersionDesc(DEFAULT_VERSION)); } //-- JStructure /** * Adds the given JField to this JStructure. *

* This method is implemented by subclasses and should only accept the * proper fields for the subclass otherwise an IllegalArgumentException will * be thrown. For example a JInterface will only accept static fields. * * @param jField the JField to add */ public abstract void addField(JField jField); /** * Adds the given JMember to this JStructure. *

* This method is implemented by subclasses and should only accept the * proper types for the subclass otherwise an IllegalArgumentException will * be thrown. * * @param jMember the JMember to add to this JStructure. */ public abstract void addMember(JMember jMember); /** * Adds the given import to this JStructure. Note: You cannot import * from the "default package," so imports with no package are ignored. * * @param className name of the class to import. */ public void addImport(final String className) { if (className == null || className.length() == 0) { return; } //-- getPackageName String pkgName = JNaming.getPackageFromClassName(className); if (pkgName != null) { if (pkgName.equals(this._packageName) || pkgName.equals("java.lang")) { return; } //-- for readabilty keep import list sorted, and make sure //-- we do not include more than one of the same import for (int i = 0; i < _imports.size(); i++) { String imp = (String) _imports.elementAt(i); if (imp.equals(className)) { return; } if (imp.compareTo(className) > 0) { _imports.insertElementAt(className, i); return; } } _imports.addElement(className); } } //-- addImport /** * Adds appropriate import for this JAnnotation. * * @param annotation a JAnnotation for which we want to add an import to * this JStructure */ protected final void addImport(final JAnnotation annotation) { addImport(annotation.getAnnotationType().getName()); } /** * Adds appropriate imports for each JAnnotation in the given Array. * * @param annotations an Array of JAnnotation; we want to add an import to * this JStructure for each JAnnotation in the Array */ protected final void addImport(final JAnnotation[] annotations) { for (int i = 0; i < annotations.length; i++) { addImport(annotations[i].getAnnotationType().getName()); } } /** * Adds the given interface to the list of interfaces this JStructure * inherits method declarations from, and either implements (JClass) or * extends (JInterface). * * @param interfaceName the name of the interface to "inherit" method * declarations from. */ public final void addInterface(final String interfaceName) { if (!_interfaces.contains(interfaceName)) { _interfaces.addElement(interfaceName); } } //-- addInterface /** * Adds the given interface to the list of interfaces this JStructure * inherits method declarations from, and either implements (JClass) or * extends (JInterface). * * @param jInterface the JInterface to inherit from. */ public final void addInterface(final JInterface jInterface) { if (jInterface == null) { return; } String interfaceName = jInterface.getName(); if (!_interfaces.contains(interfaceName)) { _interfaces.addElement(interfaceName); } } //-- addInterface /* * * Adds the given JMethodSignature to this JClass * * @param jMethodSig the JMethodSignature to add. * @throws IllegalArgumentException when the given JMethodSignature * conflicts with an existing method signature. * / /* public void addMethod(JMethodSignature jMethodSig) throws IllegalArgumentException { if (jMethodSig == null) { String err = "The JMethodSignature cannot be null."; throw new IllegalArgumentException(err); } //-- XXXX: check method name and signatures *add later* //-- keep method list sorted for esthetics when printing //-- START SORT :-) boolean added = false; short modifierVal = 0; JModifiers modifiers = jMethodSig.getModifiers(); for (int i = 0; i < methods.size(); i++) { JMethodSignature tmp = (JMethodSignature) methods.elementAt(i); //-- first compare modifiers if (tmp.getModifiers().isProtected()) { if (!modifiers.isProtected()) { methods.insertElementAt(jMethodSig, i); added = true; break; } } //-- compare names if (jMethodSig.getName().compareTo(tmp.getName()) < 0) { methods.insertElementAt(jMethodSig, i); added = true; break; } } //-- END SORT if (!added) methods.addElement(jMethodSig); //-- check parameter packages to make sure we have them //-- in our import list String[] pkgNames = jMethodSig.getParameterClassNames(); for (int i = 0; i < pkgNames.length; i++) { addImport(pkgNames[i]); } //-- check return type to make sure it's included in the //-- import list JType jType = jMethodSig.getReturnType(); if (jType != null) { while (jType.isArray()) jType = jType.getComponentType(); if (!jType.isPrimitive()) addImport(jType.getName()); } //-- check exceptions JClass[] exceptions = jMethodSig.getExceptions(); for (int i = 0; i < exceptions.length; i++) { addImport(exceptions[i].getName()); } } //-- addMethod */ /** * Returns the field with the given name, or null if no field was found with * that name. * * @param name the name of the field to return. * @return the field with the given name, or null if no field was found with * the given name. */ public abstract JField getField(String name); /** * Returns an array of all the JFields of this JStructure. * * @return an array of all the JFields of this JStructure. */ public abstract JField[] getFields(); /** * Returns the name of the file that this JStructure would be printed to, * given a call to {@link #print(String, String)}, or given a call to * {@link #print()} if the parameter destDir is null. * * @param destDir the destination directory. This may be null. * @return the name of the file that this JInterface would be printed to */ public final String getFilename(final String destDir) { String filename = getLocalName() + ".java"; //-- Convert Java package to path string String javaPackagePath = ""; if ((_packageName != null) && (_packageName.length() > 0)) { javaPackagePath = _packageName.replace('.', File.separatorChar); } //-- Create fully qualified path (including 'destDir') to file File pathFile; if (destDir == null) { pathFile = new File(javaPackagePath); } else { pathFile = new File(destDir, javaPackagePath); } if (!pathFile.exists()) { pathFile.mkdirs(); } //-- Prefix filename with path if (pathFile.toString().length() > 0) { filename = pathFile.toString() + File.separator + filename; } return filename; } //-- getFilename /** * Returns the JComment header to display at the top of the source file for * this JStructure, or null if no header was set. * * @return the JComment header or null if none exists. */ public final JComment getHeader() { return this._header; } //-- getHeader /** * Returns an Enumeration of imported package and class names for this * JStructure. * * @return the Enumeration of imports. May be empty but will not be null. */ public final Enumeration getImports() { return _imports.elements(); } //-- getImports /** * Returns an Enumeration of interface names that this JStructure inherits * from. * * @return the Enumeration of interface names for this JStructure. May be * empty but will not be null. */ public final Enumeration getInterfaces() { return _interfaces.elements(); } //-- getInterfaces /** * Returns the JavaDoc comment for this JStructure. * * @return the JDocComment for this JStructure. */ public final JDocComment getJDocComment() { return _jdc; } //-- getJDocComment /** * Returns the object managing the annotations for this JStructure. * @return the object managing the annotations for this JStructure. */ protected final JAnnotatedElementHelper getAnnotatedElementHelper() { return _annotatedElement; } //-- getAnnotatedElementHelper /* * * Returns an array of all the JMethodSignatures of this JInterface. * * @return an array of all the JMethodSignatures of this JInterface. * / /* public JMethodSignature[] getMethods() { JMethodSignature[] marray = new JMethodSignature[methods.size()]; methods.copyInto(marray); return marray; } //-- getMethods */ /* * * Returns the JMethodSignature with the given name, and occuring at or * after the given starting index. * * @param name the name of the JMethodSignature to return. * @param startIndex the starting index to begin searching from. * @return the JMethodSignature, or null if not found. * / /* public JMethodSignature getMethod(String name, int startIndex) { for (int i = startIndex; i < methods.size(); i++) { JMethodSignature jMethod = (JMethodSignature)methods.elementAt(i); if (jMethod.getName().equals(name)) return jMethod; } return null; } //-- getMethod */ /* * * Returns the JMethodSignature at the given index. * * @param index the index of the JMethodSignature to return. * @return the JMethodSignature at the given index. * / /* public JMethodSignature getMethod(int index) { return (JMethodSignature)methods.elementAt(index); } //-- getMethod */ /** * Returns the JModifiers, which allows the qualifiers to be changed. * * @return the JModifiers for this JStructure. */ public final JModifiers getModifiers() { return _modifiers; } //-- getModifiers /** * Returns the name of the package that this JStructure is a member of. * * @return the name of the package that this JStructure is a member of, or * null if there is no current package name defined. */ public final String getPackageName() { return this._packageName; } //-- getPackageName /** * Returns the name of the class represented by this JStructure. * * @param stripPackage a boolean that when true indicates that only the * local name (no package) should be returned. * @return the name of the class represented by this JStructure, including * the full package if stripPackage is false. */ public final String getName(final boolean stripPackage) { String name = super.getName(); if (stripPackage) { name = JNaming.getLocalNameFromClassName(name); } return name; } //-- getName /** * Returns true if the given classname exists in the imports of this * JStructure. * * @param classname the class name to check for * @return true if the given classname exists in the imports list. */ public final boolean hasImport(final String classname) { return _imports.contains(classname); } //-- hasImport /** * Remove the import of the given class name from this JStucture, returning * true if the import was found and removed. * * @param className Name of the class to remove the import of * @return if the import was previously part of this JStructure, false * otherwise. */ public final boolean removeImport(final String className) { boolean result = false; if (className == null) { return result; } if (className.length() == 0) { return result; } result = _imports.removeElement(className); return result; } //-- removeImport /** * Test the provided name and return true if it is a valid class name. * * @param classname A class name to test. * @return true if the provided class name is a valid class name. */ public static boolean isValidClassName(final String classname) { if (classname == null) { return false; } String name = classname; int beforeTypeName = name.indexOf("<"); if (beforeTypeName > 0) { name = name.substring(0, beforeTypeName); } //-- ignore package information, for now name = JNaming.getLocalNameFromClassName(name); return JNaming.isValidJavaIdentifier(name); } //-- isValidClassName /** * Prints the source code for this JStructure in the current working * directory. Sub-directories will be created if necessary for the package. */ public final void print() { print((String) null, (String) null); } //-- printSrouce /** * Prints the source code for this JStructure to the destination directory. * Subdirectories will be created if necessary for the package. * * @param destDir directory name to use as the root directory for all output * @param lineSeparator the line separator to use at the end of each line. * If null, then the default line separator for the runtime * platform will be used. */ public final void print(final String destDir, final String lineSeparator) { getLocalName(); //-- open output file String filename = getFilename(destDir); File file = new File(filename); JSourceWriter jsw = null; try { jsw = new JSourceWriter(new FileWriter(file)); } catch (IOException ioe) { System.out.println("unable to create class file: " + filename); return; } if (lineSeparator == null) { jsw.setLineSeparator(System.getProperty("line.separator")); } else { jsw.setLineSeparator(lineSeparator); } print(jsw); jsw.close(); } //-- print /** * Prints the source code for this JStructure to the given JSourceWriter. * * @param jsw the JSourceWriter to print to. */ public abstract void print(JSourceWriter jsw); /** * A utility method that prints the header to the given JSourceWriter. * * @param jsw the JSourceWriter to print to. */ public final void printHeader(final JSourceWriter jsw) { if (jsw == null) { throw new IllegalArgumentException(JSW_SHOULD_NOT_BE_NULL); } //-- write class header JComment header = getHeader(); if (header != null) { header.print(jsw); } else { jsw.writeln("/*"); jsw.writeln(" * " + DEFAULT_HEADER); jsw.writeln(" */"); } jsw.writeln(); jsw.flush(); } //-- printHeader /** * A utility method that prints the imports to the given JSourceWriter. * * @param jsw the JSourceWriter to print to. */ public final void printImportDeclarations(final JSourceWriter jsw) { if (jsw == null) { throw new IllegalArgumentException(JSW_SHOULD_NOT_BE_NULL); } //-- print imports if (_imports.size() > 0) { jsw.writeln(" //---------------------------------/"); jsw.writeln(" //- Imported classes and packages -/"); jsw.writeln("//---------------------------------/"); jsw.writeln(); Enumeration enumeration = _imports.elements(); while (enumeration.hasMoreElements()) { jsw.write("import "); jsw.write(enumeration.nextElement()); jsw.writeln(';'); } jsw.writeln(); jsw.flush(); } } //-- printImportDeclarations /** * A utility method that prints the packageDeclaration to the given * JSourceWriter. * * @param jsw the JSourceWriter to print to. */ public final void printPackageDeclaration(final JSourceWriter jsw) { if (jsw == null) { throw new IllegalArgumentException(JSW_SHOULD_NOT_BE_NULL); } //-- print package name if ((_packageName != null) && (_packageName.length() > 0)) { jsw.write("package "); jsw.write(_packageName); jsw.writeln(';'); jsw.writeln(); } jsw.flush(); } //-- printPackageDeclaration /* * * Prints the source code for this JStructure to the given * JSourceWriter. * * @param jsw the JSourceWriter to print to. * / /* public abstract void print(JSourceWriter jsw); StringBuffer buffer = new StringBuffer(); printHeader(); printPackageDeclaration(); printImportDeclarations(); //------------/ //- Java Doc -/ //------------/ jdc.print(jsw); //-- print class information //-- we need to add some JavaDoc API adding comments buffer.setLength(0); if (modifiers.isPrivate()) { buffer.append("private "); } else if (modifiers.isPublic()) { buffer.append("public "); } if (modifiers.isAbstract()) { buffer.append("abstract "); } buffer.append("interface "); buffer.append(getLocalName()); buffer.append(' '); if (interfaces.size() > 0) { boolean endl = false; if (interfaces.size() > 1) { jsw.writeln(buffer.toString()); buffer.setLength(0); endl = true; } buffer.append("extends "); for (int i = 0; i < interfaces.size(); i++) { if (i > 0) buffer.append(", "); buffer.append(interfaces.elementAt(i)); } if (endl) { jsw.writeln(buffer.toString()); buffer.setLength(0); } else buffer.append(' '); } buffer.append('{'); jsw.writeln(buffer.toString()); buffer.setLength(0); jsw.writeln(); jsw.indent(); //-- print method signatures if (methods.size() > 0) { jsw.writeln(); jsw.writeln(" //-----------/"); jsw.writeln(" //- Methods -/"); jsw.writeln("//-----------/"); jsw.writeln(); } for (int i = 0; i < methods.size(); i++) { JMethodSignature signature = (JMethodSignature) methods.elementAt(i); signature.print(jsw); jsw.writeln(';'); } jsw.unindent(); jsw.writeln('}'); jsw.flush(); jsw.close(); } //-- printSource */ /** * Sets the header comment for this JStructure. * * @param comment the comment to display at the top of the source file when * printed */ public final void setHeader(final JComment comment) { this._header = comment; } //-- setHeader /** * Allows changing the package name of this JStructure. * * @param packageName the package name to use */ public void setPackageName(final String packageName) { this._packageName = packageName; changePackage(packageName); } //-- setPackageName /** * @see org.exolab.javasource.JAnnotatedElement * #addAnnotation(org.exolab.javasource.JAnnotation) * {@inheritDoc} */ public final void addAnnotation(final JAnnotation annotation) { _annotatedElement.addAnnotation(annotation); addImport(annotation); } /** * @see org.exolab.javasource.JAnnotatedElement * #getAnnotation(org.exolab.javasource.JAnnotationType) * {@inheritDoc} */ public final JAnnotation getAnnotation(final JAnnotationType annotationType) { return _annotatedElement.getAnnotation(annotationType); } /** * @see org.exolab.javasource.JAnnotatedElement#getAnnotations() * {@inheritDoc} */ public final JAnnotation[] getAnnotations() { return _annotatedElement.getAnnotations(); } /** * @see org.exolab.javasource.JAnnotatedElement * #isAnnotationPresent(org.exolab.javasource.JAnnotationType) * {@inheritDoc} */ public final boolean isAnnotationPresent(final JAnnotationType annotationType) { return _annotatedElement.isAnnotationPresent(annotationType); } /** * @see org.exolab.javasource.JAnnotatedElement * #removeAnnotation(org.exolab.javasource.JAnnotationType) * {@inheritDoc} */ public final JAnnotation removeAnnotation(final JAnnotationType annotationType) { return _annotatedElement.removeAnnotation(annotationType); } /** * @see org.exolab.javasource.JAnnotatedElement#hasAnnotations() * {@inheritDoc} */ public final boolean hasAnnotations() { return _annotatedElement.hasAnnotations(); } //---------------------/ //- Protected Methods -/ //---------------------/ /** * Return the count of the number of Interfaces that have been added to this * JStructure. * * @return the count of the number of Interfaces that have been added to * this JStructure. */ protected final int getInterfaceCount() { return _interfaces.size(); } /** * Prints the given source string to the JSourceWriter using the given * prefix at the beginning of each new line. * * @param prefix the prefix for each new line. * @param source the source code to print * @param jsw the JSourceWriter to print to. */ protected static void printlnWithPrefix(final String prefix, final String source, final JSourceWriter jsw) { jsw.write(prefix); if (source == null) { return; } char[] chars = source.toCharArray(); int lastIdx = 0; for (int i = 0; i < chars.length; i++) { char ch = chars[i]; if (ch == '\n') { //-- free buffer jsw.write(chars, lastIdx, (i - lastIdx) + 1); lastIdx = i + 1; if (i < chars.length) { jsw.write(prefix); } } } //-- free buffer if (lastIdx < chars.length) { jsw.write(chars, lastIdx, chars.length - lastIdx); } jsw.writeln(); } //-- printlnWithPrefix } //-- JStructure





© 2015 - 2025 Weber Informatics LLC | Privacy Policy