This is an automated email from the ASF dual-hosted git repository.
arunpati pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/ofbiz-framework.git
The following commit(s) were added to refs/heads/trunk by this push:
new 0a3c77ace1 Fixed: Call to non-existing method in production run PDF
reports (OFBIZ-13504) (#1827)
0a3c77ace1 is described below
commit 0a3c77ace112bcc55dc0570a24af0dfb768be692
Author: toaditi <[email protected]>
AuthorDate: Wed Oct 7 18:32:14 2026 +0530
Fixed: Call to non-existing method in production run PDF reports
(OFBIZ-13504) (#1827)
## Credits
Thanks to **Carsten Heinrigs** for reporting OFBIZ-13504 and for
pinpointing both the
template and the method involved, which made this quick to pick up.
This follows up on the scope-reduction work in **OFBIZ-10478** by
**Jacques Le Roux**
and **Pradhan Yash Sharma**, reviewed by **Michael Brohl** -- a broad
and valuable
cleanup, in which this one method happened to have callers that static
analysis
could not see.
## The problem
`UtilDateTime.toDateString(Date, String)` was narrowed from `public` to
`private` in
commit `abb4ead2f6` (OFBIZ-10478). FreeMarker resolves `Static["..."]`
members
reflectively and therefore only sees public methods, so the templates
calling the
two-argument overload can no longer 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 in
an `.fo.ftl` it lands inside the FO XML.
## Why restore the method rather than edit the templates
The report originally suggested dropping the format string. That
resolves to the
single-argument overload, which is hardcoded to `MM/dd/yyyy`, so the
reports would
render without error but silently switch from day/month to month/day
order.
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.
That flexibility is really the crux of it: with the two-argument form
private, a
template that needs a particular format has no clean way to ask for one.
Restoring it
keeps the current output, fixes every call site at once, and leaves
custom templates in
existing deployments working, since they can call this documented helper
too.
## Call sites fixed (7, across 3 components)
- `applications/manufacturing/template/jobshopmgt/ProductionRun.fo.ftl`
(4)
-
`applications/manufacturing/template/reports/PRunsProductsAndOrder.fo.ftl:324`
-
`applications/manufacturing/template/reports/PRunsProductsStacks.fo.ftl:92`
- `applications/content/template/lookup/ContentTreeLookupList.ftl:85`
## Verification
Unit: new regression test in `FreeMarkerWorkerTests`, watched fail then
pass. It uses
9 March deliberately, so `dd/MM/yyyy` (09/03/2026) and `MM/dd/yyyy`
(03/09/2026)
differ -- the test therefore also fails if the format string is dropped.
`./gradlew test checkstyleMain codenarcMain javadoc` -- BUILD
SUCCESSFUL,
854 tests, 0 failures, 0 errors, 0 skipped.
Runtime: a production run was created through `createProductionRun` with
a start
date of 2026-03-09, then `PrintProductionRun` fetched over HTTP, with
only the
one-word change differing between the two runs.
Worth noting that the broken case does not fail. Both runs return HTTP
200 and a
structurally valid one page `application/pdf`. The difference is what is
printed
in the date fields:
| | before | after |
| --- | --- | --- |
| HTTP | 200 | 200 |
| bytes | 6668 | 6276 |
| Estimated Start Date | `Java method "static ...toDateString(Date)"
takes 1 argument, but 2 was given` followed by an FTL stack trace |
`09/03/2026` |
So the report currently prints Java internals where the schedule dates
belong,
while the response itself still looks healthy.
`release24.09` carries the same private modifier and the same call
sites, so it
likely needs the same change -- happy to raise a backport if that seems
right.
---
.../org/apache/ofbiz/base/util/UtilDateTime.java | 15 ++++++++++++--
.../base/util/template/FreeMarkerWorkerTests.java | 23 ++++++++++++++++++++++
2 files changed, 36 insertions(+), 2 deletions(-)
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 ded8bc626e..fcdc5bcbf1 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 214c05b692..1b5ef0e72f 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.jupiter.api.Assertions.assertEquals;
import java.io.StringWriter;
+import java.sql.Timestamp;
import java.util.HashMap;
import java.util.Map;
@@ -41,4 +42,26 @@ public final 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());
+ }
}