From c8e392ee2f9b80e3ef92e83b981214c5275f8119 Mon Sep 17 00:00:00 2001 From: Oliver Becker Date: Sat, 19 Jun 2021 13:13:55 +0200 Subject: [PATCH] Introduce DefaultHtmlBuilder to have a central and easy to use entry point for configuring the HTML rendering, and to hide the details of FlatHtml and IndentedHtml. Adds static methods in Indenter for easy changing the indent depth. This commits also adds @Deprecated annotations to some methods and fields that should be removed in a future version of the library, namely - some static fields of Config - the public visibility of FlatHtml and IndentedHtml --- library/src/main/java/j2html/Config.java | 26 +++- .../j2html/rendering/DefaultHtmlBuilder.java | 125 ++++++++++++++++++ .../main/java/j2html/rendering/FlatHtml.java | 6 + .../java/j2html/rendering/HtmlBuilder.java | 3 + .../java/j2html/rendering/IndentedHtml.java | 6 + .../main/java/j2html/tags/ContainerTag.java | 11 +- .../src/main/java/j2html/tags/EmptyTag.java | 7 +- .../src/main/java/j2html/tags/Renderable.java | 8 +- library/src/main/java/j2html/tags/Text.java | 5 +- .../main/java/j2html/tags/UnescapedText.java | 5 +- .../src/main/java/j2html/utils/Indenter.java | 11 ++ .../rendering/RenderingCompatabilityTest.java | 8 +- .../src/test/java/j2html/tags/TextTest.java | 14 +- 13 files changed, 198 insertions(+), 37 deletions(-) create mode 100644 library/src/main/java/j2html/rendering/DefaultHtmlBuilder.java diff --git a/library/src/main/java/j2html/Config.java b/library/src/main/java/j2html/Config.java index fbac933d..d015a6c4 100644 --- a/library/src/main/java/j2html/Config.java +++ b/library/src/main/java/j2html/Config.java @@ -7,14 +7,14 @@ import j2html.utils.Minifier; import j2html.utils.TextEscaper; -import java.util.Collections; - public class Config { /** * Change this to configure text-escaping * For example, to disable escaping, do {@code Config.textEscaper = text -> text;} + * @deprecated in favor of {@link j2html.rendering.DefaultHtmlBuilder#withTextEscaper(TextEscaper)} */ + @Deprecated public static TextEscaper textEscaper = EscapeUtil::escape; /** * Change this to configure css-minification. @@ -29,14 +29,18 @@ public class Config { /** * Change this to configure enable/disable closing empty tags * The default is to NOT close them + * @deprecated in favor of {@link j2html.rendering.DefaultHtmlBuilder#withEmptyTagsClosed(boolean)} */ + @Deprecated public static boolean closeEmptyTags = false; - private static String FOUR_SPACES = " "; + /** * Change this to configure indentation when rendering formatted html * The default is four spaces + * @deprecated in favor of {@link j2html.rendering.DefaultHtmlBuilder#withIndenter(Indenter)} */ - public static Indenter indenter = (level, text) -> String.join("", Collections.nCopies(level, FOUR_SPACES)) + text; + @Deprecated + public static Indenter indenter = Indenter.defaults(); private TextEscaper _textEscaper; @@ -93,6 +97,10 @@ public Indenter indenter() { return _indenter; } + /** + * @deprecated in favor of {@link j2html.rendering.DefaultHtmlBuilder#withTextEscaper(TextEscaper)} + */ + @Deprecated public Config withTextEscaper(TextEscaper textEscaper){ Config copy = new Config(this); copy._textEscaper = textEscaper; @@ -111,12 +119,20 @@ public Config withJsMinifier(Minifier jsMinifier){ return copy; } + /** + * @deprecated in favor of {@link j2html.rendering.DefaultHtmlBuilder#withEmptyTagsClosed(boolean)} + */ + @Deprecated public Config withEmptyTagsClosed(boolean closeEmptyTags){ Config copy = new Config(this); copy._closeEmptyTags = closeEmptyTags; return copy; } + /** + * @deprecated in favor of {@link j2html.rendering.DefaultHtmlBuilder#withIndenter(Indenter)} + */ + @Deprecated public Config withIndenter(Indenter indenter){ Config copy = new Config(this); copy._indenter = indenter; @@ -128,7 +144,7 @@ public Config withIndenter(Indenter indenter){ CSSMin::compressCss, JSMin::compressJs, false, - (level, text) -> String.join("", Collections.nCopies(level, FOUR_SPACES)) + text + Indenter.defaults() ); public static final Config defaults() { diff --git a/library/src/main/java/j2html/rendering/DefaultHtmlBuilder.java b/library/src/main/java/j2html/rendering/DefaultHtmlBuilder.java new file mode 100644 index 00000000..c98fc35f --- /dev/null +++ b/library/src/main/java/j2html/rendering/DefaultHtmlBuilder.java @@ -0,0 +1,125 @@ +package j2html.rendering; + +import j2html.Config; +import j2html.utils.Indenter; +import j2html.utils.TextEscaper; + +/** + * Default entry point for constructing an {@link HtmlBuilder} instance. + * Examples: + * + *
+ * HtmlTag html = ...
+ * Appendable out = ...
+ * html.render(DefaultHtmlBuilder.into(out));
+ * 
+ * + * will write the HTML into {@code out} without any line breaks or indentation + * using the default settings of {@link Config#defaults()}. + *

+ * + *

+ * html.render(DefaultHtmlBuilder.indented(true).into(out));
+ * 
+ * + * will write the HTML into {@code out} with line breaks and indentation using + * the default settings and the indenter {@link Indenter#defaults()}. + *

+ * + *

+ * html.render(DefaultHtmlBuilder.indented(true).withIndenter(Indenter.with("\t")).into(out));
+ * 
+ * + * will use the tab character {@code \t} for indentation. + *

+ * A different {@link TextEscaper} can be provided using + * {@link #withTextEscaper(TextEscaper)}, a different setting for the closing of + * empty tags can be applied with {@link #withEmptyTagsClosed(boolean)}. + *

+ * There is also a convenience method {@link #inMemory()} for rendering the HTML + * into a String: + * + *

+ * String text = html.render(DefaultHtmlBuilder.with...().inMemory()).toString();
+ * 
+ */ +public class DefaultHtmlBuilder { + + public static HtmlBuilder into(A out) { + return new Configurer().into(out); + } + + public static HtmlBuilder inMemory() { + return into(new StringBuilder()); + } + + public static Configurer indented(boolean indented) { + return new Configurer().indented(indented); + } + + public static Configurer withEmptyTagsClosed(boolean closeTags) { + return new Configurer().withEmptyTagsClosed(closeTags); + } + + public static Configurer withTextEscaper(TextEscaper textEscaper) { + return new Configurer().withTextEscaper(textEscaper); + } + + public static Configurer withIndenter(Indenter indenter) { + return new Configurer().withIndenter(indenter); + } + + /** + * @deprecated will be removed in a future version + */ + @Deprecated + public static Configurer withConfig(Config config) { + return new Configurer(config); + } + + public static class Configurer { + private boolean indented; + private Config config; + + private Configurer() { + this(Config.defaults()); + } + + private Configurer(Config config) { + this.config = config; + this.indented = false; + } + + @SuppressWarnings("deprecation") + public HtmlBuilder into(A out) { + return this.indented ? IndentedHtml.into(out, this.config) : FlatHtml.into(out, this.config); + } + + public HtmlBuilder inMemory() { + return into(new StringBuilder()); + } + + public Configurer indented(boolean indented) { + this.indented = indented; + return this; + } + + @SuppressWarnings("deprecation") + public Configurer withEmptyTagsClosed(boolean closeTags) { + this.config = this.config.withEmptyTagsClosed(closeTags); + return this; + } + + @SuppressWarnings("deprecation") + public Configurer withTextEscaper(TextEscaper textEscaper) { + this.config = this.config.withTextEscaper(textEscaper); + return this; + } + + @SuppressWarnings("deprecation") + public Configurer withIndenter(Indenter indenter) { + this.config = this.config.withIndenter(indenter); + return this; + } + } +} diff --git a/library/src/main/java/j2html/rendering/FlatHtml.java b/library/src/main/java/j2html/rendering/FlatHtml.java index f674d02d..2d815283 100644 --- a/library/src/main/java/j2html/rendering/FlatHtml.java +++ b/library/src/main/java/j2html/rendering/FlatHtml.java @@ -9,7 +9,10 @@ * Composes HTML without any extra line breaks or indentation. * * @param The type of the Appendable to which HTML will be appended. + * + * @deprecated in favor of {@link DefaultHtmlBuilder} */ +// should be made package private in 2.0 public class FlatHtml implements HtmlBuilder { /** @@ -20,6 +23,7 @@ public class FlatHtml implements HtmlBuilder { * @param The type of the Appendable to which HTML will be appended. * @return An HtmlBuilder for flat HTML. */ + @Deprecated public static final FlatHtml into(T out) { return new FlatHtml<>(out, Config.defaults()); } @@ -43,6 +47,7 @@ public static final FlatHtml into(T out, Config config * * @return An HtmlBuilder for flat HTML. */ + @Deprecated public static final FlatHtml inMemory() { return into(new StringBuilder()); } @@ -53,6 +58,7 @@ public static final FlatHtml inMemory() { * @param config The Config which will specify text escapement, tag closing, etc. * @return An HtmlBuilder for flat HTML. */ + @Deprecated public static final FlatHtml inMemory(Config config) { return into(new StringBuilder(), config); } diff --git a/library/src/main/java/j2html/rendering/HtmlBuilder.java b/library/src/main/java/j2html/rendering/HtmlBuilder.java index c1490027..fff2a34f 100644 --- a/library/src/main/java/j2html/rendering/HtmlBuilder.java +++ b/library/src/main/java/j2html/rendering/HtmlBuilder.java @@ -7,6 +7,9 @@ * Appendable, and support appending HTML-specific character * sequences to that Appendable. *

+ * This library provides configurable implementations for flat and + * indented HTML, which can be obtained from the {@link DefaultHtmlBuilder}. + *

* Note: HtmlBuilder extends Appendable for compatibility with * previous version of this library. This extension will probably be * removed in the future, so avoid relying on the deprecated methods diff --git a/library/src/main/java/j2html/rendering/IndentedHtml.java b/library/src/main/java/j2html/rendering/IndentedHtml.java index 53c36f4a..1000dd9b 100644 --- a/library/src/main/java/j2html/rendering/IndentedHtml.java +++ b/library/src/main/java/j2html/rendering/IndentedHtml.java @@ -12,7 +12,10 @@ * Composes HTML with lines breaks and indentation between tags and text. * * @param The type of the Appendable to which HTML will be appended. + * + * @deprecated in favor of {@link DefaultHtmlBuilder} */ +// should be made package private in 2.0 public class IndentedHtml implements HtmlBuilder { /** @@ -23,6 +26,7 @@ public class IndentedHtml implements HtmlBuilder { * @param The type of the Appendable to which HTML will be appended. * @return An HtmlBuilder for indented HTML. */ + @Deprecated public static final IndentedHtml into(T out) { return new IndentedHtml<>(out, Config.defaults()); } @@ -46,6 +50,7 @@ public static final IndentedHtml into(T out, Config co * * @return An HtmlBuilder for indented HTML. */ + @Deprecated public static final IndentedHtml inMemory() { return into(new StringBuilder()); } @@ -57,6 +62,7 @@ public static final IndentedHtml inMemory() { * @param config The Config which will specify indentation, text escapement, tag closing, etc. * @return An HtmlBuilder for indented HTML. */ + @Deprecated public static final IndentedHtml inMemory(Config config) { return into(new StringBuilder(), config); } diff --git a/library/src/main/java/j2html/tags/ContainerTag.java b/library/src/main/java/j2html/tags/ContainerTag.java index 5fc688b0..900d6dae 100644 --- a/library/src/main/java/j2html/tags/ContainerTag.java +++ b/library/src/main/java/j2html/tags/ContainerTag.java @@ -2,11 +2,9 @@ import j2html.Config; import j2html.attributes.Attribute; -import j2html.rendering.TagBuilder; -import j2html.rendering.FlatHtml; +import j2html.rendering.DefaultHtmlBuilder; import j2html.rendering.HtmlBuilder; -import j2html.rendering.IndentedHtml; - +import j2html.rendering.TagBuilder; import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -145,9 +143,10 @@ public int getNumChildren() { * * @return the rendered and formatted string */ + @SuppressWarnings("deprecation") public String renderFormatted() { try { - return render(IndentedHtml.into(new StringBuilder(), Config.global())).toString(); + return render(DefaultHtmlBuilder.withConfig(Config.global()).indented(true).inMemory()).toString(); }catch (IOException e) { throw new RuntimeException(e.getMessage(), e); } @@ -179,7 +178,7 @@ public A render(HtmlBuilder builder, Object model) thr public void renderModel(Appendable writer, Object model) throws IOException { HtmlBuilder builder = (writer instanceof HtmlBuilder) ? (HtmlBuilder) writer - : FlatHtml.into(writer, Config.global()); + : DefaultHtmlBuilder.withConfig(Config.global()).into(writer); render(builder, model); } diff --git a/library/src/main/java/j2html/tags/EmptyTag.java b/library/src/main/java/j2html/tags/EmptyTag.java index e2b4ed02..eebf81d3 100644 --- a/library/src/main/java/j2html/tags/EmptyTag.java +++ b/library/src/main/java/j2html/tags/EmptyTag.java @@ -2,10 +2,9 @@ import j2html.Config; import j2html.attributes.Attribute; -import j2html.rendering.TagBuilder; -import j2html.rendering.FlatHtml; +import j2html.rendering.DefaultHtmlBuilder; import j2html.rendering.HtmlBuilder; - +import j2html.rendering.TagBuilder; import java.io.IOException; public class EmptyTag> extends Tag { @@ -35,7 +34,7 @@ public A render(HtmlBuilder builder, Object model) thr public void renderModel(Appendable writer, Object model) throws IOException { HtmlBuilder builder = (writer instanceof HtmlBuilder) ? (HtmlBuilder) writer - : FlatHtml.into(writer, Config.global()); + : DefaultHtmlBuilder.withConfig(Config.global()).into(writer); render(builder, model); } diff --git a/library/src/main/java/j2html/tags/Renderable.java b/library/src/main/java/j2html/tags/Renderable.java index 67ea012a..10fd99fe 100644 --- a/library/src/main/java/j2html/tags/Renderable.java +++ b/library/src/main/java/j2html/tags/Renderable.java @@ -1,9 +1,8 @@ package j2html.tags; import j2html.Config; -import j2html.rendering.FlatHtml; +import j2html.rendering.DefaultHtmlBuilder; import j2html.rendering.HtmlBuilder; - import java.io.IOException; import java.io.UncheckedIOException; @@ -42,9 +41,10 @@ default T render(HtmlBuilder builder) throws IOExcepti * Create a StringBuilder and use it to render the Renderable and it's * children */ + @SuppressWarnings("deprecation") default String render() { try { - return render(FlatHtml.into(new StringBuilder(), Config.global())).toString(); + return render(DefaultHtmlBuilder.withConfig(Config.global()).inMemory()).toString(); } catch (IOException e) { throw new UncheckedIOException(e); } @@ -60,7 +60,7 @@ default void render(Appendable writer) throws IOException { if (writer instanceof HtmlBuilder) { render((HtmlBuilder) writer); } else { - render(FlatHtml.into(writer, Config.global())); + render(DefaultHtmlBuilder.withConfig(Config.global()).into(writer)); } } diff --git a/library/src/main/java/j2html/tags/Text.java b/library/src/main/java/j2html/tags/Text.java index 8a512ec4..71a4dfc7 100644 --- a/library/src/main/java/j2html/tags/Text.java +++ b/library/src/main/java/j2html/tags/Text.java @@ -1,9 +1,8 @@ package j2html.tags; import j2html.Config; -import j2html.rendering.FlatHtml; +import j2html.rendering.DefaultHtmlBuilder; import j2html.rendering.HtmlBuilder; - import java.io.IOException; public class Text extends DomContent { @@ -25,7 +24,7 @@ public T render(HtmlBuilder builder, Object model) thr public void renderModel(Appendable writer, Object model) throws IOException { HtmlBuilder builder = (writer instanceof HtmlBuilder) ? (HtmlBuilder) writer - : FlatHtml.into(writer, Config.global()); + : DefaultHtmlBuilder.withConfig(Config.global()).into(writer); render(builder, model); } diff --git a/library/src/main/java/j2html/tags/UnescapedText.java b/library/src/main/java/j2html/tags/UnescapedText.java index 55674f36..5bb8474a 100644 --- a/library/src/main/java/j2html/tags/UnescapedText.java +++ b/library/src/main/java/j2html/tags/UnescapedText.java @@ -1,9 +1,8 @@ package j2html.tags; import j2html.Config; -import j2html.rendering.FlatHtml; +import j2html.rendering.DefaultHtmlBuilder; import j2html.rendering.HtmlBuilder; - import java.io.IOException; public class UnescapedText extends DomContent { @@ -25,7 +24,7 @@ public T render(HtmlBuilder builder, Object model) thr public void renderModel(Appendable writer, Object model) throws IOException { HtmlBuilder builder = (writer instanceof HtmlBuilder) ? (HtmlBuilder) writer - : FlatHtml.into(writer, Config.global()); + : DefaultHtmlBuilder.withConfig(Config.global()).into(writer); render(builder, model); } diff --git a/library/src/main/java/j2html/utils/Indenter.java b/library/src/main/java/j2html/utils/Indenter.java index 379e6e9f..54580967 100644 --- a/library/src/main/java/j2html/utils/Indenter.java +++ b/library/src/main/java/j2html/utils/Indenter.java @@ -1,6 +1,17 @@ package j2html.utils; +import java.util.Collections; + @FunctionalInterface public interface Indenter { + String indent(int level, String text); + + static Indenter with(String indentString) { + return (level, text) -> String.join("", Collections.nCopies(level, indentString)) + text; + } + + static Indenter defaults() { + return with(" "); + } } diff --git a/library/src/test/java/j2html/rendering/RenderingCompatabilityTest.java b/library/src/test/java/j2html/rendering/RenderingCompatabilityTest.java index e8fb5a35..1adcd69c 100644 --- a/library/src/test/java/j2html/rendering/RenderingCompatabilityTest.java +++ b/library/src/test/java/j2html/rendering/RenderingCompatabilityTest.java @@ -68,7 +68,7 @@ public void renderModel(Appendable writer, Object model) throws IOException { // Rendering with an HtmlBuilder defers to the original methods. assertThat( - dom.render(FlatHtml.inMemory(), "success").toString(), + dom.render(DefaultHtmlBuilder.inMemory(), "success").toString(), is("

success
") ); } @@ -85,19 +85,19 @@ public void client_classes_which_implement_attribute_rendering_continue_to_work_ assertThat(stringBuilder.toString(), is(" mock=\"null\"")); assertThat( - mock.render(FlatHtml.inMemory(), "success").toString(), + mock.render(DefaultHtmlBuilder.inMemory(), "success").toString(), is(" mock=\"success\"") ); // In empty tags. assertThat( - input().attr(mock).render(FlatHtml.inMemory(), "success").toString(), + input().attr(mock).render(DefaultHtmlBuilder.inMemory(), "success").toString(), is("") ); // In container tags. assertThat( - div().attr(mock).render(FlatHtml.inMemory(), "success").toString(), + div().attr(mock).render(DefaultHtmlBuilder.inMemory(), "success").toString(), is("
") ); } diff --git a/library/src/test/java/j2html/tags/TextTest.java b/library/src/test/java/j2html/tags/TextTest.java index 359a185a..6b88b150 100644 --- a/library/src/test/java/j2html/tags/TextTest.java +++ b/library/src/test/java/j2html/tags/TextTest.java @@ -1,10 +1,8 @@ package j2html.tags; -import j2html.rendering.FlatHtml; -import j2html.rendering.IndentedHtml; -import org.junit.Test; - +import j2html.rendering.DefaultHtmlBuilder; import java.io.IOException; +import org.junit.Test; import static j2html.TagCreator.rawHtml; import static j2html.TagCreator.text; @@ -15,13 +13,13 @@ public class TextTest { @Test public void null_text_is_rendered_as_a_string_literal() throws IOException { - assertThat(text(null).render(FlatHtml.inMemory()).toString(), is("null")); - assertThat(text(null).render(IndentedHtml.inMemory()).toString(), is("null\n")); + assertThat(text(null).render(DefaultHtmlBuilder.inMemory()).toString(), is("null")); + assertThat(text(null).render(DefaultHtmlBuilder.indented(true).inMemory()).toString(), is("null\n")); } @Test public void null_unescaped_text_is_rendered_as_a_string_literal() throws IOException { - assertThat(rawHtml(null).render(FlatHtml.inMemory()).toString(), is("null")); - assertThat(rawHtml(null).render(IndentedHtml.inMemory()).toString(), is("null\n")); + assertThat(rawHtml(null).render(DefaultHtmlBuilder.inMemory()).toString(), is("null")); + assertThat(rawHtml(null).render(DefaultHtmlBuilder.indented(true).inMemory()).toString(), is("null\n")); } }