mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 15:24:43 +02:00
467 lines
14 KiB
Java
467 lines
14 KiB
Java
/*
|
|
* Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation. Sun designates this
|
|
* particular file as subject to the "Classpath" exception as provided
|
|
* by Sun in the LICENSE file that accompanied this code.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
|
* CA 95054 USA or visit www.sun.com if you need additional information or
|
|
* have any questions.
|
|
*/
|
|
|
|
package com.sun.codemodel.internal;
|
|
|
|
import java.io.BufferedOutputStream;
|
|
import java.io.BufferedWriter;
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
import java.io.OutputStream;
|
|
import java.io.PrintWriter;
|
|
import java.io.Writer;
|
|
import java.lang.annotation.Annotation;
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.HashSet;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
import java.util.TreeMap;
|
|
|
|
|
|
/**
|
|
* A Java package.
|
|
*/
|
|
public final class JPackage implements JDeclaration, JGenerable, JClassContainer, JAnnotatable, Comparable<JPackage> {
|
|
|
|
/**
|
|
* Name of the package.
|
|
* May be the empty string for the root package.
|
|
*/
|
|
private String name;
|
|
|
|
private final JCodeModel owner;
|
|
|
|
/**
|
|
* List of classes contained within this package keyed by their name.
|
|
*/
|
|
private final Map<String,JDefinedClass> classes = new TreeMap<String,JDefinedClass>();
|
|
|
|
/**
|
|
* List of resources files inside this package.
|
|
*/
|
|
private final Set<JResourceFile> resources = new HashSet<JResourceFile>();
|
|
|
|
/**
|
|
* All {@link JClass}s in this package keyed the upper case class name.
|
|
*
|
|
* This field is non-null only on Windows, to detect
|
|
* "Foo" and "foo" as a collision.
|
|
*/
|
|
private final Map<String,JDefinedClass> upperCaseClassMap;
|
|
|
|
/**
|
|
* Lazily created list of package annotations.
|
|
*/
|
|
private List<JAnnotationUse> annotations = null;
|
|
|
|
/**
|
|
* package javadoc.
|
|
*/
|
|
private JDocComment jdoc = null;
|
|
|
|
/**
|
|
* JPackage constructor
|
|
*
|
|
* @param name
|
|
* Name of package
|
|
*
|
|
* @param cw The code writer being used to create this package
|
|
*
|
|
* @throws IllegalArgumentException
|
|
* If each part of the package name is not a valid identifier
|
|
*/
|
|
JPackage(String name, JCodeModel cw) {
|
|
this.owner = cw;
|
|
if (name.equals(".")) {
|
|
String msg = "Package name . is not allowed";
|
|
throw new IllegalArgumentException(msg);
|
|
}
|
|
|
|
if(JCodeModel.isCaseSensitiveFileSystem)
|
|
upperCaseClassMap = null;
|
|
else
|
|
upperCaseClassMap = new HashMap<String,JDefinedClass>();
|
|
|
|
this.name = name;
|
|
}
|
|
|
|
|
|
public JClassContainer parentContainer() {
|
|
return parent();
|
|
}
|
|
|
|
/**
|
|
* Gets the parent package, or null if this class is the root package.
|
|
*/
|
|
public JPackage parent() {
|
|
if(name.length()==0) return null;
|
|
|
|
int idx = name.lastIndexOf('.');
|
|
return owner._package(name.substring(0,idx));
|
|
}
|
|
|
|
public boolean isClass() { return false; }
|
|
public boolean isPackage() { return true; }
|
|
public JPackage getPackage() { return this; }
|
|
|
|
/**
|
|
* Add a class to this package.
|
|
*
|
|
* @param mods
|
|
* Modifiers for this class declaration
|
|
*
|
|
* @param name
|
|
* Name of class to be added to this package
|
|
*
|
|
* @return Newly generated class
|
|
*
|
|
* @exception JClassAlreadyExistsException
|
|
* When the specified class/interface was already created.
|
|
*/
|
|
public JDefinedClass _class(int mods, String name) throws JClassAlreadyExistsException {
|
|
return _class(mods,name,ClassType.CLASS);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
* @deprecated
|
|
*/
|
|
public JDefinedClass _class( int mods, String name, boolean isInterface ) throws JClassAlreadyExistsException {
|
|
return _class(mods,name, isInterface?ClassType.INTERFACE:ClassType.CLASS );
|
|
}
|
|
|
|
public JDefinedClass _class( int mods, String name, ClassType classTypeVal ) throws JClassAlreadyExistsException {
|
|
if(classes.containsKey(name))
|
|
throw new JClassAlreadyExistsException(classes.get(name));
|
|
else {
|
|
// XXX problems caught in the NC constructor
|
|
JDefinedClass c = new JDefinedClass(this, mods, name, classTypeVal);
|
|
|
|
if( upperCaseClassMap!=null ) {
|
|
JDefinedClass dc = upperCaseClassMap.get(name.toUpperCase());
|
|
if(dc!=null)
|
|
throw new JClassAlreadyExistsException(dc);
|
|
upperCaseClassMap.put(name.toUpperCase(),c);
|
|
}
|
|
classes.put(name,c);
|
|
return c;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Adds a public class to this package.
|
|
*/
|
|
public JDefinedClass _class(String name) throws JClassAlreadyExistsException {
|
|
return _class( JMod.PUBLIC, name );
|
|
}
|
|
|
|
/**
|
|
* Gets a reference to the already created {@link JDefinedClass}.
|
|
*
|
|
* @return null
|
|
* If the class is not yet created.
|
|
*/
|
|
public JDefinedClass _getClass(String name) {
|
|
if(classes.containsKey(name))
|
|
return classes.get(name);
|
|
else
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Order is based on the lexicological order of the package name.
|
|
*/
|
|
public int compareTo(JPackage that) {
|
|
return this.name.compareTo(that.name);
|
|
}
|
|
|
|
/**
|
|
* Add an interface to this package.
|
|
*
|
|
* @param mods
|
|
* Modifiers for this interface declaration
|
|
*
|
|
* @param name
|
|
* Name of interface to be added to this package
|
|
*
|
|
* @return Newly generated interface
|
|
*/
|
|
public JDefinedClass _interface(int mods, String name) throws JClassAlreadyExistsException {
|
|
return _class(mods,name,ClassType.INTERFACE);
|
|
}
|
|
|
|
/**
|
|
* Adds a public interface to this package.
|
|
*/
|
|
public JDefinedClass _interface(String name) throws JClassAlreadyExistsException {
|
|
return _interface(JMod.PUBLIC, name);
|
|
}
|
|
|
|
/**
|
|
* Add an annotationType Declaration to this package
|
|
* @param name
|
|
* Name of the annotation Type declaration to be added to this package
|
|
* @return
|
|
* newly created Annotation Type Declaration
|
|
* @exception JClassAlreadyExistsException
|
|
* When the specified class/interface was already created.
|
|
|
|
*/
|
|
public JDefinedClass _annotationTypeDeclaration(String name) throws JClassAlreadyExistsException {
|
|
return _class (JMod.PUBLIC,name,ClassType.ANNOTATION_TYPE_DECL);
|
|
}
|
|
|
|
/**
|
|
* Add a public enum to this package
|
|
* @param name
|
|
* Name of the enum to be added to this package
|
|
* @return
|
|
* newly created Enum
|
|
* @exception JClassAlreadyExistsException
|
|
* When the specified class/interface was already created.
|
|
|
|
*/
|
|
public JDefinedClass _enum (String name) throws JClassAlreadyExistsException {
|
|
return _class (JMod.PUBLIC,name,ClassType.ENUM);
|
|
}
|
|
/**
|
|
* Adds a new resource file to this package.
|
|
*/
|
|
public JResourceFile addResourceFile(JResourceFile rsrc) {
|
|
resources.add(rsrc);
|
|
return rsrc;
|
|
}
|
|
|
|
/**
|
|
* Checks if a resource of the given name exists.
|
|
*/
|
|
public boolean hasResourceFile(String name) {
|
|
for (JResourceFile r : resources)
|
|
if (r.name().equals(name))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Iterates all resource files in this package.
|
|
*/
|
|
public Iterator propertyFiles() {
|
|
return resources.iterator();
|
|
}
|
|
|
|
/**
|
|
* Creates, if necessary, and returns the package javadoc for this
|
|
* JDefinedClass.
|
|
*
|
|
* @return JDocComment containing javadocs for this class
|
|
*/
|
|
public JDocComment javadoc() {
|
|
if (jdoc == null)
|
|
jdoc = new JDocComment(owner());
|
|
return jdoc;
|
|
}
|
|
|
|
/**
|
|
* Removes a class from this package.
|
|
*/
|
|
public void remove(JClass c) {
|
|
if (c._package() != this)
|
|
throw new IllegalArgumentException(
|
|
"the specified class is not a member of this package," + " or it is a referenced class");
|
|
|
|
// note that c may not be a member of classes.
|
|
// this happens when someone is trying to remove a non generated class
|
|
classes.remove(c.name());
|
|
if (upperCaseClassMap != null)
|
|
upperCaseClassMap.remove(c.name().toUpperCase());
|
|
}
|
|
|
|
/**
|
|
* Reference a class within this package.
|
|
*/
|
|
public JClass ref(String name) throws ClassNotFoundException {
|
|
if (name.indexOf('.') >= 0)
|
|
throw new IllegalArgumentException("JClass name contains '.': " + name);
|
|
|
|
String n = "";
|
|
if (!isUnnamed())
|
|
n = this.name + '.';
|
|
n += name;
|
|
|
|
return owner.ref(Class.forName(n));
|
|
}
|
|
|
|
/**
|
|
* Gets a reference to a sub package of this package.
|
|
*/
|
|
public JPackage subPackage( String pkg ) {
|
|
if(isUnnamed()) return owner()._package(pkg);
|
|
else return owner()._package(name+'.'+pkg);
|
|
}
|
|
|
|
/**
|
|
* Returns an iterator that walks the top-level classes defined in this
|
|
* package.
|
|
*/
|
|
public Iterator<JDefinedClass> classes() {
|
|
return classes.values().iterator();
|
|
}
|
|
|
|
/**
|
|
* Checks if a given name is already defined as a class/interface
|
|
*/
|
|
public boolean isDefined(String classLocalName) {
|
|
Iterator itr = classes();
|
|
while (itr.hasNext()) {
|
|
if (((JClass)itr.next()).name().equals(classLocalName))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Checks if this package is the root, unnamed package.
|
|
*/
|
|
public final boolean isUnnamed() { return name.length() == 0; }
|
|
|
|
/**
|
|
* Get the name of this package
|
|
*
|
|
* @return
|
|
* The name of this package, or the empty string if this is the
|
|
* null package. For example, this method returns strings like
|
|
* <code>"java.lang"</code>
|
|
*/
|
|
public String name() {
|
|
return name;
|
|
}
|
|
|
|
/**
|
|
* Return the code model root object being used to create this package.
|
|
*/
|
|
public final JCodeModel owner() { return owner; }
|
|
|
|
|
|
public JAnnotationUse annotate(JClass clazz) {
|
|
if(isUnnamed())
|
|
throw new IllegalArgumentException("the root package cannot be annotated");
|
|
if(annotations==null)
|
|
annotations = new ArrayList<JAnnotationUse>();
|
|
JAnnotationUse a = new JAnnotationUse(clazz);
|
|
annotations.add(a);
|
|
return a;
|
|
}
|
|
|
|
public JAnnotationUse annotate(Class<? extends Annotation> clazz) {
|
|
return annotate(owner.ref(clazz));
|
|
}
|
|
|
|
public <W extends JAnnotationWriter> W annotate2(Class<W> clazz) {
|
|
return TypedAnnotationWriter.create(clazz,this);
|
|
}
|
|
|
|
|
|
/**
|
|
* Convert the package name to directory path equivalent
|
|
*/
|
|
File toPath(File dir) {
|
|
if (name == null) return dir;
|
|
return new File(dir, name.replace('.', File.separatorChar));
|
|
}
|
|
|
|
public void declare(JFormatter f ) {
|
|
if (name.length() != 0)
|
|
f.p("package").p(name).p(';').nl();
|
|
}
|
|
|
|
public void generate(JFormatter f) {
|
|
f.p(name);
|
|
}
|
|
|
|
|
|
void build( CodeWriter src, CodeWriter res ) throws IOException {
|
|
|
|
// write classes
|
|
for (JDefinedClass c : classes.values()) {
|
|
if (c.isHidden())
|
|
continue; // don't generate this file
|
|
|
|
JFormatter f = createJavaSourceFileWriter(src, c.name());
|
|
f.write(c);
|
|
f.close();
|
|
}
|
|
|
|
// write package annotations
|
|
if(annotations!=null || jdoc!=null) {
|
|
JFormatter f = createJavaSourceFileWriter(src,"package-info");
|
|
|
|
if (jdoc != null)
|
|
f.g(jdoc);
|
|
|
|
// TODO: think about importing
|
|
if (annotations != null){
|
|
for (JAnnotationUse a : annotations)
|
|
f.g(a).nl();
|
|
}
|
|
f.d(this);
|
|
|
|
f.close();
|
|
}
|
|
|
|
// write resources
|
|
for (JResourceFile rsrc : resources) {
|
|
CodeWriter cw = rsrc.isResource() ? res : src;
|
|
OutputStream os = new BufferedOutputStream(cw.openBinary(this, rsrc.name()));
|
|
rsrc.build(os);
|
|
os.close();
|
|
}
|
|
}
|
|
|
|
/*package*/ int countArtifacts() {
|
|
int r = 0;
|
|
for (JDefinedClass c : classes.values()) {
|
|
if (c.isHidden())
|
|
continue; // don't generate this file
|
|
r++;
|
|
}
|
|
|
|
if(annotations!=null || jdoc!=null) {
|
|
r++;
|
|
}
|
|
|
|
r+= resources.size();
|
|
|
|
return r;
|
|
}
|
|
|
|
private JFormatter createJavaSourceFileWriter(CodeWriter src, String className) throws IOException {
|
|
Writer bw = new BufferedWriter(src.openSource(this,className+".java"));
|
|
return new JFormatter(new PrintWriter(bw));
|
|
}
|
|
}
|