You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by el...@apache.org on 2026/10/11 15:33:04 UTC
(maven-reporting-api) 01/01: Fix infinite recursion between the default generate() overloads
This is an automated email from the ASF dual-hosted git repository.
elharo pushed a commit to branch fix-91-generate-recursion
in repository https://gitbox.apache.org/repos/asf/maven-reporting-api.git
commit 4ca885e7314044b5aa6c2202068989e95f72cbeb
Author: Elliotte Rusty Harold <el...@ibiblio.org>
AuthorDate: Sun Oct 11 15:32:50 2026 +0000
Fix infinite recursion between the default generate() overloads
Both generate(Sink, Locale) and generate(Sink, SinkFactory, Locale) are
default methods that delegate to each other. An implementation
overriding neither recursed forever and failed with StackOverflowError
during report generation.
The multi-page generate(Sink, SinkFactory, Locale) now fails fast with a
MavenReportException when neither overload is overridden, while still
delegating to generate(Sink, Locale) for implementations that override
it. Implementations overriding either overload keep working unchanged.
Fixes #91
---
.../java/org/apache/maven/reporting/MavenReport.java | 19 ++++++++++++++++++-
.../org/apache/maven/reporting/MavenReportTest.java | 19 +++++++++++++++++++
2 files changed, 37 insertions(+), 1 deletion(-)
diff --git a/src/main/java/org/apache/maven/reporting/MavenReport.java b/src/main/java/org/apache/maven/reporting/MavenReport.java
index 454315e..9d6e0f8 100644
--- a/src/main/java/org/apache/maven/reporting/MavenReport.java
+++ b/src/main/java/org/apache/maven/reporting/MavenReport.java
@@ -66,14 +66,31 @@ public interface MavenReport {
* <p>
* A report that renders a single page ignores {@code sinkFactory}. A report that renders several
* pages uses {@code sinkFactory} to create the sinks for its sub-pages.
+ * <p>
+ * An implementation must override this method or the deprecated {@link #generate(Sink, Locale)}.
+ * If it overrides neither, this method throws a {@link MavenReportException} instead of
+ * recursing forever between the two default methods.
*
* @param sink the sink to use for the main page.
* @param sinkFactory the factory for sub-page sinks, or {@code null} when sub-pages cannot be created.
* @param locale the wanted locale to generate the report.
- * @throws MavenReportException if any
+ * @throws MavenReportException if any, or if neither this method nor {@link #generate(Sink, Locale)}
+ * is overridden
* @since 4.1.0
*/
default void generate(Sink sink, SinkFactory sinkFactory, Locale locale) throws MavenReportException {
+ try {
+ // Only delegate to the deprecated overload when it is actually overridden. Otherwise the
+ // two default methods would call each other until a StackOverflowError is thrown.
+ if (getClass().getMethod("generate", Sink.class, Locale.class).isDefault()) {
+ throw new MavenReportException(
+ "A MavenReport implementation must override generate(Sink, SinkFactory, Locale) "
+ + "or generate(Sink, Locale)");
+ }
+ } catch (NoSuchMethodException e) {
+ // generate(Sink, Locale) is declared by this interface, so it is always present.
+ throw new MavenReportException("Unable to determine the report generation method", e);
+ }
generate(sink, locale);
}
diff --git a/src/test/java/org/apache/maven/reporting/MavenReportTest.java b/src/test/java/org/apache/maven/reporting/MavenReportTest.java
index 4c66ba9..68d8fc5 100644
--- a/src/test/java/org/apache/maven/reporting/MavenReportTest.java
+++ b/src/test/java/org/apache/maven/reporting/MavenReportTest.java
@@ -28,6 +28,7 @@ import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertThrows;
class MavenReportTest {
@@ -101,6 +102,9 @@ class MavenReportTest {
}
}
+ /** A report that overrides neither of the generate methods. */
+ private static class NoGenerateReport extends RecordingReport {}
+
@Test
void multiPageCallReachesSinglePageImplementation() throws MavenReportException {
SinglePageReport report = new SinglePageReport();
@@ -122,4 +126,19 @@ class MavenReportTest {
assertNull(report.sinkFactory);
assertSame(LOCALE, report.locale);
}
+
+ @Test
+ void multiPageGenerateFailsFastWhenNeitherMethodIsOverridden() {
+ NoGenerateReport report = new NoGenerateReport();
+
+ assertThrows(MavenReportException.class, () -> report.generate(null, null, LOCALE));
+ }
+
+ @Test
+ @SuppressWarnings("deprecation")
+ void singlePageGenerateFailsFastWhenNeitherMethodIsOverridden() {
+ NoGenerateReport report = new NoGenerateReport();
+
+ assertThrows(MavenReportException.class, () -> report.generate(null, LOCALE));
+ }
}