Merge pull request #1488 from lukasj/is1039
#1039: Call to JPackage.annotations() causes empty package-info.java to be generated
diff --git a/jaxb-ri/codemodel/codemodel/src/main/java/com/sun/codemodel/JPackage.java b/jaxb-ri/codemodel/codemodel/src/main/java/com/sun/codemodel/JPackage.java
index 9343c48..1cfe13d 100644
--- a/jaxb-ri/codemodel/codemodel/src/main/java/com/sun/codemodel/JPackage.java
+++ b/jaxb-ri/codemodel/codemodel/src/main/java/com/sun/codemodel/JPackage.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2019 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0, which is available at
@@ -46,18 +46,18 @@
/**
* List of classes contained within this package keyed by their name.
*/
- private final Map<String,JDefinedClass> classes = new TreeMap<String,JDefinedClass>();
+ private final Map<String,JDefinedClass> classes = new TreeMap<>();
/**
* List of resources files inside this package.
*/
- private final Set<JResourceFile> resources = new HashSet<JResourceFile>();
-
+ private final Set<JResourceFile> resources = new HashSet<>();
+
/**
* 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.
+ * "Foo" and "foo" as a collision.
*/
private final Map<String,JDefinedClass> upperCaseClassMap;
@@ -88,34 +88,39 @@
String msg = "Package name . is not allowed";
throw new IllegalArgumentException(msg);
}
-
+
if(JCodeModel.isCaseSensitiveFileSystem)
upperCaseClassMap = null;
else
- upperCaseClassMap = new HashMap<String,JDefinedClass>();
-
+ upperCaseClassMap = new HashMap<>();
+
this.name = name;
}
+ @Override
public JClassContainer parentContainer() {
return parent();
}
-
+
/**
* Gets the parent package, or null if this class is the root package.
+ * @return
*/
public JPackage parent() {
if(name.length()==0) return null;
-
+
int idx = name.lastIndexOf('.');
return owner._package(name.substring(0,idx));
}
+ @Override
public boolean isClass() { return false; }
+ @Override
public boolean isPackage() { return true; }
+ @Override
public JPackage getPackage() { return this; }
-
+
/**
* Add a class to this package.
*
@@ -126,10 +131,11 @@
* Name of class to be added to this package
*
* @return Newly generated class
- *
+ *
* @exception JClassAlreadyExistsException
* When the specified class/interface was already created.
*/
+ @Override
public JDefinedClass _class(int mods, String name) throws JClassAlreadyExistsException {
return _class(mods,name,ClassType.CLASS);
}
@@ -139,38 +145,46 @@
* @deprecated
*/
@Deprecated
+ @Override
public JDefinedClass _class( int mods, String name, boolean isInterface ) throws JClassAlreadyExistsException {
- return _class(mods,name, isInterface?ClassType.INTERFACE:ClassType.CLASS );
+ return _class(mods,name, isInterface?ClassType.INTERFACE:ClassType.CLASS );
}
-
+
+ @Override
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.
- */
+ /**
+ * Adds a public class to this package.
+ *
+ * @param name
+ * @return
+ * @throws JClassAlreadyExistsException
+ */
+ @Override
public JDefinedClass _class(String name) throws JClassAlreadyExistsException {
- return _class( JMod.PUBLIC, name );
- }
+ return _class(JMod.PUBLIC, name);
+ }
/**
* Gets a reference to the already created {@link JDefinedClass}.
- *
+ *
+ * @param name
* @return null
* If the class is not yet created.
*/
@@ -183,7 +197,9 @@
/**
* Order is based on the lexicological order of the package name.
+ * @param that
*/
+ @Override
public int compareTo(JPackage that) {
return this.name.compareTo(that.name);
}
@@ -198,18 +214,24 @@
* Name of interface to be added to this package
*
* @return Newly generated interface
+ * @throws JClassAlreadyExistsException
*/
+ @Override
public JDefinedClass _interface(int mods, String name) throws JClassAlreadyExistsException {
return _class(mods,name,ClassType.INTERFACE);
}
/**
* Adds a public interface to this package.
+ * @param name
+ * @return
+ * @throws JClassAlreadyExistsException
*/
+ @Override
public JDefinedClass _interface(String name) throws JClassAlreadyExistsException {
return _interface(JMod.PUBLIC, name);
}
-
+
/**
* Add an annotationType Declaration to this package
* @param name
@@ -218,12 +240,13 @@
* newly created Annotation Type Declaration
* @exception JClassAlreadyExistsException
* When the specified class/interface was already created.
-
+
*/
+ @Override
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
@@ -232,21 +255,26 @@
* newly created Enum
* @exception JClassAlreadyExistsException
* When the specified class/interface was already created.
-
+
*/
+ @Override
public JDefinedClass _enum (String name) throws JClassAlreadyExistsException {
return _class (JMod.PUBLIC,name,ClassType.ENUM);
}
/**
* Adds a new resource file to this package.
+ * @param rsrc
+ * @return
*/
public JResourceFile addResourceFile(JResourceFile rsrc) {
resources.add(rsrc);
return rsrc;
}
-
+
/**
* Checks if a resource of the given name exists.
+ * @param name
+ * @return
*/
public boolean hasResourceFile(String name) {
for (JResourceFile r : resources)
@@ -254,9 +282,10 @@
return true;
return false;
}
-
+
/**
* Iterates all resource files in this package.
+ * @return
*/
public Iterator<JResourceFile> propertyFiles() {
return resources.iterator();
@@ -268,6 +297,7 @@
*
* @return JDocComment containing javadocs for this class
*/
+ @Override
public JDocComment javadoc() {
if (jdoc == null)
jdoc = new JDocComment(owner());
@@ -276,6 +306,7 @@
/**
* Removes a class from this package.
+ * @param c
*/
public void remove(JClass c) {
if (c._package() != this)
@@ -288,9 +319,12 @@
if (upperCaseClassMap != null)
upperCaseClassMap.remove(c.name().toUpperCase());
}
-
+
/**
* Reference a class within this package.
+ * @param name
+ * @return
+ * @throws java.lang.ClassNotFoundException
*/
public JClass ref(String name) throws ClassNotFoundException {
if (name.indexOf('.') >= 0)
@@ -303,9 +337,11 @@
return owner.ref(Class.forName(n));
}
-
+
/**
* Gets a reference to a sub package of this package.
+ * @param pkg
+ * @return
*/
public JPackage subPackage( String pkg ) {
if(isUnnamed()) return owner()._package(pkg);
@@ -315,11 +351,13 @@
/**
* Returns an iterator that walks the top-level classes defined in this
* package.
+ * @return
*/
+ @Override
public Iterator<JDefinedClass> classes() {
return classes.values().iterator();
}
-
+
/**
* Checks if this package contains any classes.
* @return {@code true} if this package contains any classes
@@ -331,6 +369,8 @@
/**
* Checks if a given name is already defined as a class/interface
+ * @param classLocalName
+ * @return
*/
public boolean isDefined(String classLocalName) {
Iterator<JDefinedClass> itr = classes();
@@ -344,6 +384,7 @@
/**
* Checks if this package is the root, unnamed package.
+ * @return
*/
public final boolean isUnnamed() { return name.length() == 0; }
@@ -351,9 +392,9 @@
* 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>
+ * 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;
@@ -361,35 +402,42 @@
/**
* Return the code model root object being used to create this package.
+ * @return
*/
+ @Override
public final JCodeModel owner() { return owner; }
+ @Override
public JAnnotationUse annotate(JClass clazz) {
if(isUnnamed())
throw new IllegalArgumentException("the root package cannot be annotated");
if(annotations==null)
- annotations = new ArrayList<JAnnotationUse>();
+ annotations = new ArrayList<>();
JAnnotationUse a = new JAnnotationUse(clazz);
annotations.add(a);
return a;
}
+ @Override
public JAnnotationUse annotate(Class<? extends Annotation> clazz) {
return annotate(owner.ref(clazz));
}
+ @Override
public <W extends JAnnotationWriter> W annotate2(Class<W> clazz) {
return TypedAnnotationWriter.create(clazz,this);
}
+ @Override
public boolean removeAnnotation(JAnnotationUse annotation) {
return this.annotations.remove(annotation);
}
+ @Override
public Collection<JAnnotationUse> annotations() {
if (annotations == null)
- annotations = new ArrayList<JAnnotationUse>();
+ annotations = new ArrayList<>();
return Collections.unmodifiableList(annotations);
}
@@ -401,11 +449,13 @@
return new File(dir, name.replace('.', File.separatorChar));
}
+ @Override
public void declare(JFormatter f ) {
if (name.length() != 0)
f.p("package").p(name).p(';').nl();
}
+ @Override
public void generate(JFormatter f) {
f.p(name);
}
@@ -424,7 +474,7 @@
}
// write package annotations
- if(annotations!=null || jdoc!=null) {
+ if ((annotations!=null && !annotations.isEmpty()) || jdoc != null) {
JFormatter f = createJavaSourceFileWriter(src,"package-info");
if (jdoc != null)
@@ -457,7 +507,7 @@
r++;
}
- if(annotations!=null || jdoc!=null) {
+ if ((annotations!=null && !annotations.isEmpty()) || jdoc != null) {
r++;
}
diff --git a/jaxb-ri/codemodel/codemodel/src/test/java/com/sun/codemodel/tests/PackageAnnotationTest.java b/jaxb-ri/codemodel/codemodel/src/test/java/com/sun/codemodel/tests/PackageAnnotationTest.java
index 75356a5..7363951 100644
--- a/jaxb-ri/codemodel/codemodel/src/test/java/com/sun/codemodel/tests/PackageAnnotationTest.java
+++ b/jaxb-ri/codemodel/codemodel/src/test/java/com/sun/codemodel/tests/PackageAnnotationTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0, which is available at
@@ -7,7 +7,6 @@
*
* SPDX-License-Identifier: BSD-3-Clause
*/
-
package com.sun.codemodel.tests;
import java.io.IOException;
@@ -16,16 +15,33 @@
import org.junit.Test;
import com.sun.codemodel.JCodeModel;
+import com.sun.codemodel.JPackage;
import com.sun.codemodel.writer.SingleStreamCodeWriter;
+import java.io.ByteArrayOutputStream;
+import org.junit.Assert;
/**
* @author Kohsuke Kawaguchi
*/
public class PackageAnnotationTest {
- @Test
- public void main() throws IOException {
- JCodeModel cm = new JCodeModel();
- cm._package("foo").annotate(Inherited.class);
- cm.build(new SingleStreamCodeWriter(System.out));
- }
+
+ @Test
+ public void main() throws IOException {
+ JCodeModel cm = new JCodeModel();
+ cm._package("foo").annotate(Inherited.class);
+ cm.build(new SingleStreamCodeWriter(System.out));
+ }
+
+ @Test
+ public void noEmptyPInfo() throws IOException {
+ // https://github.com/eclipse-ee4j/jaxb-ri/issues/1039
+ JCodeModel cm = new JCodeModel();
+ JPackage pkg = cm._package("bar");
+ Assert.assertEquals(0, cm.countArtifacts());
+ Assert.assertNotNull(pkg.annotations());
+ Assert.assertEquals(0, cm.countArtifacts());
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ cm.build(new SingleStreamCodeWriter(baos));
+ Assert.assertTrue(baos.toString().trim().isEmpty());
+ }
}