org.codehaus.modello.plugin.java.javasource.JCompUnit 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.codehaus.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.
*
* Contributors:
* --------------
* Gary Shea ([email protected]) - Original Author
* Keith Visco ([email protected]) - Changed JCompElement references to
* JStructure, some additional tweaking
* to get it working with the current
* Javasource package.
*
* $Id$
*/
package org.codehaus.modello.plugin.java.javasource;
/*
* Copyright (c) 2004, Codehaus.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import java.io.File;
import java.util.Enumeration;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.Vector;
import org.codehaus.plexus.util.WriterFactory;
/**
* A representation of the Java Source code for a Java compilation
* unit. This is
* a useful utility when creating in memory source code.
* This package was modelled after the Java Reflection API
* as much as possible to reduce the learning curve.
* @author Gary Shea
* @version $Revision$ $Date$
**/
public class JCompUnit
{
/**
* The Id for Source control systems
* I needed to separate this line to prevent CVS from
* expanding it here! ;-)
**/
private static final String DEFAULT_HEADER
= "$" + "Id$";
private JComment header = null;
/**
* The package for this JCompUnit
**/
private String packageName = null;
/**
* The file to which this JCompUnit will be saved
**/
private String fileName = null;
/**
* The set of top-level classes that live in this compilation unit.
**/
//private TypeList classes = null;
private Vector classes = null;
/**
* The set of top-level interfaces that live in this compilation unit.
**/
//private TypeList interfaces = null;
private Vector interfaces = null;
/**
* Creates a new JCompUnit
* @param packageName the name of the package for this JCompUnit.
* If packageName is null or empty, no 'package' line will be generated.
* @param fileName the name of the file in which this JCompUnit
* will be stored
**/
public JCompUnit( String packageName, String fileName )
{
this.packageName = packageName;
this.fileName = fileName;
init();
} //-- JCompUnit
/**
* Creates a new JCompUnit with the given JClass (which must have
* been created with either a full class name or package/local
* name) as the public class. Package and file name are taken
* from jClass.
* @param jClass the public class for this JCompUnit.
**/
public JCompUnit( JClass jClass )
{
this.packageName = jClass.getPackageName();
// The outer name is the package plus the simple name of the
// outermost enclosing class. The file name is just the
// simple name of the outermost enclosing class, so the
// package name part must be stripped off.
/*
Commented out until inner-class support has been added.
kvisco - 20021211
String outer = jClass.getOuterName();
int lastDot = outer.lastIndexOf(".");
String filePrefix;
if (lastDot != -1) {
filePrefix = outer.substring (lastDot + 1);
} else {
filePrefix = outer;
}
*/
String filePrefix = jClass.getLocalName();
this.fileName = filePrefix + ".java";
init();
classes.add( jClass );
} //-- JCompUnit
/**
* Creates a new JCompUnit with the given JInterface as public interface
* Package and file name are taken from jInterface.
* @param jInterface the public interface for this JCompUnit.
**/
public JCompUnit( JInterface jInterface )
{
this.packageName = jInterface.getPackageName();
this.fileName = jInterface.getLocalName() + ".java";
init();
interfaces.add( jInterface );
} //-- JCompUnit
private void init()
{
classes = new Vector();
interfaces = new Vector();
}
/**
* Adds the given JStructure (either a JInterface or
* a JClass) to this JCompUnit.
*
* @param jStructure the JStructure to add
* @exception java.lang.IllegalArgumentException when the given
* JStructure has the same name of an existing JStructure
* or if the class of jStructure is unknown.
*/
public void addStructure( JStructure jStructure )
throws IllegalArgumentException
{
if ( jStructure instanceof JInterface )
addInterface( (JInterface) jStructure );
else if ( jStructure instanceof JClass )
addClass( (JClass) jStructure );
else
{
String err = "Unknown JStructure subclass '"
+ jStructure.getClass().getName() + "'.";
throw new IllegalArgumentException( err );
}
} //-- addStructure
/**
* Adds a JClass which should be printed in this file.
**/
public void addClass( JClass jClass )
{
classes.add( jClass );
} //-- addClass
/**
* Adds a JInterface which should be printed in this file.
**/
public void addInterface( JInterface jInterface )
{
interfaces.add( jInterface );
} //-- addInterface
/**
* returns a array of String containing all import classes/packages,
* also imports within the same package of this object.
* @return a array of String containing all import classes/packages,
* also imports within the same package of this object.
*/
public SortedSet getImports()
{
SortedSet allImports = new TreeSet();
// add imports from classes
for ( JClass jClass : classes )
{
Enumeration e = jClass.getImports();
while ( e.hasMoreElements() )
{
allImports.add( e.nextElement() );
}
}
for ( JInterface jInterface : interfaces )
{
Enumeration e = jInterface.getImports();
while ( e.hasMoreElements() )
{
allImports.add( e.nextElement() );
}
}
return allImports;
}
/**
* Returns the name of the file that this JCompUnit would be
* printed as, given a call to #print.
*
* @param destDir the destination directory. This may be null.
* @return the name of the file that this JCompUnit would be
* printed as, given a call to #print.
**/
public String getFilename( String destDir )
{
String filename = new String( fileName );
//-- 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 name of the package that this JCompUnit is a member of
* @return the name of the package that this JCompUnit is a member of,
* or null if there is no current package name defined
**/
public String getPackageName()
{
return this.packageName;
} //-- getPackageName
protected static String getPackageFromClassName( String className )
{
int idx = -1;
if ( ( idx = className.lastIndexOf( '.' ) ) > 0 )
{
return className.substring( 0, idx );
}
return null;
} //-- getPackageFromClassName
/**
* Prints the source code for this JClass in the current directory
* with the default line seperator of the the runtime platform.
* @see print(java.lang.String, java.lang.String)
**/
public void print()
{
print( null, null );
} //-- print
/**
* Prints the source code for this JClass
* with the default line seperator of the the runtime platform.
* @param destDir the destination directory to generate the file.
* @see print(java.lang.String, java.lang.String)
**/
public void print( String destDir )
{
print( destDir, null );
} //-- print
/**
* Prints the source code for this JCompUnit.
* @param destDir the destination directory to generate the file.
* @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 void print( String destDir, String lineSeparator )
{
//-- open output file
String filename = getFilename( destDir );
File file = new File( filename );
JSourceWriter jsw = null;
try
{
jsw = new JSourceWriter( WriterFactory.newPlatformWriter( file ) );
}
catch ( java.io.IOException ioe )
{
System.out.println( "unable to create compilation unit file: " + filename );
return;
}
if ( lineSeparator == null )
{
lineSeparator = System.getProperty( "line.separator" );
}
jsw.setLineSeparator( lineSeparator );
print( jsw );
jsw.flush();
jsw.close();
} //-- print
/**
* Prints the source code for this JClass.
* @param jsw the JSourceWriter to print to.
**/
public void print( JSourceWriter jsw )
{
// Traverse the nested class and interface heirarchy and
// update the names to match the compilation unit.
resolveNames();
StringBuilder buffer = new StringBuilder();
//-- write file header
if ( header != null )
header.print( jsw );
else
{
jsw.writeln( "/*" );
jsw.writeln( " * " + DEFAULT_HEADER );
jsw.writeln( "*/" );
}
jsw.writeln();
jsw.flush();
//-- print package name
if ( ( packageName != null ) && ( packageName.length() > 0 ) )
{
buffer.setLength( 0 );
buffer.append( "package " );
buffer.append( packageName );
buffer.append( ';' );
jsw.writeln( buffer.toString() );
jsw.writeln();
}
//-- print imports
jsw.writeln( " //---------------------------------------------/" );
jsw.writeln( " //- Imported classes, interfaces and packages -/" );
jsw.writeln( "//---------------------------------------------/" );
jsw.writeln();
SortedSet allImports = getImports();
String compUnitPackage = getPackageName();
for ( String importName : allImports )
{
String importsPackage
= JStructure.getPackageFromClassName( importName );
if ( importsPackage != null &&
!importsPackage.equals( compUnitPackage ) )
{
jsw.write( "import " );
jsw.write( importName );
jsw.writeln( ';' );
}
}
jsw.writeln();
// Print the public elements, interfaces first, then classes.
// There should only be one public element, but if there are
// more we let the compiler catch it.
printStructures( jsw, true );
// Print the remaining non-public elements, interfaces first.
printStructures( jsw, false );
jsw.flush();
} //-- print
/**
* Print the source code for the contained JClass objects.
* @param jsw the JSourceWriter to print to.
* @param printPublic if true, print only public classes; if
* false, print only non-public classes.
**/
final public void printStructures( JSourceWriter jsw, boolean printPublic )
{
//-- print class information
//-- we need to add some JavaDoc API adding comments
boolean isFirst = true;
//SortedSet interfaceList = interfaces.sortedOnFullName();
for ( JInterface jInterface : interfaces )
{
if ( jInterface.getModifiers().isPublic() == printPublic )
{
if ( isFirst )
{
Header.print( jsw, printPublic );
isFirst = false;
}
jInterface.print( jsw, true );
jsw.writeln();
}
}
//SortedSet classList = classes.sortedOnFullName();
for ( JClass jClass : classes )
{
if ( jClass.getModifiers().isPublic() == printPublic )
{
if ( isFirst )
{
Header.print( jsw, printPublic );
isFirst = false;
}
jClass.print( jsw, true );
jsw.writeln();
}
}
} //-- printElements(JSourceWriter, int)
/**
* Sets the header comment for this JCompUnit
* @param comment the comment to display at the top of the source file
* when printed
**/
public void setHeader( JComment comment )
{
this.header = comment;
} //-- setHeader
//-------------------/
//- Private Methods -/
//-------------------/
/**
* Update the names of nested classes and interfaces.
**/
private void resolveNames()
{
/*
Commented out until support for inner-classes is added
kvisco - 20021211
for (int i = 0; i < classes.size(); i++) {
JClass jClass = (JClass) classes.get(i);
jClass.resolveNames(packageName, null);
}
for (int i = 0; i < interfaces.size(); i++) {
JInterface jInterface = (JInterface) interfaces.get(i);
jInterface.resolveNames(packageName, null);
}
*/
} //-- resolveNames
/**
* Test drive method...to be removed or commented out
**
public static void main(String[] args) {
JCompUnit unit = new JCompUnit("com.acme", "Test.java");
JClass testClass = new JClass("Test");
testClass.addImport("java.util.Vector");
testClass.addMember(new JField(JType.Int, "x"));
JField field = null;
field = new JField(JType.Int, "_z");
field.getModifiers().setStatic(true);
testClass.addField(field);
testClass.getStaticInitializationCode().add("_z = 75;");
JClass jcString = new JClass("String");
field = new JField(jcString, "myString");
field.getModifiers().makePrivate();
testClass.addMember(field);
//-- create constructor
JConstructor cons = testClass.createConstructor();
testClass.addConstructor(cons);
cons.getSourceCode().add("this.x = 6;");
JMethod jMethod = new JMethod(JType.Int, "getX");
jMethod.setSourceCode("return this.x;");
testClass.addMethod(jMethod);
unit.addClass (testClass);
unit.print();
} //-- main
/* */
} //-- JCompUnit
/**
* Print the headers delineating the public and non-public elements of
* the compilation unit.
**/
class Header
{
private static String[] publicHeader = {
" //-----------------------------/",
" //- Public Class / Interface -/",
"//-----------------------------/",
};
private static String[] nonPublicHeader = {
" //-------------------------------------/",
" //- Non-Public Classes / Interfaces -/",
"//-------------------------------------/",
};
/**
* Print the specified header to the given Writer.
* @params JSourceWriter an open JSourceWriter
* @params boolean if true print the public header, otherwise
* print the non-public header.
**/
protected static void print( JSourceWriter jsw, boolean printPublic )
{
String[] header = printPublic ? publicHeader : nonPublicHeader;
for ( String aHeader : header )
{
jsw.writeln( aHeader );
}
jsw.writeln();
}
} //-- Header
© 2015 - 2025 Weber Informatics LLC | Privacy Policy