diff --git a/pom.xml b/pom.xml
index cb4a35f..c94e6d4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -174,6 +174,12 @@
system
${java.home}/../lib/tools.jar
+
+ org.projectlombok
+ lombok
+ 1.16.20
+ provided
+
diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/CoverageDoclet.java b/src/main/java/com/manoelcampos/javadoc/coverage/CoverageDoclet.java
index 0d5739a..4042569 100644
--- a/src/main/java/com/manoelcampos/javadoc/coverage/CoverageDoclet.java
+++ b/src/main/java/com/manoelcampos/javadoc/coverage/CoverageDoclet.java
@@ -15,16 +15,10 @@
*/
package com.manoelcampos.javadoc.coverage;
-import com.manoelcampos.javadoc.coverage.exporter.ConsoleExporter;
-import com.manoelcampos.javadoc.coverage.exporter.DataExporter;
-import com.manoelcampos.javadoc.coverage.exporter.HtmlExporter;
-import com.sun.javadoc.DocErrorReporter;
-import com.sun.javadoc.Doclet;
-import com.sun.javadoc.LanguageVersion;
-import com.sun.javadoc.RootDoc;
-import com.sun.tools.doclets.standard.Standard;
-
-import java.io.*;
+import com.manoelcampos.javadoc.coverage.configuration.Configuration;
+import com.manoelcampos.javadoc.coverage.exporter.*;
+import com.manoelcampos.javadoc.coverage.stats.JavaDocsStats;
+import com.sun.javadoc.*;
/**
* A {@link Doclet} that computes coverage of JavaDoc documentation.
@@ -42,13 +36,6 @@
* @since 1.0.0
*/
public class CoverageDoclet {
- /**
- * A command line parameter to enable defining the name of the coverage report.
- * The first value is the long version of the parameter name and the second
- * is the short one.
- */
- public static final String OUTPUT_NAME_OPTION[] = {"-outputName", "-o"};
-
/**
* The {@link DataExporter} object to export the coverage report to a file
* in a specific format.
@@ -57,8 +44,8 @@ public class CoverageDoclet {
private final RootDoc rootDoc;
/**
- * Starts the actual parsing or JavaDoc documentation and generation of the coverage report.
- * This is the entry point for the JavaDoc tool to start the Doclet.
+ * Starts the actual parsing or JavaDoc documentation and generation of the coverage report. This is the entry point
+ * for the JavaDoc tool to start the Doclet.
*
* @param rootDoc root element which enables reading JavaDoc documentation
* @return true if the Doclet was started successfully, false otherwise
@@ -75,51 +62,12 @@ public static boolean start(final RootDoc rootDoc) {
*/
public CoverageDoclet(final RootDoc rootDoc) {
this.rootDoc = rootDoc;
- this.exporter = new HtmlExporter(this);
- }
+ Configuration config = new Configuration(rootDoc.options());
- /**
- * Checks if a given parameter is a valid custom parameter accepted by this doclet.
- * @param paramName the name of the parameter to check
- * @return true if it's a valid custom parameter, false otherwise
- */
- private static boolean isCustomParameter(final String paramName) {
- return isParameter(paramName, OUTPUT_NAME_OPTION);
- }
+ JavaDocsStats stats = new JavaDocsStats(rootDoc, config);
- /**
- * Checks if the name of a given parameter corresponds to either its long or short form.
- *
- * @param paramName the name of the parameter to check
- * @param validNames the list of accepted names for that parameter
- * @return true if the given name corresponds to one of the valid names, false otherwise
- */
- private static boolean isParameter(final String paramName, final String[] validNames) {
- for (String validName : validNames) {
- if (validName.equalsIgnoreCase(paramName)) {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * Validates command line options.
- *
- * @param options the array of given options
- * @param errorReporter an object that allows printing error messages for invalid options
- * @return true if the options are valid, false otherwise
- * @see Doclet#validOptions(String[][], DocErrorReporter)
- */
- public static boolean validOptions(final String[][] options, final DocErrorReporter errorReporter) {
- for (final String[] opt : options) {
- if (isCustomParameter(opt[0])) {
- return true;
- }
- }
-
- return Standard.validOptions(options, errorReporter);
+ // this needs to be the last part as it already accesses some stuff from the doclet
+ this.exporter = new HtmlExporter(config, stats);
}
/**
@@ -130,32 +78,19 @@ public static boolean validOptions(final String[][] options, final DocErrorRepor
* @see Doclet#optionLength(String)
*/
public static int optionLength(final String option) {
- /*The custom outputName parameter accepts one argument.
- * The name of the param counts as the one argument.*/
- if (isCustomParameter(option)) {
- return 2;
- }
-
- return Standard.optionLength(option);
+ return Configuration.getOptionLength(option);
}
/**
- * Gets the values associated to a given command line option.
+ * Checks that all given option are valid
*
- * @param optionNames an array containing the valid names for the command line option to get its associated values.
- * This array may include the long and short versions of the option name,
- * for instance {@code {-outputName, -o}}.
- * @return the values associated to the option, where the 0th element is the option itself;
- * or an empty array if the option is invalid.
+ * @param options the options to be checked on validity
+ * @param errorReporter
+ * @return true if the options are valid
+ * @see Doclet#validOptions(String[][], DocErrorReporter)
*/
- public String[] getOptionValues(final String[] optionNames) {
- for (final String[] optionValues : rootDoc.options()) {
- if (isParameter(optionValues[0], optionNames)) {
- return optionValues;
- }
- }
-
- return new String[]{};
+ public static boolean validOptions(final String[][] options, final DocErrorReporter errorReporter) {
+ return Configuration.areValidOptions(options, errorReporter);
}
/**
@@ -186,44 +121,4 @@ private boolean render() {
public RootDoc getRootDoc() {
return rootDoc;
}
-
- /**
- * Gets a {@link PrintWriter} used by the {@link #exporter} to write
- * the coverage report to.
- *
- * @param file the file to which the coverage report will be saved to
- */
- public PrintWriter getWriter(final File file) throws FileNotFoundException {
- return new PrintWriter(new OutputStreamWriter(new FileOutputStream(file)));
- }
-
- /**
- * Gets a {@link File} object from a given file name.
- *
- * @param fileName the name of the file to get a {@link File} object.
- * @return the {@link File} object
- */
- public File getOutputFile(final String fileName) {
- final File dir = new File(getOutputDir());
- if (!dir.exists() && !dir.mkdirs()) {
- throw new RuntimeException("The directory '" + getOutputDir() + "' was not created due to unknown reason.");
- }
-
- return new File(dir, fileName);
- }
-
- /**
- * Gets the output directory passed as a command line argument to javadoc tool.
- *
- * @return the output directory to export the JavaDocs
- */
- private String getOutputDir() {
- for (final String[] option : rootDoc.options()) {
- if (option.length == 2 && option[0].equals("-d")) {
- return Utils.includeTrailingDirSeparator(option[1]);
- }
- }
-
- return "";
- }
}
diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/configuration/Configuration.java b/src/main/java/com/manoelcampos/javadoc/coverage/configuration/Configuration.java
new file mode 100644
index 0000000..0a22d71
--- /dev/null
+++ b/src/main/java/com/manoelcampos/javadoc/coverage/configuration/Configuration.java
@@ -0,0 +1,124 @@
+package com.manoelcampos.javadoc.coverage.configuration;
+
+import java.util.*;
+
+import com.manoelcampos.javadoc.coverage.Utils;
+import com.sun.javadoc.DocErrorReporter;
+import com.sun.tools.doclets.standard.Standard;
+
+public class Configuration {
+
+ private static final NoValueOption computePublicCoverageOnly = new NoValueOption("-po", "-publicOnly",
+ "Indicates if coverage should be computed only for the public parts of a project.");
+ private static final StringOption coverageFileName = new StringOption("-o", "-outputName",
+ "Set the filename for the created coverage file. If nothing is given, the default is \"javadoc-coverage\".",
+ Optional.of("javadoc-coverage"));
+
+ private static final List> ALL_OPTIONS = new ArrayList<>();
+
+ /**
+ * Static constructor for initializing the options list
+ */
+ static {
+ ALL_OPTIONS.add(computePublicCoverageOnly);
+ ALL_OPTIONS.add(coverageFileName);
+ }
+
+ /**
+ * The raw options which need to be parsed to our configuration
+ */
+ private final String[][] rawOptions;
+
+ public Configuration(String[][] rawOptions) {
+ this.rawOptions = rawOptions;
+ }
+
+ public boolean computePublicCoverageOnly() {
+ return isOptionContained(computePublicCoverageOnly);
+ }
+
+ public String getCoverageFileName() {
+ if (isOptionContained(coverageFileName)) {
+ return getOptionValue(coverageFileName);
+ }
+ return coverageFileName.getDefaultValue();
+ }
+
+ /**
+ * Gets the output directory passed as a command line argument to javadoc tool.
+ *
+ * @return the output directory to export the JavaDocs
+ */
+ public String getOutputDirectory() {
+ // This is no option of the doclet, but instead of the javadoc tool
+ // so we don't declare it as an option here directly)
+
+ for (final String[] option : rawOptions) {
+ if (option.length == 2 && option[0].equals("-d")) {
+ return Utils.includeTrailingDirSeparator(option[1]);
+ }
+ }
+
+ return "";
+ }
+
+ private boolean isOptionContained(Option> option) {
+ for (final String[] opt : rawOptions) {
+ if (option.isOption(opt[0])) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private T getOptionValue(Option option) {
+ if (!isOptionContained(option) && !option.hasDefaultValue()) {
+ throw new IllegalStateException("Option is not contained and has no default value");
+ }
+
+ if (!isOptionContained(option)) {
+ return option.getDefaultValue();
+ }
+
+ for (final String[] opt: rawOptions) {
+ if (option.isOption(opt[0])) {
+ return option.parseValue(opt);
+ }
+ }
+
+ throw new IllegalStateException("no valid option found although it should be there");
+ }
+
+ /**
+ * This method is necessary for validating the doclet parameters, which happens before instantiating the
+ * CoverageDoclet and the configuration container.
+ *
+ * @param option
+ * @return the length of the option
+ */
+ public static int getOptionLength(final String option) {
+ Optional> opt = ALL_OPTIONS.stream().filter(o -> o.isOption(option)).findFirst();
+ if (opt.isPresent()) {
+ return opt.get().getLength();
+ }
+ return Standard.optionLength(option);
+ }
+
+ /**
+ * This method is necessary for validating the doclet parameters, which happens before instantiating the
+ * CoverageDoclet and the configuration container.
+ *
+ * @param options
+ * @param errorReporter
+ * @return indicates if the given options are valid
+ */
+ public static boolean areValidOptions(final String[][] options, final DocErrorReporter errorReporter) {
+ for (final String[] opt : options) {
+ if (ALL_OPTIONS.stream().anyMatch(o -> o.isOption(opt[0]))) {
+ return true;
+ }
+ }
+
+ return Standard.validOptions(options, errorReporter);
+ }
+}
diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/configuration/NoValueOption.java b/src/main/java/com/manoelcampos/javadoc/coverage/configuration/NoValueOption.java
new file mode 100644
index 0000000..f615411
--- /dev/null
+++ b/src/main/java/com/manoelcampos/javadoc/coverage/configuration/NoValueOption.java
@@ -0,0 +1,20 @@
+package com.manoelcampos.javadoc.coverage.configuration;
+
+import lombok.NonNull;
+
+class NoValueOption extends Option {
+
+ public NoValueOption(@NonNull String shortName, @NonNull String longName, @NonNull String description) {
+ super(shortName, longName, description, 1);
+ }
+
+ @Override
+ public Void parseValue(String[] value) {
+ throw new UnsupportedOperationException("NoValueOption does not have a value.");
+ }
+
+ @Override
+ public Void getDefaultValue() {
+ throw new UnsupportedOperationException("NoValueOption does not have a default value.");
+ }
+}
diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/configuration/Option.java b/src/main/java/com/manoelcampos/javadoc/coverage/configuration/Option.java
new file mode 100644
index 0000000..817f7c5
--- /dev/null
+++ b/src/main/java/com/manoelcampos/javadoc/coverage/configuration/Option.java
@@ -0,0 +1,32 @@
+package com.manoelcampos.javadoc.coverage.configuration;
+
+import lombok.*;
+
+@ToString
+@Getter
+@AllArgsConstructor
+abstract class Option {
+ @NonNull
+ private final String shortName;
+ @NonNull
+ private final String longName;
+ @NonNull
+ private final String description;
+ private final int length;
+
+ public abstract T parseValue(String[] opt);
+
+ public final boolean isOption(String name) {
+ return shortName.equals(name) || longName.equals(name);
+ }
+
+ public boolean hasDefaultValue() {
+ return false;
+ }
+
+ public abstract T getDefaultValue();
+
+ public int getLength() {
+ return length;
+ }
+}
diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/configuration/StringOption.java b/src/main/java/com/manoelcampos/javadoc/coverage/configuration/StringOption.java
new file mode 100644
index 0000000..8967ab3
--- /dev/null
+++ b/src/main/java/com/manoelcampos/javadoc/coverage/configuration/StringOption.java
@@ -0,0 +1,34 @@
+package com.manoelcampos.javadoc.coverage.configuration;
+
+import java.util.Optional;
+
+import lombok.NonNull;
+
+class StringOption extends Option {
+
+ private final Optional defaultValue;
+
+ public StringOption(@NonNull String shortName, @NonNull String longName, @NonNull String description,
+ @NonNull Optional defaultValue) {
+ super(shortName, longName, description, 2);
+ this.defaultValue = defaultValue;
+ }
+
+ @Override
+ public String parseValue(String[] value) {
+ if (value.length != 2) {
+ throw new IllegalStateException("Wrong option line passed, string options do only have 2 values");
+ }
+ return value[1];
+ }
+
+ @Override
+ public boolean hasDefaultValue() {
+ return defaultValue.isPresent();
+ }
+
+ @Override
+ public String getDefaultValue() {
+ return defaultValue.get();
+ }
+}
diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/exporter/AbstractDataExporter.java b/src/main/java/com/manoelcampos/javadoc/coverage/exporter/AbstractDataExporter.java
index 91a9e45..8579c80 100644
--- a/src/main/java/com/manoelcampos/javadoc/coverage/exporter/AbstractDataExporter.java
+++ b/src/main/java/com/manoelcampos/javadoc/coverage/exporter/AbstractDataExporter.java
@@ -15,13 +15,13 @@
*/
package com.manoelcampos.javadoc.coverage.exporter;
-import com.manoelcampos.javadoc.coverage.CoverageDoclet;
+import java.io.*;
+
import com.manoelcampos.javadoc.coverage.Utils;
+import com.manoelcampos.javadoc.coverage.configuration.Configuration;
import com.manoelcampos.javadoc.coverage.stats.JavaDocsStats;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.PrintWriter;
+import lombok.NonNull;
/**
* Abstract class to implement JavaDoc Coverage reports in different formats.
@@ -34,17 +34,21 @@ public abstract class AbstractDataExporter implements DataExporter {
private final JavaDocsStats stats;
private final PrintWriter writer;
private File file;
- private final CoverageDoclet doclet;
+ private final Configuration config;
private final String reportFileName;
/**
* Instantiates a DataExporter object to generate JavaDoc coverage report.
*
- * @param doclet the {@link CoverageDoclet} which computes teh JavaDoc coverage statistics.
- * @param fileExtension the extension to the report file. If empty, the report will be printed to the standard output.
+ * @param config the configuration of the doclet
+ * @param stats the javadoc statistics
+ * @param fileExtension the extension to the report file. If empty, the report will be printed to the standard
+ * output.
*/
- protected AbstractDataExporter(final CoverageDoclet doclet, final String fileExtension) {
- this.doclet = doclet;
+ protected AbstractDataExporter(@NonNull final Configuration config, @NonNull final JavaDocsStats stats,
+ final String fileExtension) {
+ this.stats = stats;
+ this.config = config;
if (Utils.isStringEmpty(fileExtension)) {
writer = new PrintWriter(System.out);
@@ -52,54 +56,54 @@ protected AbstractDataExporter(final CoverageDoclet doclet, final String fileExt
} else {
this.reportFileName = generateReportFileName(fileExtension);
try {
- this.writer = doclet.getWriter(file);
+ this.writer = getWriter(file);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
}
-
- this.stats = new JavaDocsStats(doclet.getRootDoc());
}
/**
* Instantiates a DataExporter object that generates JavaDoc coverage report to the standard output.
*
- * @param doclet the {@link CoverageDoclet} which computes teh JavaDoc coverage statistics.
+ * @param config the configuration of the doclet
+ * @param stats the javadoc statistics
*/
- protected AbstractDataExporter(final CoverageDoclet doclet) {
- this(doclet, "");
- }
-
- private String generateReportFileName(final String fileExtension) {
- String fileName = getFileNameFromCommandLine();
- fileName = fileName + fileExtensionToAdd(fileName, fileExtension);
- this.file = doclet.getOutputFile(fileName);
- return fileName;
+ protected AbstractDataExporter(@NonNull final Configuration config, @NonNull final JavaDocsStats stats) {
+ this(config, stats, "");
}
/**
- * Gets the JavaDoc Coverage Report file name from command line options
- * or the default name if no option is given.
+ * Gets a {@link PrintWriter} used by the {@link #exporter} to write the coverage report to.
*
- * @return
- * @see CoverageDoclet#OUTPUT_NAME_OPTION
+ * @param file the file to which the coverage report will be saved to
*/
- private String getFileNameFromCommandLine() {
- final String[] outputNameOption = doclet.getOptionValues(CoverageDoclet.OUTPUT_NAME_OPTION);
- return outputNameOption.length > 1 ? outputNameOption[1] : DEFAULT_OUTPUT_NAME;
+ private PrintWriter getWriter(final File file) throws FileNotFoundException {
+ return new PrintWriter(new OutputStreamWriter(new FileOutputStream(file)));
+ }
+
+ private String generateReportFileName(final String fileExtension) {
+ String fileName = config.getCoverageFileName();
+ if (Utils.getFileExtension(fileName).isEmpty()) {
+ fileName += getFileExtensionStartingWithDot(fileExtension);
+ }
+ this.file = getOutputFile(fileName);
+ return fileName;
}
/**
- * Gets the extension to add to a given file if it doesn't have one.
+ * Gets a {@link File} object for the output file
*
- * @param fileName the file name to try getting and extension to add
- * @param defaultFileExtension the default file extension to return if the file doesn't have one
- * @return the file extension to add to the file it it doesn't have one or an empty string
- * if it already has.
+ * @return the {@link File} object
*/
- private String fileExtensionToAdd(final String fileName, final String defaultFileExtension) {
- return Utils.getFileExtension(fileName).isEmpty() ?
- getFileExtensionStartingWithDot(defaultFileExtension) : "";
+ private File getOutputFile(String fileName) {
+ String outputDirectory = config.getOutputDirectory();
+ final File dir = new File(outputDirectory);
+ if (!dir.exists() && !dir.mkdirs()) {
+ throw new RuntimeException("The directory '" + outputDirectory + "' was not created due to unknown reason.");
+ }
+
+ return new File(dir, fileName);
}
/**
@@ -121,7 +125,6 @@ public String getReportFileName() {
public boolean build() {
try {
header();
- exportClassesDocStats();
exportPackagesDocStats();
exportProjectDocumentationCoverageSummary();
footer();
@@ -154,6 +157,4 @@ public File getFile() {
protected abstract void afterBuild();
protected abstract void exportPackagesDocStats();
-
- protected abstract void exportClassesDocStats();
}
diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/exporter/ConsoleExporter.java b/src/main/java/com/manoelcampos/javadoc/coverage/exporter/ConsoleExporter.java
index 1f60fc3..f5d950f 100644
--- a/src/main/java/com/manoelcampos/javadoc/coverage/exporter/ConsoleExporter.java
+++ b/src/main/java/com/manoelcampos/javadoc/coverage/exporter/ConsoleExporter.java
@@ -15,13 +15,14 @@
*/
package com.manoelcampos.javadoc.coverage.exporter;
-import com.manoelcampos.javadoc.coverage.CoverageDoclet;
+import java.io.PrintWriter;
+import java.util.List;
+
import com.manoelcampos.javadoc.coverage.Utils;
+import com.manoelcampos.javadoc.coverage.configuration.Configuration;
import com.manoelcampos.javadoc.coverage.stats.*;
-import com.sun.javadoc.PackageDoc;
-import java.io.PrintWriter;
-import java.util.List;
+import lombok.NonNull;
/**
* Prints the JavaDoc coverage report to the console (standard output).
@@ -31,8 +32,8 @@
*/
public class ConsoleExporter extends AbstractDataExporter {
- public ConsoleExporter(final CoverageDoclet doclet) {
- super(doclet);
+ public ConsoleExporter(@NonNull Configuration config, @NonNull JavaDocsStats stats) {
+ super(config, stats);
}
@Override
@@ -51,33 +52,20 @@ protected void exportProjectDocumentationCoverageSummary() {
@Override
protected void exportPackagesDocStats() {
- final PackagesDocStats packagesDocStats = getStats().getPackagesDocStats();
- exportPkgsOrClassesDocStats(packagesDocStats);
- packagesDocStats.getPackagesDoc().forEach(this::exportPackageDocStats);
+ for (PackageDocStats packageDoc : getStats().getPackagesDocStats()) {
+ getWriter().printf("%-26s: \t%11d Undocumented: %6d Documented: %6d (%.2f%%)\n",
+ packageDoc.getType() + " " + packageDoc.getName(),
+ packageDoc.getNumberOfDocumentableMembers(), packageDoc.getUndocumentedMembersOfElement(),
+ packageDoc.getNumberOfDocumentedMembers(), packageDoc.getDocumentedMembersPercent());
+ exportClassesDocStats(packageDoc);
+ }
getWriter().println();
}
- private void exportPkgsOrClassesDocStats(MembersDocStats packagesDocStats) {
- getWriter().printf("%-26s: \t%11d Undocumented: %6d Documented: %6d (%.2f%%)\n",
- packagesDocStats.getType(), packagesDocStats.getMembersNumber(), packagesDocStats.getUndocumentedMembers(),
- packagesDocStats.getDocumentedMembers(), packagesDocStats.getDocumentedMembersPercent());
- }
-
- /**
- * Exports the statistics about JavaDoc coverage of a given package.
- * @param doc the object containing the JavaDoc coverage data
- *
- */
- private void exportPackageDocStats(final PackageDoc doc) {
- getWriter().printf("\tPackage %s. Documented: %s\n", doc.name(), Utils.isNotStringEmpty(doc.commentText()));
- }
-
- @Override
- protected void exportClassesDocStats() {
- final ClassesDocStats classesDocStats = getStats().getClassesDocStats();
- exportPkgsOrClassesDocStats(classesDocStats);
-
- for (final ClassDocStats classStats : getStats().getClassesDocStats().getClassesList()) {
+ private void exportClassesDocStats(PackageDocStats packageWithClasses) {
+ for (final ClassDocStats classStats : packageWithClasses.getClassDocs()) {
+ getWriter().printf("\t%s: %s Package: %s Documented: %s (%.2f%%)\n", classStats.getType(), classStats.getName(),
+ packageWithClasses.getName(), classStats.isDocumented(), classStats.getDocumentedMembersPercent());
exportClassDocStats(classStats);
}
getWriter().println();
@@ -89,14 +77,11 @@ protected void exportClassesDocStats() {
*
*/
private void exportClassDocStats(final ClassDocStats classStats) {
- getWriter().printf("\t%s: %s Package: %s Documented: %s (%.2f%%)\n",
- classStats.getType(), classStats.getName(), classStats.getPackageName(),
- classStats.isDocumented(), classStats.getDocumentedMembersPercent());
-
exportMembersDocStats(getWriter(), classStats.getFieldsStats());
+ exportMembersDocStats(getWriter(), classStats.getEnumsStats());
+ exportMembersDocStats(getWriter(), classStats.getAnnotationsStats());
exportMethodsDocStats(getWriter(), classStats.getConstructorsStats());
exportMethodsDocStats(getWriter(), classStats.getMethodsStats());
- exportMembersDocStats(getWriter(), classStats.getEnumsStats());
getWriter().flush();
}
@@ -108,7 +93,7 @@ private void exportMethodsDocStats(final PrintWriter writer, final List 0) {
+ if (methodStats.getThrownExceptionsStats().getNumberOfDocumentableMembers() > 0) {
exportMembersDocStats(writer, methodStats.getThrownExceptionsStats(), memberTypeFormat);
}
}
@@ -119,16 +104,16 @@ private void exportMembersDocStats(final PrintWriter writer, final MembersDocSta
}
private void exportMembersDocStats(final PrintWriter writer, final MembersDocStats membersDocStats, final String memberTypeFormat) {
- if (membersDocStats.getMembersNumber() == 0 && !membersDocStats.isPrintIfNoMembers()) {
+ if (membersDocStats.getNumberOfDocumentableMembers() == 0 && !membersDocStats.isPrintIfNoMembers()) {
return;
}
final String format = (Utils.isStringEmpty(memberTypeFormat) ? "\t\t%-20s" : memberTypeFormat) +
- " %6d Undocumented: %6d Documented: %6d (%.2f%%) \n";
+ " %6d Undocumented: %6d Documented: %6d (%.2f%%) \n";
writer.printf(format,
- membersDocStats.getType()+":", membersDocStats.getMembersNumber(),
- membersDocStats.getUndocumentedMembers(),
- membersDocStats.getDocumentedMembers(), membersDocStats.getDocumentedMembersPercent());
+ membersDocStats.getType() + ":", membersDocStats.getNumberOfDocumentableMembers(),
+ membersDocStats.getUndocumentedMembersOfElement(),
+ membersDocStats.getNumberOfDocumentedMembers(), membersDocStats.getDocumentedMembersPercent());
}
}
diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/exporter/DataExporter.java b/src/main/java/com/manoelcampos/javadoc/coverage/exporter/DataExporter.java
index 4100b24..264ac32 100644
--- a/src/main/java/com/manoelcampos/javadoc/coverage/exporter/DataExporter.java
+++ b/src/main/java/com/manoelcampos/javadoc/coverage/exporter/DataExporter.java
@@ -15,8 +15,6 @@
*/
package com.manoelcampos.javadoc.coverage.exporter;
-import com.manoelcampos.javadoc.coverage.CoverageDoclet;
-
/**
* An interface to implement JavaDoc Coverage reports in different formats such as HTML, CSV, JSON, etc.
*
@@ -24,14 +22,6 @@
* @since 1.0.0
*/
public interface DataExporter {
- /**
- * The name to be used as default for the JavaDoc Coverage report if
- * a specific name is not given.
- *
- * @see CoverageDoclet#OUTPUT_NAME_OPTION
- */
- String DEFAULT_OUTPUT_NAME = "javadoc-coverage";
-
/**
* Gets the actual name to be used for the JavaDoc Coverage Report,
* whether the default or given one.
diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/exporter/HtmlExporter.java b/src/main/java/com/manoelcampos/javadoc/coverage/exporter/HtmlExporter.java
index dd12c80..bfa2cb6 100644
--- a/src/main/java/com/manoelcampos/javadoc/coverage/exporter/HtmlExporter.java
+++ b/src/main/java/com/manoelcampos/javadoc/coverage/exporter/HtmlExporter.java
@@ -15,14 +15,13 @@
*/
package com.manoelcampos.javadoc.coverage.exporter;
-import com.manoelcampos.javadoc.coverage.CoverageDoclet;
+import java.util.List;
+
import com.manoelcampos.javadoc.coverage.Utils;
-import com.manoelcampos.javadoc.coverage.stats.ClassDocStats;
-import com.manoelcampos.javadoc.coverage.stats.MembersDocStats;
-import com.manoelcampos.javadoc.coverage.stats.MethodDocStats;
-import com.sun.javadoc.PackageDoc;
+import com.manoelcampos.javadoc.coverage.configuration.Configuration;
+import com.manoelcampos.javadoc.coverage.stats.*;
-import java.util.List;
+import lombok.NonNull;
/**
* Exports the JavaDoc coverage report to an HTML file.
@@ -33,13 +32,16 @@
public class HtmlExporter extends AbstractDataExporter {
public static final String COLUMNS = "%s %s %s %s %s %s %.2f%% \n";
- public HtmlExporter(final CoverageDoclet doclet) {
- super(doclet, ".html");
+ public HtmlExporter(@NonNull final Configuration config, @NonNull JavaDocsStats stats) {
+ super(config, stats, ".html");
}
@Override
protected void exportProjectDocumentationCoverageSummary() {
- getWriter().printf("" + COLUMNS + " ", "Project Documentation Coverage ", "", "", "", "", "", getStats().getDocumentedMembersPercent());
+ JavaDocsStats stats = getStats();
+ getWriter().printf("" + COLUMNS + " ", "Project Documentation Coverage ", "", "",
+ stats.getNumberOfDocumentableMembers(), stats.getUndocumentedMembersOfElement(),
+ stats.getNumberOfDocumentedMembers(), stats.getDocumentedMembersPercent());
}
@Override
@@ -81,21 +83,27 @@ protected void footer() {
@Override
protected void exportPackagesDocStats() {
- exportMembersDocStatsSummary(getStats().getPackagesDocStats());
- for (final PackageDoc doc : getStats().getPackagesDocStats().getPackagesDoc()) {
+ for (final PackageDocStats doc : getStats().getPackagesDocStats()) {
getWriter().println("");
- final Boolean documented = Utils.isNotStringEmpty(doc.getRawCommentText());
- final double coverage = Utils.boolToInt(documented)*100;
- exportLine(2, "Package", doc.name(), "", "", "", documented.toString(), coverage);
+ exportLine(0, "Package", doc.getName(), "", doc.getNumberOfDocumentableMembers(), doc.getUndocumentedMembersOfElement(),
+ doc.getNumberOfDocumentedMembers(), doc.getDocumentedMembersPercent());
+ int isPackageDocumented = Utils.boolToInt(doc.isDocumented());
+ exportLine(2, "package-info.java", "", "", 1L, 1L - isPackageDocumented, (long) isPackageDocumented,
+ isPackageDocumented * 100.0);
+ exportClassesDocStats(doc);
}
}
- @Override
- protected void exportClassesDocStats() {
- exportMembersDocStatsSummary(getStats().getClassesDocStats());
- for (final ClassDocStats classDocStats : getStats().getClassesDocStats().getClassesList()) {
- exportMembersDocStatsSummary(classDocStats, 2, classDocStats.getName(), classDocStats.getPackageName());
+
+ private void exportClassesDocStats(PackageDocStats pkg) {
+ for (final ClassDocStats classDocStats : pkg.getClassDocs()) {
+ exportMembersDocStatsSummary(classDocStats, 2, classDocStats.getName(), pkg.getName());
+ int isClassDocumented = Utils.boolToInt(classDocStats.isDocumented());
+ exportLine(3, classDocStats.getType() + " Doc", "", "", 1L, 1L - isClassDocumented, (long) isClassDocumented,
+ isClassDocumented * 100.0);
+ exportMembersDocStatsSummary(classDocStats.getEnumsStats(), 3);
exportMembersDocStatsSummary(classDocStats.getFieldsStats(), 3);
+ exportMembersDocStatsSummary(classDocStats.getAnnotationsStats(), 3);
exportMethodsDocStats(classDocStats.getConstructorsStats());
exportMethodsDocStats(classDocStats.getMethodsStats());
}
@@ -104,6 +112,13 @@ protected void exportClassesDocStats() {
private void exportMethodsDocStats(final List methods) {
for (MethodDocStats m : methods) {
exportMembersDocStatsSummary(m, 4, m.getMethodName(), "");
+ int isMethodDocumented = Utils.boolToInt(m.isDocumented());
+ exportLine(5, m.getType() + " Doc", "", "", 1L, 1L - isMethodDocumented, (long) isMethodDocumented,
+ isMethodDocumented * 100.0);
+ if (!m.isVoidMethodOrConstructor()) {
+ int isReturnDocumented = Utils.boolToInt(m.isReturnDocumented());
+ exportLine(5, "Return Value", "", "", 1L, 1L - isReturnDocumented, (long) isReturnDocumented, isReturnDocumented * 100.0);
+ }
exportMembersDocStatsSummary(m.getParamsStats(), 5);
exportMembersDocStatsSummary(m.getThrownExceptionsStats(), 5);
}
@@ -113,20 +128,16 @@ private void exportMembersDocStatsSummary(final MembersDocStats membersDocStats,
exportMembersDocStatsSummary(membersDocStats, indentLevel, "","");
}
- private void exportMembersDocStatsSummary(final MembersDocStats membersDocStats) {
- exportMembersDocStatsSummary(membersDocStats, 1, "","");
- }
-
private void exportMembersDocStatsSummary(final MembersDocStats membersDocStats, final int indentLevel, final String name, final String pkg) {
- if(!membersDocStats.isPrintIfNoMembers() && membersDocStats.getMembersNumber() == 0){
+ if (!membersDocStats.isPrintIfNoMembers() && membersDocStats.getNumberOfDocumentableMembers() == 0) {
return;
}
exportLine(
indentLevel, membersDocStats.getType(), name, pkg,
- membersDocStats.getMembersNumber(),
- membersDocStats.getUndocumentedMembers(),
- membersDocStats.getDocumentedMembers(),
+ membersDocStats.getNumberOfDocumentableMembers(),
+ membersDocStats.getUndocumentedMembersOfElement(),
+ membersDocStats.getNumberOfDocumentedMembers(),
membersDocStats.getDocumentedMembersPercent());
}
diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassDocStats.java b/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassDocStats.java
index 1a6147d..7e2bf23 100644
--- a/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassDocStats.java
+++ b/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassDocStats.java
@@ -15,13 +15,12 @@
*/
package com.manoelcampos.javadoc.coverage.stats;
+import java.util.*;
+
import com.manoelcampos.javadoc.coverage.Utils;
+import com.manoelcampos.javadoc.coverage.configuration.Configuration;
import com.sun.javadoc.*;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
/**
* Computes statistics about the JavaDocs of a class, inner class, interface or enum
* and its members, such as: fields, methods, constructors and annotations.
@@ -33,8 +32,6 @@ public class ClassDocStats extends MembersDocStats {
/**
* This value is added to the number of elements in order to count the class itself as an element
* which can be documented.
- *
- * @see #getMembersNumber()
*/
private static final int CLASS_DOC = 1;
@@ -46,82 +43,51 @@ public class ClassDocStats extends MembersDocStats {
private List methodsStats;
private List constructorsStats;
- public ClassDocStats(final ClassDoc doc) {
+ public ClassDocStats(final ClassDoc doc, Configuration config) {
this.doc = doc;
- fieldsStats = new ClassMembersDocStats(doc.fields(false), "Fields");
- enumsStats = new ClassMembersDocStats(doc.enumConstants(), "Enum Consts");
- processMethodsDocsStats(doc);
- processConstructorsDocsStats(doc);
- processAnnotationsDocsStats(doc);
+ fieldsStats = new ClassMembersDocStats(doc.fields(false), "Fields", config);
+ enumsStats = new ClassMembersDocStats(doc.enumConstants(), "Enum Consts", config);
+ processMethodsDocsStats(doc, config.computePublicCoverageOnly());
+ processConstructorsDocsStats(doc, config.computePublicCoverageOnly());
+ processAnnotationsDocsStats(doc, config);
}
- private void processAnnotationsDocsStats(ClassDoc doc) {
+ private void processAnnotationsDocsStats(ClassDoc doc, Configuration config) {
if (doc instanceof AnnotationTypeDoc) {
- annotationsStats = new ClassMembersDocStats(((AnnotationTypeDoc) doc).elements(), "Annotations");
- } else annotationsStats = new ClassMembersDocStats(new AnnotationTypeElementDoc[0], "Annotations");
+ annotationsStats = new ClassMembersDocStats(((AnnotationTypeDoc) doc).elements(), "Annotations", config);
+ } else {
+ annotationsStats = new ClassMembersDocStats(new AnnotationTypeElementDoc[0], "Annotations", config);
+ }
}
- private void processConstructorsDocsStats(ClassDoc doc) {
+ private void processConstructorsDocsStats(ClassDoc doc, boolean computeOnlyForPublic) {
final ConstructorDoc[] constructors = doc.constructors(false);
- constructorsStats = new ArrayList<>(constructors.length);
+ constructorsStats = new ArrayList<>();
for (final ConstructorDoc constructor : constructors) {
- constructorsStats.add(new MethodDocStats(constructor));
+ if (!computeOnlyForPublic || constructor.isPublic()) {
+ constructorsStats.add(new MethodDocStats(constructor));
+ }
}
}
- private void processMethodsDocsStats(ClassDoc doc) {
+ private void processMethodsDocsStats(ClassDoc doc, boolean computeOnlyForPublic) {
final MethodDoc[] methods = doc.methods(false);
- methodsStats = new ArrayList<>(methods.length);
+ methodsStats = new ArrayList<>();
for (final MethodDoc method : methods) {
- methodsStats.add(new MethodDocStats(method));
+ if ((!computeOnlyForPublic || method.isPublic()) && isNoPredefinedEnumMethod(doc, method)) {
+ methodsStats.add(new MethodDocStats(method));
+ }
}
}
- @Override
- public long getDocumentedMembers() {
- return
- Utils.boolToInt(isDocumented()) +
- fieldsStats.getDocumentedMembers() +
- enumsStats.getDocumentedMembers() +
- getDocumentedMethodMembers(methodsStats) +
- getDocumentedMethodMembers(constructorsStats) +
- annotationsStats.getDocumentedMembers();
- }
-
- @Override
- public long getMembersNumber() {
- return CLASS_DOC +
- fieldsStats.getMembersNumber() +
- enumsStats.getMembersNumber() +
- getMethodMembers(methodsStats) +
- getMethodMembers(constructorsStats) +
- annotationsStats.getMembersNumber();
- }
-
- private long getDocumentedMethodMembers(final List methodOrConstructor) {
- return methodOrConstructor.stream().filter(MethodDocStats::isDocumented).count() +
- methodOrConstructor.stream().mapToLong(MethodDocStats::getDocumentedMembers).sum();
- }
-
- /**
- * Gets the amount of documentable members from a given list of methods/constructors.
- *
- * @param methodOrConstructor a list containing the methods and constructors to get their number of members
- * @return the total number of members for the given list of methods/constructors
- * @see MethodDocStats#getMembersNumber()
- */
- private long getMethodMembers(final List methodOrConstructor) {
- return methodOrConstructor.stream().mapToLong(MethodDocStats::getMembersNumber).sum();
+ private boolean isNoPredefinedEnumMethod(ClassDoc doc, final MethodDoc method) {
+ return !(doc.isEnum() && (method.name().equals("values") || method.name().equals("valueOf")));
}
public String getName() {
return doc.name();
}
- public String getPackageName() {
- return doc.containingPackage().name();
- }
-
@Override
public String getType() {
return doc.isInterface() ? "Interface" : doc.isEnum() ? "Enum" : "Class";
@@ -147,12 +113,32 @@ public List getConstructorsStats() {
return Collections.unmodifiableList(constructorsStats);
}
- public ClassDoc getDoc() {
- return doc;
- }
-
@Override
public boolean isDocumented() {
return Utils.isElementDocumented(doc.getRawCommentText());
}
+
+ @Override
+ public long getNumberOfDocumentedMembers() {
+ // @formatter:off
+ return constructorsStats.stream().mapToLong(DocStats::getNumberOfDocumentedMembers).sum()
+ + methodsStats.stream().mapToLong(DocStats::getNumberOfDocumentedMembers).sum()
+ + fieldsStats.getNumberOfDocumentedMembers()
+ + enumsStats.getNumberOfDocumentedMembers()
+ + annotationsStats.getNumberOfDocumentedMembers()
+ + (isDocumented() ? CLASS_DOC : 0);
+ // @formatter:on
+ }
+
+ @Override
+ public long getNumberOfDocumentableMembers() {
+ // @formatter:off
+ return constructorsStats.stream().mapToLong(DocStats::getNumberOfDocumentableMembers).sum()
+ + methodsStats.stream().mapToLong(DocStats::getNumberOfDocumentableMembers).sum()
+ + fieldsStats.getNumberOfDocumentableMembers()
+ + enumsStats.getNumberOfDocumentableMembers()
+ + annotationsStats.getNumberOfDocumentableMembers()
+ + CLASS_DOC;
+ // @formatter:on
+ }
}
diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassMembersDocStats.java b/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassMembersDocStats.java
index 311f7e3..caa05cd 100644
--- a/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassMembersDocStats.java
+++ b/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassMembersDocStats.java
@@ -15,12 +15,13 @@
*/
package com.manoelcampos.javadoc.coverage.stats;
-import com.manoelcampos.javadoc.coverage.Utils;
-import com.sun.javadoc.Doc;
-
import java.util.Arrays;
import java.util.Objects;
+import com.manoelcampos.javadoc.coverage.Utils;
+import com.manoelcampos.javadoc.coverage.configuration.Configuration;
+import com.sun.javadoc.*;
+
/**
* Computes JavaDoc coverage statistics for specific type of members belonging to an owner.
* An owner can be a class, interface or enum.
@@ -35,59 +36,75 @@ public class ClassMembersDocStats extends MembersDocStats {
*/
private final Doc[] membersDocs;
private final String membersType;
+ private final Configuration config;
/**
- * Instantiates an object to compute JavaDoc coverage statistics
- * for the members of a class, interface or enum.
+ * Instantiates an object to compute JavaDoc coverage statistics for the members of a class, interface or enum.
*
* @param membersDocs the JavaDoc documentation for the members of the owner.
* @param membersType the type of the members of the owner to compute JavaDoc coverage statistics.
+ * @param config the coverage configuration
+ *
*/
- ClassMembersDocStats(final Doc[] membersDocs, final String membersType) {
+ ClassMembersDocStats(final Doc[] membersDocs, final String membersType, Configuration config) {
this.membersDocs = membersDocs;
this.membersType = membersType;
+ this.config = config;
+ }
+
+ @Override
+ public String getType() {
+ return membersType;
}
/**
- * Gets the number of members which are explicitly declared into the source code,
- * from a list of given members.
+ * A set of class members doesn't have documentation, only each individual member may have.
*
- * The length of the given array cannot be used to this purpose
- * because some elements such as default no-args constructors are not directly declared
- * into the source class but are counted as a member.
- * This way, it may count as a non-documented element
- * while it doesn't even exist into the source code.
+ * @return always false
*/
@Override
- public long getMembersNumber() {
- /*
- * @todo the method is not working as expected. It always returns the length of the array.
- * The side-effect is that default no-args constructors (which aren't directly declared into
- * a class source code) will be computed as undocumented.
- */
- return Arrays.stream(membersDocs)
- .map(Doc::position)
- .filter(Objects::nonNull)
- .count();
+ public boolean isDocumented() {
+ return false;
}
+
@Override
- public long getDocumentedMembers() {
- return Arrays.stream(membersDocs).map(Doc::getRawCommentText).filter(Utils::isNotStringEmpty).count();
+ public long getNumberOfDocumentedMembers() {
+ // @formatter:off
+ return Arrays.stream(membersDocs)
+ .filter(this::filterPublicIfNecessary)
+ .map(Doc::getRawCommentText)
+ .filter(Utils::isNotStringEmpty)
+ .count();
+ // @formatter:on
}
@Override
- public String getType() {
- return membersType;
+ public long getNumberOfDocumentableMembers() {
+ /*
+ * default constructors are also counted here, this is correct, they will also appear in the generated javadoc, and have no
+ * dedicated information
+ */
+ // @formatter:off
+ return Arrays.stream(membersDocs)
+ .filter(this::filterPublicIfNecessary)
+ .map(Doc::position)
+ .filter(Objects::nonNull)
+ .count();
+ // @formatter:on
}
- /**
- * A set of class members doesn't have documentation,
- * only each individual member may have.
- * @return
- */
- @Override
- public boolean isDocumented() {
- return false;
+ private boolean filterPublicIfNecessary(Doc m) {
+ boolean computeOnlyForPublic = config.computePublicCoverageOnly();
+ if (computeOnlyForPublic) {
+ if (m instanceof ClassDoc) {
+ return !computeOnlyForPublic || ((ClassDoc) m).isPublic();
+ } else if (m instanceof ProgramElementDoc) {
+ return !computeOnlyForPublic || ((ProgramElementDoc) m).isPublic();
+ } else {
+ throw new UnsupportedOperationException("unimplemented for type " + m.getClass());
+ }
+ }
+ return true;
}
}
diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassesDocStats.java b/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassesDocStats.java
deleted file mode 100644
index 201e4c4..0000000
--- a/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassesDocStats.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright 2017-2017 Manoel Campos da Silva Filho
- *
- * Licensed under the General Public License Version 3 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.gnu.org/licenses/gpl-3.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.manoelcampos.javadoc.coverage.stats;
-
-import com.manoelcampos.javadoc.coverage.Utils;
-import com.sun.javadoc.ClassDoc;
-import com.sun.javadoc.Doc;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Computes JavaDoc coverage statistics for a list of classes.
- *
- * @author Manoel Campos da Silva Filho
- * @since 1.0.0
- */
-public class ClassesDocStats extends MembersDocStats {
- private final List classesDocStats;
-
- /**
- * Instantiates an object to compute JavaDoc coverage statistics for a list of classes.
- *
- * @param docs an array of elements which enables reading the classes' JavaDoc documentation
- */
- public ClassesDocStats(final ClassDoc[] docs){
- classesDocStats = new ArrayList<>(docs.length);
- for (final ClassDoc doc : docs) {
- classesDocStats.add(new ClassDocStats(doc));
- }
- }
-
- @Override
- public long getMembersNumber() {
- return classesDocStats.size();
- }
-
- @Override
- public String getType() {
- return "Classes/Interfaces/Enums";
- }
-
- @Override
- public long getDocumentedMembers() {
- return classesDocStats.stream().map(ClassDocStats::getDoc).map(Doc::getRawCommentText).filter(Utils::isNotStringEmpty).count();
- }
-
- /**
- * Gets a List where each element represents the individual JavaDoc coverage statistics for a specific class.
- *
- * @return a List of class's JavaDoc coverage statistics
- */
- public List getClassesList() {
- return Collections.unmodifiableList(classesDocStats);
- }
-
- /**
- * A set of classes doesn't have documentation,
- * only each individual class may have.
- * @return
- */
- @Override
- public boolean isDocumented() {
- return false;
- }
-}
diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/stats/DocStats.java b/src/main/java/com/manoelcampos/javadoc/coverage/stats/DocStats.java
index 694bf5f..11d789b 100644
--- a/src/main/java/com/manoelcampos/javadoc/coverage/stats/DocStats.java
+++ b/src/main/java/com/manoelcampos/javadoc/coverage/stats/DocStats.java
@@ -38,7 +38,15 @@ public interface DocStats {
*
* @return the number of members having JavaDoc documentation
*/
- long getDocumentedMembers();
+ long getNumberOfDocumentedMembers();
+
+ /**
+ * Gets the total number of members contained into the object for which the JavaDoc coverage statistics is being computed.
+ *
+ * @return the total number of members
+ */
+ long getNumberOfDocumentableMembers();
+
/**
* Gets the number of undocumented members contained into
@@ -46,8 +54,8 @@ public interface DocStats {
*
* @return the number of members not having JavaDoc documentation
*/
- default long getUndocumentedMembers() {
- return getMembersNumber() - getDocumentedMembers();
+ default long getUndocumentedMembersOfElement() {
+ return getNumberOfDocumentableMembers() - getNumberOfDocumentedMembers();
}
/**
@@ -57,14 +65,7 @@ default long getUndocumentedMembers() {
* @return the percentage of documented members, in scale from 0 to 100.
*/
default double getDocumentedMembersPercent(){
- return Utils.computePercentage(getDocumentedMembers(), getMembersNumber());
+ return Utils.computePercentage(getNumberOfDocumentedMembers(), getNumberOfDocumentableMembers());
}
- /**
- * Gets the total number of members contained into
- * the object for which the JavaDoc coverage statistics is being computed.
- *
- * @return the total number of members
- */
- long getMembersNumber();
}
diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/stats/JavaDocsStats.java b/src/main/java/com/manoelcampos/javadoc/coverage/stats/JavaDocsStats.java
index 3fd1f6a..58533d6 100644
--- a/src/main/java/com/manoelcampos/javadoc/coverage/stats/JavaDocsStats.java
+++ b/src/main/java/com/manoelcampos/javadoc/coverage/stats/JavaDocsStats.java
@@ -15,9 +15,10 @@
*/
package com.manoelcampos.javadoc.coverage.stats;
-import com.manoelcampos.javadoc.coverage.Utils;
-import com.sun.javadoc.ClassDoc;
-import com.sun.javadoc.RootDoc;
+import java.util.*;
+
+import com.manoelcampos.javadoc.coverage.configuration.Configuration;
+import com.sun.javadoc.*;
/**
* Computes JavaDoc coverage statistics for Java files received by the JavaDoc tool.
@@ -31,74 +32,55 @@
* @since 1.0.0
*/
public class JavaDocsStats implements DocStats {
- /**
- * Stores the root of the program structure information.
- */
- private final RootDoc rootDoc;
- private final PackagesDocStats packagesDocStats;
- private final ClassesDocStats classesDocStats;
+ private final List packagesDocStats;
/**
- * Instantiates an object to compute JavaDoc coverage statistics for all Java files
- * received by the JavaDoc tool.
+ * Instantiates an object to compute JavaDoc coverage statistics for all Java files received by the JavaDoc tool.
*
* @param rootDoc root element which enables reading JavaDoc documentation
+ * @param config the coverage configuration
*/
- public JavaDocsStats(final RootDoc rootDoc) {
- this.rootDoc = rootDoc;
- this.classesDocStats = new ClassesDocStats(rootDoc.classes());
- this.packagesDocStats = computePackagesDocsStats();
- }
+ public JavaDocsStats(final RootDoc rootDoc, Configuration config) {
+ this.packagesDocStats = new ArrayList<>();
- /**
- * Computes JavaDoc coverage statistics for detected packages.
- *
- * @return packages' JavaDoc coverage statistics
- */
- private PackagesDocStats computePackagesDocsStats() {
- final PackagesDocStats stats = new PackagesDocStats();
+ Map tmp = new HashMap<>();
for (final ClassDoc doc : rootDoc.classes()) {
- stats.addPackageDoc(doc.containingPackage());
- }
+ // add all packages regardless of public/whatever classes in it
+ if (!tmp.containsKey(doc.containingPackage())) {
+ PackageDocStats pkgDoc = new PackageDocStats(doc.containingPackage(), config);
+ tmp.put(doc.containingPackage(), pkgDoc);
+ }
- return stats;
+ // only add necessary classes depending on options
+ if (!config.computePublicCoverageOnly() || doc.isPublic()) {
+ tmp.get(doc.containingPackage()).addClass(doc);
+ }
+ }
+ packagesDocStats.addAll(tmp.values());
}
/**
* Gets the object containing JavaDoc coverage statistics for detected packages.
*
* @return packages' JavaDoc coverage statistics
- * @see #computePackagesDocsStats()
*/
- public PackagesDocStats getPackagesDocStats() {
+ public List getPackagesDocStats() {
return packagesDocStats;
}
- /**
- * Gets the object containing JavaDoc coverage statistics for detected classes.
- *
- * @return classes' JavaDoc coverage statistics
- */
- public ClassesDocStats getClassesDocStats() { return classesDocStats; }
-
@Override
public String getType() {
return "Project JavaDoc Statistics";
}
@Override
- public long getDocumentedMembers() {
- return packagesDocStats.getDocumentedMembers() + classesDocStats.getDocumentedMembers();
- }
-
- @Override
- public double getDocumentedMembersPercent() {
- return Utils.mean(packagesDocStats.getDocumentedMembersPercent(), classesDocStats.getDocumentedMembersPercent());
+ public long getNumberOfDocumentedMembers() {
+ return packagesDocStats.stream().mapToLong(DocStats::getNumberOfDocumentedMembers).sum();
}
@Override
- public long getMembersNumber() {
- return classesDocStats.getMembersNumber() + packagesDocStats.getMembersNumber();
+ public long getNumberOfDocumentableMembers() {
+ return packagesDocStats.stream().mapToLong(DocStats::getNumberOfDocumentableMembers).sum();
}
}
diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/stats/MethodDocStats.java b/src/main/java/com/manoelcampos/javadoc/coverage/stats/MethodDocStats.java
index 952f595..ea48caf 100644
--- a/src/main/java/com/manoelcampos/javadoc/coverage/stats/MethodDocStats.java
+++ b/src/main/java/com/manoelcampos/javadoc/coverage/stats/MethodDocStats.java
@@ -15,13 +15,16 @@
*/
package com.manoelcampos.javadoc.coverage.stats;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
import com.manoelcampos.javadoc.coverage.Utils;
+import com.sun.javadoc.ClassDoc;
import com.sun.javadoc.ExecutableMemberDoc;
import com.sun.javadoc.MethodDoc;
import com.sun.javadoc.Tag;
-import java.util.Arrays;
-
/**
* Computes JavaDoc coverage statistics for a method/constructor
* and its members, namely parameters and thrown exceptions.
@@ -34,7 +37,7 @@ public class MethodDocStats extends MembersDocStats {
* This value is added to the number of elements in order to count the method itself as an element
* which can be documented.
*
- * @see #getMembersNumber()
+ * @see #getMembersOfElement()
* @see #getDocumentedMembersPercent()
*/
private static final int METHOD_DOC = 1;
@@ -82,36 +85,50 @@ public MethodExceptionsDocStats getThrownExceptionsStats() {
return thrownExceptionsStats;
}
- @Override
- public long getDocumentedMembers() {
- final int returnCount = (!isVoidMethodOrConstructor() && isReturnDocumented()) ? 1 : 0;
- final long documentedMembers = Utils.boolToInt(isDocumented()) +
- paramsStats.getDocumentedMembers() +
- thrownExceptionsStats.getDocumentedMembers() +
- returnCount;
-
- /* If an overridden method isn't documented at all, it doesn't matter because
- * its documentation is optional. The superclass is accountable to document
- * the method. This way, the method is counted as completely documented.
- */
- if (isOverridden() && documentedMembers == 0) {
- return getMembersNumber();
- }
-
- return documentedMembers;
- }
-
- private boolean isReturnDocumented() {
+ public boolean isReturnDocumented() {
return Arrays.stream(doc.tags()).filter(t -> t.name().equals("@return")).map(Tag::text).anyMatch(Utils::isNotStringEmpty);
}
- private boolean isOverridden() {
- return doc.isMethod() && ((MethodDoc) doc).overriddenMethod() != null;
+ private boolean isOverriddenDocumented() {
+ if (doc.isMethod()) {
+ MethodDoc curMethod = (MethodDoc) doc;
+ Set allClassesToCheck = new HashSet<>();
+
+ // really use all interfaces, there might be interfaces extending interfaces
+ // such that this is needed
+ for (ClassDoc ifc : curMethod.containingClass().interfaces()) {
+ allClassesToCheck.add(ifc);
+ allClassesToCheck.addAll(getAllInterfaces(ifc));
+ }
+ ClassDoc superclass = curMethod.containingClass().superclass();
+ while (superclass != null) {
+ allClassesToCheck.add(superclass);
+ superclass = superclass.superclass();
+ }
+
+ for (ClassDoc potOverridden : allClassesToCheck) {
+ for (MethodDoc method : potOverridden.methods()) {
+ // only if overridden method is documented completely
+ // we assume that the overriding method doesn't need to be documented
+ MethodDocStats methodStats = new MethodDocStats(method);
+ if (curMethod.overrides(method)
+ && methodStats.getNumberOfDocumentedMembers() == methodStats.getNumberOfDocumentableMembers()) {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
}
- @Override
- public double getDocumentedMembersPercent() {
- return Utils.computePercentage(getDocumentedMembers(), getMembersNumber());
+ private Set getAllInterfaces(ClassDoc doc) {
+ Set ifcs = new HashSet<>();
+ for (ClassDoc ifc : doc.interfaces()) {
+ ifcs.add(ifc);
+ ifcs.addAll(getAllInterfaces(ifc));
+ }
+ return ifcs;
}
/**
@@ -120,7 +137,7 @@ public double getDocumentedMembersPercent() {
*
* @return true if the method is void or is a constructor, false otherwise
*/
- private boolean isVoidMethodOrConstructor() {
+ public boolean isVoidMethodOrConstructor() {
return isVoidMethod() || doc.isConstructor();
}
@@ -129,17 +146,41 @@ private boolean isVoidMethod() {
}
@Override
- public long getMembersNumber() {
- final int returnCount = isVoidMethodOrConstructor() ? 0 : 1;
+ public boolean isDocumented() {
+ return Utils.isElementDocumented(doc.getRawCommentText());
+ }
- return METHOD_DOC +
- paramsStats.getMembersNumber() +
- thrownExceptionsStats.getMembersNumber() +
- returnCount;
+ @Override
+ public long getNumberOfDocumentedMembers() {
+ final int returnCount = (!isVoidMethodOrConstructor() && isReturnDocumented()) ? 1 : 0;
+
+ // @formatter:off
+ final long documentedMembers = Utils.boolToInt(isDocumented())
+ + paramsStats.getNumberOfDocumentedMembers()
+ + thrownExceptionsStats.getNumberOfDocumentedMembers()
+ + returnCount;
+ // @formatter:on
+
+ /*
+ * If an overridden method isn't documented at all, it doesn't matter because its documentation is optional. The superclass is
+ * accountable to document the method. This way, the method is counted as completely documented.
+ */
+ if (isOverriddenDocumented() && documentedMembers == 0) {
+ return getNumberOfDocumentableMembers();
+ }
+
+ return documentedMembers;
}
@Override
- public boolean isDocumented() {
- return Utils.isElementDocumented(doc.getRawCommentText());
+ public long getNumberOfDocumentableMembers() {
+ final int returnCount = isVoidMethodOrConstructor() ? 0 : 1;
+
+ // @formatter:off
+ return METHOD_DOC +
+ paramsStats.getNumberOfDocumentableMembers() +
+ thrownExceptionsStats.getNumberOfDocumentableMembers() +
+ returnCount;
+ // @formatter:on
}
}
diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/stats/MethodExceptionsDocStats.java b/src/main/java/com/manoelcampos/javadoc/coverage/stats/MethodExceptionsDocStats.java
index 7104203..df23846 100644
--- a/src/main/java/com/manoelcampos/javadoc/coverage/stats/MethodExceptionsDocStats.java
+++ b/src/main/java/com/manoelcampos/javadoc/coverage/stats/MethodExceptionsDocStats.java
@@ -15,15 +15,15 @@
*/
package com.manoelcampos.javadoc.coverage.stats;
-import com.sun.javadoc.ClassDoc;
-import com.sun.javadoc.ExecutableMemberDoc;
-import com.sun.javadoc.Tag;
-
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;
+import com.sun.javadoc.ClassDoc;
+import com.sun.javadoc.ExecutableMemberDoc;
+import com.sun.javadoc.Tag;
+
/**
* Computes JavaDoc coverage statistics for the exceptions thrown by a specific method.
*
@@ -61,10 +61,10 @@ public String getType() {
* @return the total number of exceptions
*/
@Override
- public long getMembersNumber() {
+ public long getNumberOfDocumentableMembers() {
return getDeclaredButNotDocumentedExceptionsNumber() +
- getDocumentedButNotDeclaredExceptionsNumber() +
- getDeclaredAndDocumentedExceptionsNumber();
+ getDocumentedButNotDeclaredExceptionsNumber() +
+ getDeclaredAndDocumentedExceptionsNumber();
}
/**
@@ -80,7 +80,7 @@ public long getMembersNumber() {
*/
private long getDocumentedButNotDeclaredExceptionsNumber() {
return
- getDocumentedTagStream()
+ getDocumentedTagStream()
.filter(tag -> getDeclaredExceptionsStream().noneMatch(ex -> isExceptionEqualsToJavaDocTag(ex, tag)))
.count();
}
@@ -128,7 +128,7 @@ private boolean isExceptionEqualsToJavaDocTag(final ClassDoc exception, final Ta
even if the package is not included in the throws clause.
On the other hand, the JavaDoc tag used by a developer to document the
exception usually isn't prefixed with its package.
- */
+ */
return exception.toString().endsWith(getExceptionClassFromTag(tag));
}
diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/stats/MethodParamsDocStats.java b/src/main/java/com/manoelcampos/javadoc/coverage/stats/MethodParamsDocStats.java
index b139059..1cde9de 100644
--- a/src/main/java/com/manoelcampos/javadoc/coverage/stats/MethodParamsDocStats.java
+++ b/src/main/java/com/manoelcampos/javadoc/coverage/stats/MethodParamsDocStats.java
@@ -35,11 +35,6 @@ public class MethodParamsDocStats extends MethodTagsDocStats {
super(doc);
}
- @Override
- public long getMembersNumber() {
- return getDoc().parameters().length;
- }
-
@Override
public String getTagName() {
return "@param";
@@ -49,4 +44,9 @@ public String getTagName() {
public String getType() {
return "Params";
}
+
+ @Override
+ public long getNumberOfDocumentableMembers() {
+ return getDoc().parameters().length;
+ }
}
diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/stats/MethodTagsDocStats.java b/src/main/java/com/manoelcampos/javadoc/coverage/stats/MethodTagsDocStats.java
index 9146917..8600bb4 100644
--- a/src/main/java/com/manoelcampos/javadoc/coverage/stats/MethodTagsDocStats.java
+++ b/src/main/java/com/manoelcampos/javadoc/coverage/stats/MethodTagsDocStats.java
@@ -15,13 +15,13 @@
*/
package com.manoelcampos.javadoc.coverage.stats;
+import java.util.Arrays;
+import java.util.stream.Stream;
+
import com.manoelcampos.javadoc.coverage.Utils;
import com.sun.javadoc.ExecutableMemberDoc;
import com.sun.javadoc.Tag;
-import java.util.Arrays;
-import java.util.stream.Stream;
-
/**
* An abstract class to compute JavaDoc statistics for a set of tags
* associated to a method/constructor, such as the {@code @param} and {@code @throws} tags.
@@ -50,16 +50,15 @@ public abstract class MethodTagsDocStats extends MembersDocStats {
}
/**
- * Gets the name of the tag associated to this object for which
- * JavaDoc coverage statistics will be computed, for instance,
- * "param" or "throws" tags.
+ * Gets the name of the tag associated to this object for which JavaDoc coverage statistics will be computed, for instance, "param" or
+ * "throws" tags.
*
- * @return
+ * @return the tag name
*/
public abstract String getTagName();
@Override
- public long getDocumentedMembers() {
+ public long getNumberOfDocumentedMembers() {
return getDocumentedTagStream().count();
}
@@ -68,9 +67,11 @@ public long getDocumentedMembers() {
* @return the documented Tag Stream
*/
protected Stream getDocumentedTagStream() {
+ // @formatter:off
return Arrays.stream(getDoc().tags())
.filter(tag -> getTagName().equals(tag.name()))
.filter(tag -> Utils.isNotStringEmpty(tag.text()));
+ // @formatter:on
}
/**
@@ -83,10 +84,9 @@ protected ExecutableMemberDoc getDoc() {
}
/**
- * A set of tags doesn't have documentation.
- * Only each individual tag may have.
+ * A set of tags doesn't have documentation. Only each individual tag may have.
*
- * @return
+ * @return always false
*/
@Override
public boolean isDocumented() {
diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/stats/PackageDocStats.java b/src/main/java/com/manoelcampos/javadoc/coverage/stats/PackageDocStats.java
new file mode 100644
index 0000000..2f80199
--- /dev/null
+++ b/src/main/java/com/manoelcampos/javadoc/coverage/stats/PackageDocStats.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2017-2017 Manoel Campos da Silva Filho
+ *
+ * Licensed under the General Public License Version 3 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.gnu.org/licenses/gpl-3.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.manoelcampos.javadoc.coverage.stats;
+
+import java.util.*;
+
+import com.manoelcampos.javadoc.coverage.Utils;
+import com.manoelcampos.javadoc.coverage.configuration.Configuration;
+import com.sun.javadoc.ClassDoc;
+import com.sun.javadoc.PackageDoc;
+
+/**
+ * Computes JavaDoc statistics for a set of packages.
+ *
+ * @author Manoel Campos da Silva Filho
+ * @since 1.0.0
+ */
+public class PackageDocStats extends MembersDocStats {
+ private final PackageDoc packageDoc;
+ private final Configuration config;
+ private final List classDocs = new ArrayList<>();
+
+ public PackageDocStats(final PackageDoc doc, Configuration config) {
+ this.packageDoc = doc;
+ this.config = config;
+ }
+
+ /**
+ * Adds an element to the Set of elements containing packages' JavaDocs.
+ *
+ * @param doc the package's JavaDoc element to add to the Set
+ */
+ public void addClass(final ClassDoc doc) {
+ if (!packageDoc.equals(doc.containingPackage())) {
+ throw new IllegalArgumentException("Class is not in the correct package");
+ }
+ classDocs.add(new ClassDocStats(doc, config));
+ }
+
+ public List getClassDocs() {
+ return Collections.unmodifiableList(classDocs);
+ }
+
+ @Override
+ public String getType() {
+ return "Package";
+ }
+
+ public String getName() {
+ return packageDoc.name();
+ }
+
+ @Override
+ public long getNumberOfDocumentedMembers() {
+ return classDocs.stream().mapToLong(DocStats::getNumberOfDocumentedMembers).sum() + Utils.boolToInt(isDocumented());
+ }
+
+ @Override
+ public long getNumberOfDocumentableMembers() {
+ // +1 for the package-info documentation
+ return classDocs.stream().mapToLong(DocStats::getNumberOfDocumentableMembers).sum() + 1;
+ }
+
+ @Override
+ public boolean isDocumented() {
+ return Utils.isNotStringEmpty(packageDoc.getRawCommentText());
+ }
+
+}
diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/stats/PackagesDocStats.java b/src/main/java/com/manoelcampos/javadoc/coverage/stats/PackagesDocStats.java
deleted file mode 100644
index 7dc4d57..0000000
--- a/src/main/java/com/manoelcampos/javadoc/coverage/stats/PackagesDocStats.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright 2017-2017 Manoel Campos da Silva Filho
- *
- * Licensed under the General Public License Version 3 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.gnu.org/licenses/gpl-3.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.manoelcampos.javadoc.coverage.stats;
-
-import com.manoelcampos.javadoc.coverage.Utils;
-import com.sun.javadoc.PackageDoc;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Computes JavaDoc statistics for a set of packages.
- *
- * @author Manoel Campos da Silva Filho
- * @since 1.0.0
- */
-public class PackagesDocStats extends MembersDocStats {
- private final Set packagesDoc;
-
- public PackagesDocStats(){
- this.packagesDoc = new HashSet<>();
- }
-
- /**
- * Adds an element to the Set of elements containing packages' JavaDocs.
- *
- * @param doc the package's JavaDoc element to add to the Set
- */
- public void addPackageDoc(final PackageDoc doc){
- packagesDoc.add(doc);
- }
-
- @Override
- public String getType() {
- return "Packages";
- }
-
- @Override
- public long getMembersNumber() {
- return packagesDoc.size();
- }
-
- @Override
- public long getDocumentedMembers() {
- return packagesDoc.stream().map(PackageDoc::getRawCommentText).filter(Utils::isNotStringEmpty).count();
- }
-
- /**
- * Gets a Set of elements containing packages' JavaDocs.
- *
- * @return the Set of packages' JavaDocs
- */
- public Set getPackagesDoc() {
- return Collections.unmodifiableSet(packagesDoc);
- }
-
- /**
- * A set of packages doesn't have documentation,
- * only each individual package may have.
- * @return
- */
- @Override
- public boolean isDocumented() {
- return false;
- }
-}