This is an automated email from the ASF dual-hosted git repository.
ddekany pushed a commit to branch 2.3-gae
in repository https://gitbox.apache.org/repos/asf/freemarker.git
The following commit(s) were added to refs/heads/2.3-gae by this push:
new 204d76ab Add fine-grained mixed-content support to markup output
formats.
new 836903b6 Merge pull request #83 from nolaviz/nolaviz-devel
204d76ab is described below
commit 204d76ab82a01bce1935029b81a2dfae06dc1a0c
Author: Alon Ziv <[email protected]>
AuthorDate: Wed Aug 24 09:29:00 2022 +0000
Add fine-grained mixed-content support to markup output formats.
---
.../freemarker/core/CombinedMarkupOutputFormat.java | 5 +++++
src/main/java/freemarker/core/DollarVariable.java | 10 +++++++---
.../java/freemarker/core/MarkupOutputFormat.java | 8 ++++++++
src/main/java/freemarker/core/OutputFormat.java | 20 +++++++++++++-------
src/test/java/freemarker/core/DummyOutputFormat.java | 18 +++++++++++++++++-
src/test/java/freemarker/core/OutputFormatTest.java | 9 +++++++++
6 files changed, 59 insertions(+), 11 deletions(-)
diff --git a/src/main/java/freemarker/core/CombinedMarkupOutputFormat.java
b/src/main/java/freemarker/core/CombinedMarkupOutputFormat.java
index fd1e8233..a8a6b85c 100644
--- a/src/main/java/freemarker/core/CombinedMarkupOutputFormat.java
+++ b/src/main/java/freemarker/core/CombinedMarkupOutputFormat.java
@@ -69,6 +69,11 @@ public final class CombinedMarkupOutputFormat extends
CommonMarkupOutputFormat<T
outer.output(inner.escapePlainText(textToEsc), out);
}
+ @Override
+ public <MO2 extends TemplateMarkupOutputModel<MO2>> void outputForeign(MO2
mo, Writer out) throws IOException, TemplateModelException {
+ outer.outputForeign(mo, out);
+ }
+
@Override
public String escapePlainText(String plainTextContent) throws
TemplateModelException {
return outer.escapePlainText(inner.escapePlainText(plainTextContent));
diff --git a/src/main/java/freemarker/core/DollarVariable.java
b/src/main/java/freemarker/core/DollarVariable.java
index 12fa02a4..6823a5ad 100644
--- a/src/main/java/freemarker/core/DollarVariable.java
+++ b/src/main/java/freemarker/core/DollarVariable.java
@@ -73,7 +73,9 @@ final class DollarVariable extends Interpolation {
final TemplateMarkupOutputModel mo = (TemplateMarkupOutputModel)
moOrStr;
final MarkupOutputFormat moOF = mo.getOutputFormat();
// ATTENTION: Keep this logic in sync. ?esc/?noEsc's logic!
- if (moOF != outputFormat &&
!outputFormat.isOutputFormatMixingAllowed()) {
+ if (moOF == outputFormat) {
+ moOF.output(mo, out);
+ } else if (!outputFormat.isOutputFormatMixingAllowed()) {
final String srcPlainText;
// ATTENTION: Keep this logic in sync. ?esc/?noEsc's logic!
srcPlainText = moOF.getSourcePlainText(mo);
@@ -83,11 +85,13 @@ final class DollarVariable extends Interpolation {
" format, which differs from the current output
format, ",
new _DelayedToString(outputFormat), ". Format
conversion wasn't possible.");
}
- if (outputFormat instanceof MarkupOutputFormat) {
- ((MarkupOutputFormat) outputFormat).output(srcPlainText,
out);
+ if (markupOutputFormat != null) {
+ markupOutputFormat.output(srcPlainText, out);
} else {
out.write(srcPlainText);
}
+ } else if (markupOutputFormat != null) {
+ markupOutputFormat.outputForeign(mo, out);
} else {
moOF.output(mo, out);
}
diff --git a/src/main/java/freemarker/core/MarkupOutputFormat.java
b/src/main/java/freemarker/core/MarkupOutputFormat.java
index 81ffe8b2..352a1228 100644
--- a/src/main/java/freemarker/core/MarkupOutputFormat.java
+++ b/src/main/java/freemarker/core/MarkupOutputFormat.java
@@ -81,6 +81,14 @@ public abstract class MarkupOutputFormat<MO extends
TemplateMarkupOutputModel> e
*/
public abstract void output(String textToEsc, Writer out) throws
IOException, TemplateModelException;
+ /**
+ * Outputs a value from a foreign output format; only used if {@link
#isOutputFormatMixingAllowed()} is true.
+ * By default will just let the other output format handle the value, but
can be overridden to support more nuanced conversions.
+ */
+ public <MO2 extends TemplateMarkupOutputModel<MO2>> void outputForeign(MO2
mo, Writer out) throws IOException, TemplateModelException {
+ mo.getOutputFormat().output(mo, out);
+ }
+
/**
* If this {@link TemplateMarkupOutputModel} was created with {@link
#fromPlainTextByEscaping(String)}, it returns
* the original plain text, otherwise it returns {@code null}. Useful for
converting between different types
diff --git a/src/main/java/freemarker/core/OutputFormat.java
b/src/main/java/freemarker/core/OutputFormat.java
index 8ab52da0..eb7d6486 100644
--- a/src/main/java/freemarker/core/OutputFormat.java
+++ b/src/main/java/freemarker/core/OutputFormat.java
@@ -46,13 +46,19 @@ public abstract class OutputFormat {
/**
* Tells if this output format allows inserting {@link
TemplateMarkupOutputModel}-s of another output formats into
- * it. If {@code true}, the foreign {@link TemplateMarkupOutputModel} will
be inserted into the output as is (like
- * if the surrounding output format was the same). This is usually a bad
idea to allow, as such an event could
- * indicate application bugs. If this method returns {@code false}
(recommended), then FreeMarker will try to
- * assimilate the inserted value by converting its format to this format,
which will currently (2.3.24) cause
- * exception, unless the inserted value is made by escaping plain text and
the target format is non-escaping, in
- * which case format conversion is trivially possible. (It's not
impossible that conversions will be extended beyond
- * this, if there will be demand for that.)
+ * it.
+ *
+ * <p>If {@code true}, the foreign {@link TemplateMarkupOutputModel} will
be inserted into the output. If the current
+ * output format is a {@link MarkupOutputFormat} this is done using the
+ * {@link MarkupOutputFormat#outputForeign(TemplateMarkupOutputModel,
Writer)} method, which can implement smart
+ * conversions. The default behavior (and the only behavior for non-markup
outputs) is to behave as if the surrounding
+ * output format was the same; this is usually a bad idea to allow, as
such an event could
+ * indicate application bugs.
+ *
+ * <p>If this method returns {@code false} (recommended), then FreeMarker
will try to assimilate the inserted value by
+ * converting its format to this format, which will currently (2.3.24)
cause exception, unless the inserted value is
+ * made by escaping plain text and the target format is non-escaping, in
which case format conversion is trivially
+ * possible. (It's not impossible that conversions will be extended beyond
this, if there will be demand for that.)
*
* <p>
* {@code true} value is used by {@link UndefinedOutputFormat}.
diff --git a/src/test/java/freemarker/core/DummyOutputFormat.java
b/src/test/java/freemarker/core/DummyOutputFormat.java
index c37f45e5..78186dae 100644
--- a/src/test/java/freemarker/core/DummyOutputFormat.java
+++ b/src/test/java/freemarker/core/DummyOutputFormat.java
@@ -22,6 +22,8 @@ import java.io.IOException;
import java.io.Writer;
import freemarker.template.TemplateModelException;
+import freemarker.core._TemplateModelException;
+import freemarker.core._DelayedToString;
public class DummyOutputFormat extends
CommonMarkupOutputFormat<TemplateDummyOutputModel> {
@@ -46,6 +48,20 @@ public class DummyOutputFormat extends
CommonMarkupOutputFormat<TemplateDummyOut
out.write(escapePlainText(textToEsc));
}
+ @Override
+ public boolean isOutputFormatMixingAllowed() {
+ return true;
+ }
+
+ @Override
+ public <MO extends TemplateMarkupOutputModel<MO>> void outputForeign(MO
mo, Writer out) throws IOException, TemplateModelException {
+ if (mo.getOutputFormat().getMimeType().equals("text/html")) {
+ mo.getOutputFormat().output(mo, out);
+ } else {
+ throw new _TemplateModelException("DummyOutputFormat is
incompatible with ", new _DelayedToString(mo.getOutputFormat()));
+ }
+ }
+
@Override
public String escapePlainText(String plainTextContent) {
return plainTextContent.replaceAll("(\\.|\\\\)", "\\\\$1");
@@ -61,4 +77,4 @@ public class DummyOutputFormat extends
CommonMarkupOutputFormat<TemplateDummyOut
return new TemplateDummyOutputModel(plainTextContent, markupContent);
}
-}
\ No newline at end of file
+}
diff --git a/src/test/java/freemarker/core/OutputFormatTest.java
b/src/test/java/freemarker/core/OutputFormatTest.java
index 0c72faa6..1856166c 100644
--- a/src/test/java/freemarker/core/OutputFormatTest.java
+++ b/src/test/java/freemarker/core/OutputFormatTest.java
@@ -744,6 +744,15 @@ public class OutputFormatTest extends TemplateTest {
"convention", "#noAutoEsc", "#noautoesc");
}
+ @Test
+ public void testMixedContent() throws Exception {
+
getConfiguration().setRegisteredCustomOutputFormats(Collections.singleton(DummyOutputFormat.INSTANCE));
+ addToDataModel("m1", HTMLOutputFormat.INSTANCE.fromMarkup("x"));
+ addToDataModel("m2", XMLOutputFormat.INSTANCE.fromMarkup("y"));
+ assertOutput("<#ftl outputFormat='dummy'>${m1}", "x");
+ assertErrorContains("<#ftl outputFormat='dummy'>${m2}", "is
incompatible with");
+ }
+
@Test
public void testExplicitAutoEscBannedForNonMarkup() throws Exception {
// While this restriction is technically unnecessary, we can catch a
dangerous and probably common user