This is an automated email from the ASF dual-hosted git repository.
arunpati pushed a commit to branch release24.09
in repository https://gitbox.apache.org/repos/asf/ofbiz-framework.git
The following commit(s) were added to refs/heads/release24.09 by this push:
new f74f3df897 Fixed: Call to non-existing method in production run PDF
reports (OFBIZ-13504) [release24.09] (#1828)
f74f3df897 is described below
commit f74f3df89776d5b80d5f8b20fe926889e8baaeb4
Author: toaditi <[email protected]>
AuthorDate: Wed Oct 7 18:32:26 2026 +0530
Fixed: Call to non-existing method in production run PDF reports
(OFBIZ-13504) [release24.09] (#1828)
Backport of #1827 to `release24.09`.
## Credits
Thanks to **Carsten Heinrigs** for reporting OFBIZ-13504 and for naming
both the
template and the method in the report.
This follows on from **OFBIZ-10478** by **Jacques Le Roux** and
**Pradhan Yash Sharma**,
reviewed by **Michael Brohl** — a broad and worthwhile cleanup, in which
this one method
happened to have all of its callers in templates, where static analysis
could not see them.
## The problem
`UtilDateTime.toDateString(Date, String)` is reached from templates
through
`Static["org.apache.ofbiz.base.util.UtilDateTime"]`. FreeMarker resolves
those members
reflectively and so sees public methods only, so narrowing the
two-argument overload to
private left the templates unable to resolve it:
```
Java method "static
org.apache.ofbiz.base.util.UtilDateTime.toDateString(Date)"
takes 1 argument, but 2 was given.
```
The render does not throw — that message is written *into* the output
stream. So the
report still returns HTTP 200 and a structurally valid PDF, with a
FreeMarker stack trace
printed where the dates belong.
`release24.09` carries the same modifier and the same seven call sites
as trunk:
`ProductionRun.fo.ftl` (4), `PRunsProductsAndOrder.fo.ftl:324`,
`PRunsProductsStacks.fo.ftl:92` and `ContentTreeLookupList.ftl:85`.
Restoring the overload to public keeps the rendered format unchanged.
Dropping the format
string in the templates instead would fall back to the single-argument
overload and
silently move the reports from `dd/MM/yyyy` to `MM/dd/yyyy`.
This was discussed on the Jira issue, and **Carsten Heinrigs, who
reported it, agreed that
restoring the method is the better route**, adding that he values being
able to specify the
date format string. With the two-argument form private, a template that
needs a particular
format has no clean way to ask for one.
## Two differences from the trunk PR, both deliberate
**1. The test is JUnit 4**, matching this branch, rather than the
Jupiter version on trunk.
**2. There is a one-line `build.gradle` change.** The `test` task here
lists the JUnit
classes it runs explicitly, and `FreeMarkerWorkerTests` was not among
them — so the test
already in that class was never executed. Without the added `include`,
the new regression
test would sit in the tree and never run, which would be worse than not
adding it. It is
called out separately here so it is easy to drop if you would rather
leave the task list
untouched.
## Verification
The test asserts `09/03/2026`, a date whose `dd/MM/yyyy` and
`MM/dd/yyyy` forms differ, so
it also fails if the format string is dropped rather than the method
restored. It was
watched failing before the change and passing after, on this branch,
against the
FreeMarker 2.3.35 this branch now pins.
`./gradlew test checkstyleMain codenarcMain codenarcTest javadoc` — all
pass, 25 tests,
0 failures, 0 errors.
The trunk change in #1827 was additionally verified by creating a
production run and
fetching `PrintProductionRun` over HTTP before and after, which is what
confirmed the
"valid PDF containing a stack trace" behaviour described above. That
runtime check was not
repeated here, since the code path and the fix are identical.
---
build.gradle | 1 +
.../org/apache/ofbiz/base/util/UtilDateTime.java | 15 ++++++++++++--
.../base/util/template/FreeMarkerWorkerTests.java | 23 ++++++++++++++++++++++
3 files changed, 37 insertions(+), 2 deletions(-)
diff --git a/build.gradle b/build.gradle
index 41d54f0c53..7128ac12f8 100644
--- a/build.gradle
+++ b/build.gradle
@@ -373,6 +373,7 @@ test {
include 'org/apache/ofbiz/test/TestServices.class'
include
'org/apache/ofbiz/base/util/string/FlexibleStringExpanderBaseCodeTests.class'
include 'org/apache/ofbiz/base/util/FileUtilTests.class'
+ include 'org/apache/ofbiz/base/util/template/FreeMarkerWorkerTests.class'
jvmArgs "-javaagent:${classpath.find { it.name.contains('jmockit')
}.absolutePath}"
}
diff --git
a/framework/base/src/main/java/org/apache/ofbiz/base/util/UtilDateTime.java
b/framework/base/src/main/java/org/apache/ofbiz/base/util/UtilDateTime.java
index 9ced64d53a..169c9f6bca 100644
--- a/framework/base/src/main/java/org/apache/ofbiz/base/util/UtilDateTime.java
+++ b/framework/base/src/main/java/org/apache/ofbiz/base/util/UtilDateTime.java
@@ -582,11 +582,22 @@ public final class UtilDateTime {
}
/**
- * Makes a date String in the given from a Date
+ * Makes a date String in the given format from a Date.
+ *
+ * <p>This overload has no callers in Java code. It is reached from
FreeMarker templates
+ * through {@code Static["org.apache.ofbiz.base.util.UtilDateTime"]},
which resolves members
+ * reflectively and therefore only sees public ones, so it must stay
public. Narrowing it to
+ * private broke the production run reports (OFBIZ-13504); the failure is
quiet, because
+ * FreeMarker writes the resolution error into the rendered output rather
than throwing.
+ * Templates rely on passing an explicit pattern here: the single argument
overload is fixed
+ * to {@code MM/dd/yyyy}, so dropping the pattern silently changes the
rendered date order.</p>
+ *
* @param date The Date
+ * @param format The date format pattern, as understood by {@link
SimpleDateFormat}; the locale
+ * default format is used when null
* @return A date String in the given format
*/
- private static String toDateString(java.util.Date date, String format) {
+ public static String toDateString(java.util.Date date, String format) {
if (date == null) {
return "";
}
diff --git
a/framework/base/src/test/java/org/apache/ofbiz/base/util/template/FreeMarkerWorkerTests.java
b/framework/base/src/test/java/org/apache/ofbiz/base/util/template/FreeMarkerWorkerTests.java
index 27ef6050d3..e421391f67 100644
---
a/framework/base/src/test/java/org/apache/ofbiz/base/util/template/FreeMarkerWorkerTests.java
+++
b/framework/base/src/test/java/org/apache/ofbiz/base/util/template/FreeMarkerWorkerTests.java
@@ -21,6 +21,7 @@ package org.apache.ofbiz.base.util.template;
import static org.junit.Assert.assertEquals;
import java.io.StringWriter;
+import java.sql.Timestamp;
import java.util.HashMap;
import java.util.Map;
@@ -41,4 +42,26 @@ public class FreeMarkerWorkerTests {
FreeMarkerWorker.renderTemplateFromString("template1", "Hello
${name}", context, out, 0, false);
assertEquals("Hello World!", out.toString());
}
+
+ /**
+ * OFBIZ-13504: report templates format dates through
+ * {@code Static["...UtilDateTime"].toDateString(date, format)}.
FreeMarker resolves
+ * {@code Static[...]} members reflectively against public methods only,
so the two-argument
+ * overload must stay publicly visible for those templates to render.
+ *
+ * <p>The date below is deliberately the 9th of the 3rd month: {@code
dd/MM/yyyy} yields
+ * 09/03/2026 while {@code MM/dd/yyyy} yields 03/09/2026. The assertion
therefore also fails if
+ * the explicit format is dropped in favour of the single-argument
overload, which silently
+ * switches the reports to US date order.</p>
+ */
+ @Test
+ public void renderTemplateCallingToDateStringWithExplicitFormat() throws
Exception {
+ StringWriter out = new StringWriter();
+ Map<String, Object> context = new HashMap<>();
+ context.put("aDate", Timestamp.valueOf("2026-03-09 14:30:00"));
+ FreeMarkerWorker.renderTemplateFromString("templateToDateString",
+
"${Static[\"org.apache.ofbiz.base.util.UtilDateTime\"].toDateString(aDate,
\"dd/MM/yyyy\")}",
+ context, out, 0, false);
+ assertEquals("09/03/2026", out.toString());
+ }
}