105 Commits

Author SHA1 Message Date
David
023922a7db [maven-release-plugin] prepare release j2html-1.4.0 2019-01-24 14:42:55 +01:00
David
00c0461669 Auto format project 2019-01-24 14:24:21 +01:00
Robin Karlsson
cd6e0084ef Add Stream<DomContent> variants of each and with (#118) 2018-05-20 21:45:36 +02:00
Moandji Ezana
764b5d7759 Add TagCreator::each(Map, BiFunction) (#115) 2018-05-07 00:18:36 +02:00
David
d9c4963ff0 bump version 2018-05-01 12:29:02 +02:00
David
3ec15d28a5 woops 2018-05-01 12:28:13 +02:00
Moandji Ezana
f1680464d1 Do not indent textarea contents (#113)
* Do not indent textarea contents.

Fixes #102

* Restore import style

* Handle <pre> and TagCreator::each
2018-05-01 02:06:45 +02:00
Matthias
f497b5c8b5 support osgi meta data (#112) 2018-04-17 23:54:31 +02:00
Matthias
f212895eb2 Let each() take Map in addition to Collection (#110)
* add support for maps for 'each' method.

* add missing imports.
2018-04-16 20:11:37 +02:00
Rupert Madden-Abbott
62cafb9b31 Allow nulls in join() (fix #109)
* Discard nulls in join.

* Add test.
2018-04-16 20:07:11 +02:00
David
af7c986dd6 reorder asserts in each/fitler test 2018-02-05 01:36:46 +01:00
David
3aaab8b0fe unignore tests 2018-02-05 01:34:45 +01:00
David
cf9558b6ab fix formatting 2018-02-05 01:14:29 +01:00
Paul N. Baker
f87f9d8647 Overloaded method of iff for java8 Optional<>'s. (Includes test) (#103)
Using an optional as a condition is really tricky. Even if the optional is not present, the right value of ifValue must be evaluated eagerly in order to be passed to the method. Passing a lambda function for ifFunction allows the value to be evaluated lazily. This avoids the need to manually map and "elseGet" a null value to preserve current functionality.
2018-01-17 22:10:21 +01:00
David
b42ba41697 Update README.md 2017-12-31 12:25:35 +01:00
David
0c7f75f5b8 Update README.md 2017-12-31 12:25:05 +01:00
Janning Vygen
754003ebf6 Add attr(Attribute attribute) to Tag 2017-12-10 16:50:15 +01:00
David
6968478894 add multiplication-table to perf-test 2017-12-08 19:36:41 +01:00
David
0b92a963e9 add some ignored performance-tests 2017-12-07 22:10:34 +01:00
David
ac92facca7 Update README.md 2017-12-06 18:11:29 +01:00
David
4cf16320ad [maven-release-plugin] prepare for next development iteration 2017-12-06 17:04:20 +01:00
David
7d9ad230c1 [maven-release-plugin] prepare release j2html-1.2.2 2017-12-06 17:03:56 +01:00
David
7ebf4792b4 auto format 2017-12-06 14:08:24 +01:00
Janning Vygen
889fd2a3ac Add renderModel(writer, model) to Renderable (#93) 2017-12-06 14:04:13 +01:00
David
4acda0c6bb auto format project 2017-12-05 19:46:47 +01:00
Janning Vygen
17dac2871e Pass StringBuilder around instead of returning/concating strings (#88)
- Also remove retrolambda
2017-12-05 19:40:14 +01:00
David
1bfceaa62c Auto-format project (#92) 2017-12-02 12:17:32 +01:00
Janning Vygen
13134d042a Add Eclipse formatting config (#91) 2017-12-02 11:57:32 +01:00
Janning Vygen
b808d70a0d Addin root=true to .editorconfig (#90) 2017-12-02 11:47:24 +01:00
David
b068024070 Rewrite escaper-performance-test 2017-12-02 00:37:38 +01:00
David
5448c41887 Add basic editorconfig 2017-12-02 00:26:11 +01:00
Janning Vygen
d853c9cb1e Adding a performance test for https://github.com/tipsy/j2html/issues/86 (#87)
* Fix for https://github.com/tipsy/j2html/issues/79

* Adding PerformanceTest to measure execution time of rendering and GC

Signed-off-by: Janning Vygen <vygen@kicktipp.de>
2017-12-01 19:55:17 +01:00
David
eff53e073f Update README.md 2017-11-28 00:14:12 +01:00
David
98d7a6e912 [maven-release-plugin] prepare for next development iteration 2017-11-28 00:05:42 +01:00
David
eb3f28a09f [maven-release-plugin] prepare release j2html-1.2.1 2017-11-28 00:05:25 +01:00
David
368241313d Allow reading static resources from jars 2017-11-27 19:41:20 +01:00
David
4288924f8f Fix greedy semi-colon stripper bug in CSSMin
If CSSMin encounters a CSS-rule without a semi-colon at the end,
it will strip one char too many from that rule. This commit fixes that.
2017-11-27 12:54:07 +01:00
Janning Vygen
9948095c08 Fix for https://github.com/tipsy/j2html/issues/80 (#82)
* Fix for https://github.com/tipsy/j2html/issues/79

* Fix for https://github.com/tipsy/j2html/issues/80
2017-11-10 16:11:58 +01:00
Janning Vygen
56090046b5 Fix for https://github.com/tipsy/j2html/issues/79 (#81) 2017-11-10 16:07:20 +01:00
Thomas Tanon
d45af42650 Adds Tag.withLang and Tag.withDir (#76)
* Adds Tag.withLang and Tag.withDir

Allows easiest addition of mixed languages

* Add withCond(Lang|Dir)
2017-10-23 14:21:29 +02:00
David
7d65f91f44 Fix javadoc bug 2017-09-03 11:30:05 +02:00
David
aecf5e71d6 Update README.md 2017-09-03 11:26:10 +02:00
David
cf47772c89 [maven-release-plugin] prepare for next development iteration 2017-09-03 11:16:05 +02:00
David
897c53d830 [maven-release-plugin] prepare release j2html-1.2.0 2017-09-03 11:15:46 +02:00
David
1e29d81107 Fix another javadoc violation 2017-09-03 11:14:41 +02:00
David
dee3efb8e7 Remove javadoc violation 2017-09-03 11:08:36 +02:00
David
ee82201dfb Misc cleanup
- Add javadoc to Config
- Make CSSMin/JSMin configurable (add Minifier interface)
- Change SimpleEscaper back to a util
2017-09-02 19:41:37 +02:00
David
691680ea51 Add simple formatter (fixed #65)
* Add simple formatter
* Create Indenter interface
* Shorten variable-names in renderFormatted
* Fix javadoc
2017-09-02 19:05:48 +02:00
David
0853692e80 Use diamond operator 2017-09-01 20:50:20 +02:00
David
c2bc4b3209 Add @FunctionalInterface annotation to TextEscaper 2017-09-01 20:40:57 +02:00
David
ff9d138f63 Add option to close empty tags (fixes #52) 2017-09-01 20:39:23 +02:00
David
f778f4df3c Add convenience method for title (fixes #71) 2017-09-01 20:12:47 +02:00
David
a0b060ac42 Let attr() take object value (fixes #57) 2017-09-01 20:09:10 +02:00
David
4161be67bb Fix escaper-test 2017-09-01 20:07:48 +02:00
David
863527f684 Update README.md 2017-08-14 17:58:37 +02:00
David
5ef2dd3ec5 [maven-release-plugin] prepare for next development iteration 2017-08-14 17:45:23 +02:00
David
fc3bb29b6a [maven-release-plugin] prepare release j2html-1.1.0 2017-08-14 17:45:02 +02:00
Sergey Bezkostnyi
ef5777e54a Add ability to change text escaper implementation (#70) 2017-08-14 17:10:02 +02:00
David
cfc1489399 Merge pull request #63 from maztan/master
Add method to get number of children of ContainerTag
2017-07-29 19:19:08 +02:00
Ed Savailonei
8112dad1bb Add methd to get number of children of ContainerTag 2017-07-03 12:41:10 +02:00
David
235dec78ed Merge pull request #62 from kiru/patch-1
Updaate Gradle Version
2017-05-19 23:05:12 +02:00
Kiru
6316dd2262 Updaate Gradle Version 2017-05-19 21:57:04 +02:00
David
5667d7c68d Update README.md 2017-05-16 18:49:27 +02:00
David
13911d5f57 [maven-release-plugin] prepare for next development iteration 2017-05-16 18:00:33 +02:00
David
0bc6e274db [maven-release-plugin] prepare release j2html-1.0.0 2017-05-16 18:00:10 +02:00
David
325afd463c Fix version 2017-05-16 17:58:03 +02:00
David
f331eb9eb3 Merge pull request #61 from EthanDRaymond/DomContentJoiner-Does-Not-Use-Delimiter
Fixed a bug (maybe) where a delimiter was not being used
2017-05-12 22:45:10 +02:00
Ethan Raymond
d37dc1cac6 Fixed a bug (maybe) where a delimiter was not being used. 2017-05-12 15:39:23 -04:00
David
dab61bd662 [maven-release-plugin] prepare for next development iteration 2017-05-03 19:57:56 +02:00
David
d559f05903 [maven-release-plugin] prepare release j2html-1.0.0-RC 2017-05-03 19:57:31 +02:00
David
97a8f34572 Make filereader java6 compatible, because why not 2017-05-02 22:39:59 +02:00
David
6305e364ca Experimental Java6/Java7 support 2017-05-02 03:12:17 +02:00
David
28ba518b12 Fix name collision + minor cleanup 2017-05-01 19:10:42 +02:00
David
5f04cde97c Merge pull request #56 from tipsy/id-class-shorthand
Add shorthand notation for id/class
2017-05-01 18:59:11 +02:00
David
b00ba50133 Add attrs method to tagcreator 2017-05-01 18:51:04 +02:00
David
e09918da12 Add missing test-case to attr.shortform 2017-05-01 18:06:10 +02:00
David
55b74e81aa Improve generics in Attr.addTo 2017-05-01 16:54:05 +02:00
David
75deeff13d Remove unwanted import 2017-05-01 16:29:22 +02:00
David
3aa05aa540 Merge branch 'master' into id-class-shorthand 2017-05-01 16:15:01 +02:00
David
fb24d1eabf Merge pull request #55 from chmuche/empty-attribute
Empty attribute
2017-05-01 15:50:07 +02:00
David
458f3baf98 Merge pull request #54 from chmuche/gradle-dependency
Add Gradle dependency in README.md
2017-05-01 15:48:25 +02:00
David
a661f37575 Add document() method that renders a html() child 2017-05-01 15:45:02 +02:00
David
26796cd30d Add shorthand notation for id/class 2017-05-01 15:22:48 +02:00
chmuche
75dc60c415 Add Test 2017-05-01 15:19:27 +02:00
chmuche
99b98f9b09 Create a method attr without value to create empty attribute inside the tag 2017-05-01 15:12:41 +02:00
chmuche
8d4756bab0 Add Gradle dependency in README.md 2017-05-01 15:07:50 +02:00
David
2c1f337348 Update README.md 2017-04-30 20:37:27 +02:00
David
d437e1affd Add a domcontentjoiner 2017-04-29 16:44:48 +02:00
David
4fdcc3c213 Remove need for with() 2017-04-29 12:15:51 +02:00
David
ba3261b210 Update README.md 2017-04-25 23:34:26 +02:00
David
ee0100d1a7 Set snapshot to 1.0.0 2017-04-20 23:17:07 +02:00
David
9ec3088d82 [maven-release-plugin] prepare for next development iteration 2017-04-20 23:13:36 +02:00
David
8052cdaff1 [maven-release-plugin] prepare release j2html-0.99 2017-04-20 23:13:16 +02:00
David
34b2410830 Add withClasses(String... classes) method 2017-04-20 23:08:12 +02:00
David
75d361fa20 Merge pull request #51 from tipsy/iff-else
Add generic iff-method to use in method calls
2017-04-20 21:34:07 +02:00
David
3e91da0640 Add generic iff-method to use in method calls 2017-04-17 16:20:12 +02:00
David
d1613b0570 Change Error to RuntimeException 2017-04-17 15:35:06 +02:00
David
a841271ba4 Merge pull request #50 from tipsy/inline-static-fix
Fix #14 (Unable to read files from directories other that /src/main/r…
2017-04-16 10:37:09 +02:00
David
9272438940 Simplify resource handling and throw exception 2017-04-13 21:21:01 +02:00
David
3d43eb159f Fix #14 (Unable to read files from directories other that /src/main/resources) 2017-04-13 01:25:16 +02:00
David
30bfe4ea7f Small formatting fix 2017-04-12 19:40:26 +02:00
David
7409772c20 Update README.md 2017-04-12 19:30:26 +02:00
David
29e16df057 Improve escaper performance 2017-03-28 22:23:33 +02:00
David
6903bcbe4d Update README.md 2017-01-30 00:28:58 +01:00
David
56b830782f [maven-release-plugin] prepare for next development iteration 2017-01-29 21:32:54 +01:00
62 changed files with 4942 additions and 451 deletions

8
.editorconfig Normal file
View File

@@ -0,0 +1,8 @@
root=true
[*]
charset=utf-8
end_of_line=crlf
insert_final_newline=true
indent_style=space
indent_size=4

View File

@@ -7,25 +7,29 @@ Java to HTML generator. Enjoy typesafe HTML generation.
The project webpage is [j2html.com](http://j2html.com).
##Getting started
###Add the maven dependency
## Getting started
### Add the maven dependency
```xml
<dependency>
<groupId>com.j2html</groupId>
<artifactId>j2html</artifactId>
<version>0.7</version>
<version>1.3.0</version>
</dependency>
```
### Or the gradle dependency
```
compile 'com.j2html:j2html:1.3.0'
```
###Import TagCreator and start building HTML
### Import TagCreator and start building HTML
```java
import static j2html.TagCreator.*;
public class Main {
public static void main(String[] args) {
body().with(
h1("Heading!").withClass("example"),
img().withSrc("img/hello.png")
body(
h1("Hello, World!"),
img().withSrc("/img/hello.png")
).render();
}
}
@@ -33,8 +37,8 @@ public class Main {
The above Java will result in the following HTML:
```html
<body>
<h1 class="example">Heading!</h1>
<img src="img/hello.png">
<h1>Hello, World!</h1>
<img src="/img/hello.png">
</body>
```

View File

@@ -0,0 +1,313 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<profiles version="12">
<profile kind="CodeFormatterProfile" name="j2html" version="12">
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/>
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_binary_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/>
<setting id="org.eclipse.jdt.core.compiler.problem.enumIdentifier" value="error"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="80"/>
<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_binary_expression" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_lambda_body" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_parameters" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.compiler.problem.assertIdentifier" value="error"/>
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_binary_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="64"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="48"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
<setting id="org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode" value="enabled"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_conditional_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines" value="2147483647"/>
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try" value="80"/>
<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/>
<setting id="org.eclipse.jdt.core.compiler.source" value="1.8"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="64"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="64"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_assignment_operator" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="insert"/>
<setting id="org.eclipse.jdt.core.compiler.codegen.targetPlatform" value="1.8"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="52"/>
<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_arguments" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_binary_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.compiler.compliance" value="1.8"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="space"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="200"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
</profile>
</profiles>

56
pom.xml
View File

@@ -10,7 +10,7 @@
<groupId>com.j2html</groupId>
<artifactId>j2html</artifactId>
<version>0.88</version>
<version>1.4.0</version>
<name>j2html</name>
<description>Java to HTML builder with a fluent API</description>
@@ -52,6 +52,33 @@
<version>1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.carrotsearch</groupId>
<artifactId>junit-benchmarks</artifactId>
<version>0.7.2</version>
<scope>test</scope>
</dependency>
<!-- performance test dependencies -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
<version>1.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.18</version>
<scope>test</scope>
</dependency>
</dependencies>
<packaging>jar</packaging>
@@ -95,6 +122,33 @@
<configuration>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<archive>
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
<manifest>
<addClasspath>true</addClasspath>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>2.5.0</version>
<executions>
<execution>
<id>bundle-manifest</id>
<phase>process-classes</phase>
<goals>
<goal>manifest</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

View File

@@ -0,0 +1,44 @@
package j2html;
import j2html.utils.CSSMin;
import j2html.utils.EscapeUtil;
import j2html.utils.Indenter;
import j2html.utils.JSMin;
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>{@code Config.textEscaper = text -> text;}</code>
*/
public static TextEscaper textEscaper = EscapeUtil::escape;
/**
* Change this to configure css-minification.
* The default minifier is https://github.com/barryvan/CSSMin
*/
public static Minifier cssMinifier = CSSMin::compressCss;
/**
* Change this to configure js-minification.
* The default minifier is a simple whitespace/newline stripper
*/
public static Minifier jsMinifier = JSMin::compressJs;
/**
* Change this to configure enable/disable closing empty tags
* The default is to NOT close them
*/
public static boolean closeEmptyTags = false;
private static String FOUR_SPACES = " ";
/**
* Change this to configure indentation when rendering formatted html
* The default is four spaces
*/
public static Indenter indenter = (level, text) -> String.join("", Collections.nCopies(level, FOUR_SPACES)) + text;
private Config() {
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,8 @@
package j2html.attributes;
public class Attr {
import j2html.tags.Tag;
private Attr() {
}
public class Attr {
public static final String ACCEPT = "accept";
public static final String ACCEPT_CHARSET = "accept-charset";
@@ -115,5 +114,60 @@ public class Attr {
public static final String VALUE = "value";
public static final String WIDTH = "width";
public static final String WRAP = "wrap";
private Attr() {
}
public static ShortForm shortFormFromAttrsString(String attrs) {
if (!attrs.contains(".") && !attrs.contains(("#"))) {
throw new IllegalArgumentException("String must contain either id (#) or class (.)");
}
if (attrs.split("#").length > 2) {
throw new IllegalArgumentException("Only one id (#) allowed");
}
String id = "";
StringBuilder classes = new StringBuilder();
for (String attr : attrs.split("\\.")) {
if (attr.contains("#")) {
if (!attr.startsWith("#")) {
throw new IllegalArgumentException("# cannot be in the middle of string");
}
id = attr.replace("#", "");
} else {
classes.append(attr).append(" ");
}
}
return new ShortForm(id.trim(), classes.toString().trim());
}
public static <T extends Tag<T>> T addTo(T tag, ShortForm shortForm) {
if (shortForm.hasId() && shortForm.hasClasses()) {
return tag.withId(shortForm.id).withClass(shortForm.classes);
}
if (shortForm.hasId()) {
return tag.withId(shortForm.id);
}
if (shortForm.hasClasses()) {
return tag.withClass(shortForm.classes);
}
return tag;
}
public static class ShortForm {
String id;
String classes;
private ShortForm(String id, String classes) {
this.id = id;
this.classes = classes;
}
boolean hasId() {
return id != null && !"".equals(id);
}
boolean hasClasses() {
return classes != null && !"".equals(classes);
}
}
}

View File

@@ -1,15 +1,16 @@
package j2html.attributes;
import j2html.Config;
import j2html.tags.Renderable;
import java.io.IOException;
import j2html.utils.SimpleEscaper;
public class Attribute {
public class Attribute implements Renderable {
private String name;
private String value;
public Attribute(String name, String value) {
this.name = name;
this.value = SimpleEscaper.escape(value);
this.value = Config.textEscaper.escape(value);
}
public Attribute(String name) {
@@ -17,19 +18,18 @@ public class Attribute {
this.value = null;
}
public String render() {
if (name == null) {
return "";
}
if (value == null) {
return " " + name;
}
return (" " + name + "=\"" + value + "\"");
}
@Override
public String toString() {
return this.render();
public void renderModel(Appendable writer, Object model) throws IOException {
if (name == null) {
return;
}
writer.append(" ");
writer.append(name);
if (value != null) {
writer.append("=\"");
writer.append(value);
writer.append("\"");
}
}
public String getName() {

View File

@@ -1,8 +1,10 @@
package j2html.tags;
import j2html.Config;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
public class ContainerTag extends Tag<ContainerTag> {
@@ -22,7 +24,10 @@ public class ContainerTag extends Tag<ContainerTag> {
*/
public ContainerTag with(DomContent child) {
if (this == child) {
throw new Error("Cannot append a tag to itself.");
throw new RuntimeException("Cannot append a tag to itself.");
}
if (child == null) {
return this; // in some cases, like when using iff(), we ignore null children
}
children.add(child);
return this;
@@ -85,6 +90,18 @@ public class ContainerTag extends Tag<ContainerTag> {
}
/**
* Appends the DomContent-objects in the stream to the end of this element
*
* @param children Stream of DomContent-objects to be appended
* @return itself for easy chaining
*/
public ContainerTag with(Stream<DomContent> children) {
children.forEach(this::with);
return this;
}
/**
* Call with-method based on condition
* {@link #with(DomContent... children)}
@@ -108,33 +125,74 @@ public class ContainerTag extends Tag<ContainerTag> {
return with(new Text(text));
}
/**
* Gets number of child nodes this tag element contains
*/
public int getNumChildren() {
return children.size();
}
/**
* Render the ContainerTag and its children
* Render the ContainerTag and its children, adding newlines before each
* child and using Config.indenter to indent child based on how deep
* in the tree it is
*
* @return the rendered string
* @return the rendered and formatted string
*/
@Override
public String render() {
StringBuilder rendered = new StringBuilder(renderOpenTag());
if (children != null && !children.isEmpty()) {
for (DomContent child : children) {
rendered.append(child.render());
public String renderFormatted() {
try {
return renderFormatted(0);
} catch (IOException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
private String renderFormatted(int lvl) throws IOException {
StringBuilder sb = new StringBuilder();
renderOpenTag(sb, null);
if (hasTagName() && !isSelfFormattingTag()) {
sb.append("\n");
}
if (!children.isEmpty()) {
for (DomContent c : children) {
lvl++;
if (c instanceof ContainerTag) {
if (((ContainerTag) c).hasTagName()) {
sb.append(Config.indenter.indent(lvl, ((ContainerTag) c).renderFormatted(lvl)));
} else {
sb.append(Config.indenter.indent(lvl - 1, ((ContainerTag) c).renderFormatted(lvl - 1)));
}
} else if (isSelfFormattingTag()) {
sb.append(Config.indenter.indent(0, c.render()));
} else {
sb.append(Config.indenter.indent(lvl, c.render())).append("\n");
}
lvl--;
}
}
rendered.append(renderCloseTag());
return rendered.toString();
if (!isSelfFormattingTag()) {
sb.append(Config.indenter.indent(lvl, ""));
}
renderCloseTag(sb);
if (hasTagName()) {
sb.append("\n");
}
return sb.toString();
}
private boolean isSelfFormattingTag() {
return "textarea".equals(tagName) || "pre".equals(tagName);
}
@Override
public void render(Appendable writer) throws IOException {
writer.append(renderOpenTag());
public void renderModel(Appendable writer, Object model) throws IOException {
renderOpenTag(writer, model);
if (children != null && !children.isEmpty()) {
for (DomContent child : children) {
child.render(writer);
child.renderModel(writer, model);
}
}
writer.append(renderCloseTag());
renderCloseTag(writer);
}
}

View File

@@ -1,18 +1,4 @@
package j2html.tags;
import java.io.IOException;
public abstract class DomContent {
public abstract String render();
public void render(Appendable writer) throws IOException {
writer.append(render());
}
@Override
public String toString() {
return render();
}
public abstract class DomContent implements Renderable {
}

View File

@@ -0,0 +1,26 @@
package j2html.tags;
public class DomContentJoiner {
public static UnescapedText join(CharSequence delimiter, boolean fixPeriodAndCommaSpacing, Object... stringOrDomObjects) {
StringBuilder sb = new StringBuilder();
for (Object o : stringOrDomObjects) {
if (o instanceof String) {
sb.append(((String) o).trim()).append(delimiter);
} else if (o instanceof DomContent) {
sb.append(((DomContent) o).render().trim()).append(delimiter);
} else if (o == null) {
//Discard null objects so iff/iffelse can be used with join
} else {
throw new RuntimeException("You can only join DomContent and String objects");
}
}
String joined = sb.toString().trim();
if (fixPeriodAndCommaSpacing) {
joined = joined.replaceAll("\\s\\.", ".");
joined = joined.replaceAll("\\s\\,", ",");
}
return new UnescapedText(joined);
}
}

View File

@@ -1,5 +1,9 @@
package j2html.tags;
import j2html.Config;
import j2html.attributes.Attribute;
import java.io.IOException;
public class EmptyTag extends Tag<EmptyTag> {
public EmptyTag(String tagName) {
@@ -7,8 +11,19 @@ public class EmptyTag extends Tag<EmptyTag> {
}
@Override
public String render() {
return renderOpenTag();
public void render(Appendable writer) throws IOException {
renderModel(writer, null);
}
@Override
public void renderModel(Appendable writer, Object model) throws IOException {
writer.append("<").append(tagName);
for (Attribute attribute : getAttributes()) {
attribute.renderModel(writer, model);
}
if (Config.closeEmptyTags) {
writer.append("/");
}
writer.append(">");
}
}

View File

@@ -1,49 +1,49 @@
package j2html.tags;
import java.nio.file.Files;
import java.nio.file.Paths;
import j2html.utils.CSSMin;
import j2html.utils.JSMin;
import j2html.Config;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Scanner;
import static j2html.TagCreator.rawHtml;
import static j2html.TagCreator.script;
import static j2html.TagCreator.style;
import static j2html.TagCreator.rawHtml;
public class InlineStaticResource {
public enum TargetFormat {CSS_MIN, CSS, JS_MIN, JS}
public static ContainerTag get(String path, TargetFormat format) {
ContainerTag errorAlert = script().with(rawHtml("alert('Unable to read file. File: \"" + path + "\", Type: \"" + format + "\"')"));
String fileString = getFileAsString(path);
if(fileString != null) {
switch(format) {
case CSS_MIN : return style().with(rawHtml(compressCss(fileString)));
case JS_MIN : return script().with(rawHtml(compressJs(fileString)));
case CSS : return style().with(rawHtml(fileString));
case JS : return script().with(rawHtml(fileString));
default : return errorAlert;
}
switch (format) {
case CSS_MIN:
return style().with(rawHtml(Config.cssMinifier.minify(fileString)));
case JS_MIN:
return script().with(rawHtml(Config.jsMinifier.minify((fileString))));
case CSS:
return style().with(rawHtml(fileString));
case JS:
return script().with(rawHtml(fileString));
default:
throw new RuntimeException("Invalid target format");
}
return errorAlert;
}
public static String getFileAsString(String path) {
try {
return new String(Files.readAllBytes(Paths.get(InlineStaticResource.class.getResource(path).toURI())), "UTF-8");
} catch (Exception e) {
return null;
return streamToString(InlineStaticResource.class.getResourceAsStream(path));
} catch (Exception expected) { // we don't ask users to specify classpath or file-system
try {
return streamToString(new FileInputStream(path));
} catch (Exception exception) {
throw new RuntimeException("Couldn't find file with path='" + path + "'");
}
}
}
private static String compressCss(String code) {
return CSSMin.compress(code);
private static String streamToString(InputStream inputStream) {
Scanner s = new Scanner(inputStream).useDelimiter("\\A");
return s.hasNext() ? s.next() : "";
}
private static String compressJs(String code) {
return JSMin.compressJs(code);
}
public enum TargetFormat {CSS_MIN, CSS, JS_MIN, JS}
}

View File

@@ -0,0 +1,37 @@
package j2html.tags;
import java.io.IOException;
public interface Renderable {
/**
* Create a StringBuilder and use it to render the Renderable and it's
* children
*/
default String render() {
StringBuilder stringBuilder = new StringBuilder();
try {
render(stringBuilder);
} catch (IOException e) {
throw new RuntimeException(e.getMessage(), e);
}
return stringBuilder.toString();
}
/**
* Render the Renderable and it's children using the supplied writer
*
* @param writer the current writer
*/
default void render(Appendable writer) throws IOException {
renderModel(writer, null);
}
/**
* Render the Renderable and it's children using the supplied writer and a model.
*
* @param writer the current writer
* @param model a model object to provide data for children to render
*/
void renderModel(Appendable writer, Object model) throws IOException;
}

View File

@@ -1,12 +1,12 @@
package j2html.tags;
import java.util.ArrayList;
import j2html.attributes.Attr;
import j2html.attributes.Attribute;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
public abstract class Tag<T extends Tag<T>> extends DomContent {
protected String tagName;
private ArrayList<Attribute> attributes;
@@ -15,21 +15,49 @@ public abstract class Tag<T extends Tag<T>> extends DomContent {
this.attributes = new ArrayList<>();
}
public String getTagName() {
return this.tagName;
}
String renderOpenTag() {
StringBuilder sb = new StringBuilder("<").append(tagName);
for (Attribute attribute : attributes) {
sb.append(attribute.render());
protected boolean hasTagName() {
return tagName != null && !tagName.isEmpty();
}
String renderOpenTag() throws IOException {
StringBuilder stringBuilder = new StringBuilder();
renderOpenTag(stringBuilder, null);
return stringBuilder.toString();
}
String renderCloseTag() throws IOException {
StringBuilder stringBuilder = new StringBuilder();
renderCloseTag(stringBuilder);
return stringBuilder.toString();
}
void renderOpenTag(Appendable writer, Object model) throws IOException {
if (!hasTagName()) { // avoid <null> and <> tags
return;
}
sb.append(">");
return sb.toString();
writer.append("<").append(tagName);
for (Attribute attribute : attributes) {
attribute.renderModel(writer, model);
}
writer.append(">");
}
String renderCloseTag() {
return "</" + tagName + ">";
void renderCloseTag(Appendable writer) throws IOException {
if (!hasTagName()) { // avoid <null> and <> tags
return;
}
writer.append("</");
writer.append(tagName);
writer.append(">");
}
ArrayList<Attribute> getAttributes() {
return attributes;
}
/**
* Sets an attribute on an element
@@ -43,14 +71,13 @@ public abstract class Tag<T extends Tag<T>> extends DomContent {
}
for (Attribute attribute : attributes) {
if (attribute.getName().equals(name)) {
attribute.setValue(value); //update with new value
attribute.setValue(value); // update with new value
return true;
}
}
return attributes.add(new Attribute(name, value));
}
/**
* Sets a custom attribute
*
@@ -58,15 +85,47 @@ public abstract class Tag<T extends Tag<T>> extends DomContent {
* @param value the attribute value
* @return itself for easy chaining
*/
public T attr(String attribute, String value) {
setAttribute(attribute, value);
public T attr(String attribute, Object value) {
setAttribute(attribute, value == null ? null : String.valueOf(value));
return (T) this;
}
/**
* Adds the specified attribute. If the Tag previously contained an attribute with the same name, the old attribute is replaced by the specified attribute.
*
* @param attribute the attribute
* @return itself for easy chaining
*/
public T attr(Attribute attribute) {
Iterator<Attribute> iterator = attributes.iterator();
String name = attribute.getName();
if (name != null) {
// name == null is allowed, but those Attributes are not rendered. So we add them anyway.
while (iterator.hasNext()) {
Attribute existingAttribute = iterator.next();
if (existingAttribute.getName().equals(name)) {
iterator.remove();
}
}
}
attributes.add(attribute);
return (T) this;
}
/**
* Sets a custom attribute without value
*
* @param attribute the attribute name
* @return itself for easy chaining
* @see Tag#attr(String, Object)
*/
public T attr(String attribute) {
return attr(attribute, null);
}
/**
* Call attr-method based on condition
* {@link #attr(String attribute, String value)}
* {@link #attr(String attribute, Object value)}
*
* @param condition the condition
* @param attribute the attribute name
@@ -77,7 +136,6 @@ public abstract class Tag<T extends Tag<T>> extends DomContent {
return (condition ? attr(attribute, value) : (T) this);
}
@Override
public boolean equals(Object obj) {
if (obj == null || !(obj instanceof Tag)) {
@@ -86,54 +144,212 @@ public abstract class Tag<T extends Tag<T>> extends DomContent {
return ((Tag) obj).render().equals(this.render());
}
/**
* Convenience methods that call attr with predefined attributes
*
* @return itself for easy chaining
*/
public T isAutoComplete() { return attr(Attr.AUTOCOMPLETE, null); }
public T isAutoFocus() { return attr(Attr.AUTOFOCUS, null); }
public T isHidden() { return attr(Attr.HIDDEN, null); }
public T isRequired() { return attr(Attr.REQUIRED, null); }
public T withAlt(String alt) { return attr(Attr.ALT, alt); }
public T withAction(String action) { return attr(Attr.ACTION, action); }
public T withCharset(String charset) { return attr(Attr.CHARSET, charset); }
public T withClass(String className) { return attr(Attr.CLASS, className); }
public T withContent(String content) { return attr(Attr.CONTENT, content); }
public T withHref(String href) { return attr(Attr.HREF, href); }
public T withId(String id) { return attr(Attr.ID, id); }
public T withData(String dataAttr, String value) { return attr(Attr.DATA + "-" + dataAttr, value); }
public T withMethod(String method) { return attr(Attr.METHOD, method); }
public T withName(String name) { return attr(Attr.NAME, name); }
public T withPlaceholder(String placeholder) { return attr(Attr.PLACEHOLDER, placeholder); }
public T withTarget(String target) { return attr(Attr.TARGET, target); }
public T withType(String type) { return attr(Attr.TYPE, type); }
public T withRel(String rel) { return attr(Attr.REL, rel); }
public T withRole(String role) { return attr(Attr.ROLE, role); }
public T withSrc(String src) { return attr(Attr.SRC, src); }
public T withStyle(String style) { return attr(Attr.STYLE, style); }
public T withValue(String value) { return attr(Attr.VALUE, value); }
public T withClasses(String... classes) {
StringBuilder sb = new StringBuilder();
for (String s : classes) {
sb.append(s != null ? s : "").append(" ");
}
return attr(Attr.CLASS, sb.toString().trim());
}
public T withCondAutoComplete(boolean condition) { return condAttr(condition, Attr.AUTOCOMPLETE, null); }
public T withCondAutoFocus(boolean condition) { return condAttr(condition, Attr.AUTOFOCUS, null); }
public T withCondHidden(boolean condition) { return condAttr(condition, Attr.HIDDEN, null); }
public T withCondRequired(boolean condition) { return condAttr(condition, Attr.REQUIRED, null); }
public T withCondAlt(boolean condition, String alt) { return condAttr(condition, Attr.ALT, alt); }
public T withCondAction(boolean condition, String action) { return condAttr(condition, Attr.ACTION, action); }
public T withCharset(boolean condition, String charset) { return condAttr(condition, Attr.CHARSET, charset); }
public T withCondClass(boolean condition, String className) { return condAttr(condition, Attr.CLASS, className); }
public T withCondContent(boolean condition, String content) { return condAttr(condition, Attr.CONTENT, content); }
public T withCondHref(boolean condition, String href) { return condAttr(condition, Attr.HREF, href); }
public T withCondId(boolean condition, String id) { return condAttr(condition, Attr.ID, id); }
public T withCondData(boolean condition, String dataAttr, String value) { return condAttr(condition, Attr.DATA + "-" + dataAttr, value); }
public T withCondMethod(boolean condition, String method) { return condAttr(condition, Attr.METHOD, method); }
public T withCondName(boolean condition, String name) { return condAttr(condition, Attr.NAME, name); }
public T withCondPlaceholder(boolean condition, String placeholder) { return condAttr(condition, Attr.PLACEHOLDER, placeholder); }
public T withCondTarget(boolean condition, String target) { return condAttr(condition, Attr.TARGET, target); }
public T withCondType(boolean condition, String type) { return condAttr(condition, Attr.TYPE, type); }
public T withCondRel(boolean condition, String rel) { return condAttr(condition, Attr.REL, rel); }
public T withCondSrc(boolean condition, String src) { return condAttr(condition, Attr.SRC, src); }
public T withCondStyle(boolean condition, String style) { return condAttr(condition, Attr.STYLE, style); }
public T withCondValue(boolean condition, String value) { return condAttr(condition, Attr.VALUE, value); }
public T isAutoComplete() {
return attr(Attr.AUTOCOMPLETE, null);
}
public T isAutoFocus() {
return attr(Attr.AUTOFOCUS, null);
}
public T isHidden() {
return attr(Attr.HIDDEN, null);
}
public T isRequired() {
return attr(Attr.REQUIRED, null);
}
public T withAlt(String alt) {
return attr(Attr.ALT, alt);
}
public T withAction(String action) {
return attr(Attr.ACTION, action);
}
public T withCharset(String charset) {
return attr(Attr.CHARSET, charset);
}
public T withClass(String className) {
return attr(Attr.CLASS, className);
}
public T withContent(String content) {
return attr(Attr.CONTENT, content);
}
public T withDir(String dir) {
return attr(Attr.DIR, dir);
}
public T withHref(String href) {
return attr(Attr.HREF, href);
}
public T withId(String id) {
return attr(Attr.ID, id);
}
public T withData(String dataAttr, String value) {
return attr(Attr.DATA + "-" + dataAttr, value);
}
public T withLang(String lang) {
return attr(Attr.LANG, lang);
}
public T withMethod(String method) {
return attr(Attr.METHOD, method);
}
public T withName(String name) {
return attr(Attr.NAME, name);
}
public T withPlaceholder(String placeholder) {
return attr(Attr.PLACEHOLDER, placeholder);
}
public T withTarget(String target) {
return attr(Attr.TARGET, target);
}
public T withTitle(String title) {
return attr(Attr.TITLE, title);
}
public T withType(String type) {
return attr(Attr.TYPE, type);
}
public T withRel(String rel) {
return attr(Attr.REL, rel);
}
public T withRole(String role) {
return attr(Attr.ROLE, role);
}
public T withSrc(String src) {
return attr(Attr.SRC, src);
}
public T withStyle(String style) {
return attr(Attr.STYLE, style);
}
public T withValue(String value) {
return attr(Attr.VALUE, value);
}
public T withCondAutoComplete(boolean condition) {
return condAttr(condition, Attr.AUTOCOMPLETE, null);
}
public T withCondAutoFocus(boolean condition) {
return condAttr(condition, Attr.AUTOFOCUS, null);
}
public T withCondHidden(boolean condition) {
return condAttr(condition, Attr.HIDDEN, null);
}
public T withCondRequired(boolean condition) {
return condAttr(condition, Attr.REQUIRED, null);
}
public T withCondAlt(boolean condition, String alt) {
return condAttr(condition, Attr.ALT, alt);
}
public T withCondAction(boolean condition, String action) {
return condAttr(condition, Attr.ACTION, action);
}
public T withCharset(boolean condition, String charset) {
return condAttr(condition, Attr.CHARSET, charset);
}
public T withCondClass(boolean condition, String className) {
return condAttr(condition, Attr.CLASS, className);
}
public T withCondContent(boolean condition, String content) {
return condAttr(condition, Attr.CONTENT, content);
}
public T withCondDir(boolean condition, String dir) {
return condAttr(condition, Attr.DIR, dir);
}
public T withCondHref(boolean condition, String href) {
return condAttr(condition, Attr.HREF, href);
}
public T withCondId(boolean condition, String id) {
return condAttr(condition, Attr.ID, id);
}
public T withCondData(boolean condition, String dataAttr, String value) {
return condAttr(condition, Attr.DATA + "-" + dataAttr, value);
}
public T withCondLang(boolean condition, String lang) {
return condAttr(condition, Attr.LANG, lang);
}
public T withCondMethod(boolean condition, String method) {
return condAttr(condition, Attr.METHOD, method);
}
public T withCondName(boolean condition, String name) {
return condAttr(condition, Attr.NAME, name);
}
public T withCondPlaceholder(boolean condition, String placeholder) {
return condAttr(condition, Attr.PLACEHOLDER, placeholder);
}
public T withCondTarget(boolean condition, String target) {
return condAttr(condition, Attr.TARGET, target);
}
public T withCondTitle(boolean condition, String title) {
return condAttr(condition, Attr.TITLE, title);
}
public T withCondType(boolean condition, String type) {
return condAttr(condition, Attr.TYPE, type);
}
public T withCondRel(boolean condition, String rel) {
return condAttr(condition, Attr.REL, rel);
}
public T withCondSrc(boolean condition, String src) {
return condAttr(condition, Attr.SRC, src);
}
public T withCondStyle(boolean condition, String style) {
return condAttr(condition, Attr.STYLE, style);
}
public T withCondValue(boolean condition, String value) {
return condAttr(condition, Attr.VALUE, value);
}
}

View File

@@ -0,0 +1,167 @@
package j2html.tags;
import java.util.Arrays;
import java.util.List;
class TagCreatorCodeGenerator {
public static void main(String[] args) {
System.out.println("// EmptyTags, generated in " + TagCreatorCodeGenerator.class);
for (String tag : emptyTags()) {
String emptyA1 = "public static EmptyTag " + tag + "()";
String emptyA2 = "{ return new EmptyTag(\"" + tag + "\"); }";
// Attr shorthands
String emptyB1 = "public static EmptyTag " + tag + "(Attr.ShortForm shortAttr)";
String emptyB2 = "{ return Attr.addTo(new EmptyTag(\"" + tag + "\"), shortAttr); }";
// Print
System.out.println(String.format("%-80s%1s", emptyA1, emptyA2));
System.out.println(String.format("%-80s%1s", emptyB1, emptyB2));
System.out.println("");
}
System.out.println("// ContainerTags, generated in " + TagCreatorCodeGenerator.class);
for (String tag : containerTags()) {
String containerA1 = "public static ContainerTag " + tag + "()";
String containerA2 = "{ return new ContainerTag(\"" + tag + "\"); }";
String containerB1 = "public static ContainerTag " + tag + "(String text)";
String containerB2 = "{ return new ContainerTag(\"" + tag + "\").withText(text); }";
String containerC1 = "public static ContainerTag " + tag + "(DomContent... dc)";
String containerC2 = "{ return new ContainerTag(\"" + tag + "\").with(dc); }";
// Attr shorthands
String containerD1 = "public static ContainerTag " + tag + "(Attr.ShortForm shortAttr)";
String containerD2 = "{ return Attr.addTo(new ContainerTag(\"" + tag + "\"), shortAttr); }";
String containerE1 = "public static ContainerTag " + tag + "(Attr.ShortForm shortAttr, String text)";
String containerE2 = "{ return Attr.addTo(new ContainerTag(\"" + tag + "\").withText(text), shortAttr); }";
String containerF1 = "public static ContainerTag " + tag + "(Attr.ShortForm shortAttr, DomContent... dc)";
String containerF2 = "{ return Attr.addTo(new ContainerTag(\"" + tag + "\").with(dc), shortAttr); }";
// Print
System.out.println(String.format("%-80s%1s", containerA1, containerA2));
System.out.println(String.format("%-80s%1s", containerB1, containerB2));
System.out.println(String.format("%-80s%1s", containerC1, containerC2));
System.out.println(String.format("%-80s%1s", containerD1, containerD2));
System.out.println(String.format("%-80s%1s", containerE1, containerE2));
System.out.println(String.format("%-80s%1s", containerF1, containerF2));
System.out.println("");
}
}
// This is a method that contains all ContainerTags, there is nothing below it
private static List<String> emptyTags() {
return Arrays.asList(
"area",
"base",
"br",
"col",
//"!DOCTYPE html",
"embed",
"hr",
"img",
"input",
"keygen",
"link",
"meta",
"param",
"source",
"track",
"wbr"
);
}
private static List<String> containerTags() {
return Arrays.asList(
"a",
"abbr",
"address",
"article",
"aside",
"audio",
"b",
"bdi",
"bdo",
"blockquote",
"body",
"button",
"canvas",
"caption",
"cite",
"code",
"colgroup",
"datalist",
"dd",
"del",
"details",
"dfn",
"dialog",
"div",
"dl",
"dt",
"em",
"fieldset",
"figcaption",
"figure",
"footer",
"form",
"h1",
"h2",
"h3",
"h4",
"h5",
"h6",
"head",
"header",
"html",
"i",
"iframe",
"ins",
"kbd",
"label",
"legend",
"li",
"main",
"map",
"mark",
"menu",
"menuitem",
"meter",
"nav",
"noscript",
"object",
"ol",
"optgroup",
"option",
"output",
"p",
"pre",
"progress",
"q",
"rp",
"rt",
"ruby",
"s",
"samp",
"script",
"section",
"select",
"small",
"span",
"strong",
"style",
"sub",
"summary",
"sup",
"table",
"tbody",
"td",
"textarea",
"tfoot",
"th",
"thead",
"time",
"title",
"tr",
"u",
"ul",
"var",
"video"
);
}
}

View File

@@ -1,6 +1,7 @@
package j2html.tags;
import j2html.utils.SimpleEscaper;
import j2html.Config;
import java.io.IOException;
public class Text extends DomContent {
@@ -11,8 +12,13 @@ public class Text extends DomContent {
}
@Override
public String render() {
return SimpleEscaper.escape(text);
public void render(Appendable writer) throws IOException {
renderModel(writer, null);
}
@Override
public void renderModel(Appendable writer, Object model) throws IOException {
writer.append(Config.textEscaper.escape(text));
}
}

View File

@@ -1,5 +1,7 @@
package j2html.tags;
import java.io.IOException;
public class UnescapedText extends DomContent {
private String text;
@@ -9,8 +11,13 @@ public class UnescapedText extends DomContent {
}
@Override
public String render() {
return text;
public void render(Appendable writer) throws IOException {
renderModel(writer, null);
}
@Override
public void renderModel(Appendable writer, Object model) throws IOException {
writer.append(text);
}
}

View File

@@ -1,4 +1,4 @@
/**
/*
* * CSSMin Copyright License Agreement (BSD License)
* <p>
* Copyright (c) 2011-2014, Barry van Oudtshoorn
@@ -65,13 +65,11 @@ import java.util.regex.PatternSyntaxException;
public class CSSMin {
private CSSMin() {
}
private static final Logger LOG = Logger.getLogger(CSSMin.class.getName());
static boolean debugLogging = false;
private CSSMin() {
}
/**
* Minify supplied CSS.
@@ -79,11 +77,11 @@ public class CSSMin {
* @param input the CSS
* @return the compressed version
*/
public static String compress(String input) {
public static String compressCss(String input) {
try {
int k,
j, // Number of open braces
n; // Current position in stream
j, // Number of open braces
n; // Current position in stream
char curr;
BufferedReader br = new BufferedReader(new StringReader(input));
@@ -224,7 +222,8 @@ class Selector {
if (contents.length() == 1) {
throw new EmptySelectorBodyException(selector);
}
contents = contents.substring(0, contents.length() - 2);
int endIndex = contents.endsWith(";}") ? 2 : 1;
contents = contents.substring(0, contents.length() - endIndex);
this.properties = new Property[0];
this.properties = parseProperties(contents).toArray(this.properties);
@@ -266,7 +265,7 @@ class Selector {
private ArrayList<Property> parseProperties(String contents) {
ArrayList<String> parts = new ArrayList<>();
boolean bInsideString = false,
bInsideURL = false;
bInsideURL = false;
int j = 0;
String substr;
for (int i = 0; i < contents.length(); i++) {

View File

@@ -0,0 +1,36 @@
package j2html.utils;
public class EscapeUtil {
public static String escape(String s) {
if (s == null) {
return null;
}
StringBuilder escapedText = new StringBuilder();
char currentChar;
for (int i = 0; i < s.length(); i++) {
currentChar = s.charAt(i);
switch (currentChar) {
case '<':
escapedText.append("&lt;");
break;
case '>':
escapedText.append("&gt;");
break;
case '&':
escapedText.append("&amp;");
break;
case '"':
escapedText.append("&quot;");
break;
case '\'':
escapedText.append("&#x27;");
break;
default:
escapedText.append(currentChar);
}
}
return escapedText.toString();
}
}

View File

@@ -0,0 +1,6 @@
package j2html.utils;
@FunctionalInterface
public interface Indenter {
String indent(int level, String text);
}

View File

@@ -1,4 +1,5 @@
package j2html.utils;
/*
* JSMin.java 2006-02-13
*
@@ -37,8 +38,6 @@ package j2html.utils;
* SOFTWARE.
*/
// package org.inconspicuous.jsmin;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -46,9 +45,18 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.io.PushbackInputStream;
public class JSMin {
private static final int EOF = -1;
private PushbackInputStream in;
private OutputStream out;
private int theA;
private int theB;
private JSMin(InputStream in, OutputStream out) {
this.in = new PushbackInputStream(in);
this.out = out;
}
/**
* Compress a JS-string
*
@@ -62,37 +70,24 @@ public class JSMin {
try {
jsmin.jsmin();
return outStream.toString().trim();
} catch (IOException | UnterminatedRegExpLiteralException | UnterminatedCommentException | UnterminatedStringLiteralException e) {
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
private static final int EOF = -1;
private PushbackInputStream in;
private OutputStream out;
private int theA;
private int theB;
private JSMin(InputStream in, OutputStream out) {
this.in = new PushbackInputStream(in);
this.out = out;
}
/**
* isAlphanum -- return true if the character is a letter, digit,
* underscore, dollar sign, or non-ASCII character.
*/
private static boolean isAlphanum(int c) {
return ((c >= 'a' && c <= 'z') ||
(c >= '0' && c <= '9') ||
(c >= 'A' && c <= 'Z') ||
c == '_' ||
c == '$' ||
c == '\\' ||
c > 126);
(c >= '0' && c <= '9') ||
(c >= 'A' && c <= 'Z') ||
c == '_' ||
c == '$' ||
c == '\\' ||
c > 126);
}
/**
@@ -172,7 +167,7 @@ public class JSMin {
*/
private void action(int d) throws IOException, UnterminatedRegExpLiteralException,
UnterminatedCommentException, UnterminatedStringLiteralException {
UnterminatedCommentException, UnterminatedStringLiteralException {
switch (d) {
case 1:
out.write(theA);
@@ -302,4 +297,4 @@ public class JSMin {
private class UnterminatedRegExpLiteralException extends Exception {
}
}
}

View File

@@ -0,0 +1,6 @@
package j2html.utils;
@FunctionalInterface
public interface Minifier {
String minify(String s);
}

View File

@@ -1,28 +0,0 @@
package j2html.utils;
import java.util.HashMap;
import java.util.Map;
public class SimpleEscaper {
private static Map<Character, String> map = new HashMap<Character, String>() {{
put('&', "&amp;");
put('<', "&lt;");
put('>', "&gt;");
put('"', "&quot;");
put('\'', "&#x27;");
}};
public static String escape(String s) {
if(s == null) {
return null;
}
String escapedString = "";
for(char c : s.toCharArray()) {
String escaped = map.get(c);
escapedString += escaped != null ? escaped : c;
}
return escapedString;
}
}

View File

@@ -0,0 +1,6 @@
package j2html.utils;
@FunctionalInterface
public interface TextEscaper {
String escape(String text);
}

View File

@@ -0,0 +1,2 @@
public class AnyContent {
}

7
src/test/files/test.css Normal file
View File

@@ -0,0 +1,7 @@
body {
background: goldenrod;
margin-top: 10px;
margin-right: 10px;
margin-bottom: 10px;
margin-left: 10px;
}

3
src/test/files/test.html Normal file
View File

@@ -0,0 +1,3 @@
<body>
Any content
</body>

6
src/test/files/test.js Normal file
View File

@@ -0,0 +1,6 @@
(function () {
var test = 5;
var tast = 10;
var testTast = test + tast;
console.log(testTast);
})();

View File

@@ -0,0 +1,59 @@
package j2html;
import com.carrotsearch.junitbenchmarks.BenchmarkOptions;
import com.carrotsearch.junitbenchmarks.BenchmarkRule;
import com.carrotsearch.junitbenchmarks.Clock;
import j2html.utils.EscapeUtil;
import org.apache.commons.lang3.StringEscapeUtils;
import org.junit.FixMethodOrder;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.runners.MethodSorters;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@BenchmarkOptions(callgc = false, benchmarkRounds = 10000, warmupRounds = 200, concurrency = 2, clock = Clock.NANO_TIME)
public class PerformanceTest {
@Rule
public TestRule benchmarkRun = new BenchmarkRule();
private String shortTestString = "<body>\n"
+ " <h1 class=\"example\">Heading!</h1>\n"
+ " <img src=\"img/hello.png\">\n"
+ "</body>";
// syntax-highlighted getting started example from j2html.com:
private String longTestString =
"<pre class=\" language-java\"><code class=\" language-java\"><span class=\"token keyword\">import</span> <span class=\"token keyword\">static</span> j2html<span class=\"token punctuation\">.</span>TagCreator<span class=\"token punctuation\">.</span>*<span class=\"token punctuation\">;</span>\n"
+ "\n"
+ "<span class=\"token keyword\">public</span> <span class=\"token keyword\">class</span> <span class=\"token class-name\">Main</span> <span class=\"token punctuation\">{</span>\n"
+ " <span class=\"token keyword\">public</span> <span class=\"token keyword\">static</span> <span class=\"token keyword\">void</span> <span class=\"token function\">main<span class=\"token punctuation\">(</span></span>String<span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span> args<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n"
+ " <span class=\"token function\">body<span class=\"token punctuation\">(</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">with<span class=\"token punctuation\">(</span></span>\n"
+ " <span class=\"token function\">h1<span class=\"token punctuation\">(</span></span><span class=\"token string\">\"Heading!\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">withClass<span class=\"token punctuation\">(</span></span><span class=\"token string\">\"example\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n"
+ " <span class=\"token function\">img<span class=\"token punctuation\">(</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">withSrc<span class=\"token punctuation\">(</span></span><span class=\"token string\">\"img/hello.png\"</span><span class=\"token punctuation\">)</span>\n"
+ " <span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">render<span class=\"token punctuation\">(</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n"
+ " <span class=\"token punctuation\">}</span>\n"
+ "<span class=\"token punctuation\">}</span>\n"
+ "</code></pre>";
@Test
public void testSimpleEscaperShort() throws Exception {
EscapeUtil.escape(shortTestString);
}
@Test
public void testSimpleEscaperLong() throws Exception {
EscapeUtil.escape(longTestString);
}
@Test
public void testApacheEscaperShort() throws Exception {
StringEscapeUtils.escapeHtml4(shortTestString);
}
@Test
public void testApacheEscaperLong() throws Exception {
StringEscapeUtils.escapeHtml4(longTestString);
}
}

View File

@@ -0,0 +1,123 @@
package j2html;
import com.carrotsearch.junitbenchmarks.BenchmarkOptions;
import com.carrotsearch.junitbenchmarks.BenchmarkRule;
import com.carrotsearch.junitbenchmarks.Clock;
import j2html.model.BrowserTitle;
import j2html.model.Button;
import j2html.model.ButtonModel;
import j2html.model.PageModel;
import j2html.model.TextTemplate;
import j2html.tags.DomContent;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import static j2html.TagCreator.attrs;
import static j2html.TagCreator.body;
import static j2html.TagCreator.div;
import static j2html.TagCreator.h1;
import static j2html.TagCreator.h2;
import static j2html.TagCreator.head;
import static j2html.TagCreator.html;
import static j2html.TagCreator.p;
import static j2html.TagCreator.title;
import static org.junit.Assert.assertEquals;
@BenchmarkOptions(callgc = false, benchmarkRounds = 50000, warmupRounds = 200, concurrency = 2, clock = Clock.NANO_TIME)
public class RenderPerformanceTest {
@Rule
public TestRule benchmarkRun = new BenchmarkRule();
String expected = "<html><head><title>Browsertitle</title></head><body><h1>Hello World!</h1><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><p>Hello World!</p></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div><h2 id=\"title\" class=\"visible-small\">Hello World!</h2><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><p>Hello World!</p></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div><h2>Hello World!</h2><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><p>Hello World!</p></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div><h2 id=\"title\" class=\"visible-small\">Hello World!</h2><div class=\"button\"><div class=\"button-text\">Action!</div></div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><p>Hello World!</p></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div><h2>Hello World!</h2><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><p>Hello World!</p></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div><h1>Hello World!</h1><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><p>Hello World!</p></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div><h2>Hello World!</h2><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><p>Hello World!</p></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div><h2>Hello World!</h2><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><p>Hello World!</p></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div><h2>Hello World!</h2><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><p>Hello World!</p></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div><h2>Hello World!</h2><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><p>Hello World!</p></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></body></html>";
private DomContent template;
public RenderPerformanceTest() {
this.template =
// @formatter:off
html(
head(
title(new BrowserTitle())
),
body(
h1(new TextTemplate()),
div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(p(new TextTemplate()))))))))))))))))))))))))))),
h2(attrs("#title.visible-small"),new TextTemplate()),
div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(p(new TextTemplate()))))))))))))))))))))))))))),
h2(new TextTemplate()),
div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(p(new TextTemplate()))))))))))))))))))))))))))),
h2(attrs("#title.visible-small"),new TextTemplate()),
new Button(),
div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(p(new TextTemplate()))))))))))))))))))))))))))),
h2(new TextTemplate()),
div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(p(new TextTemplate()))))))))))))))))))))))))))),
h1(new TextTemplate()),
div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(p(new TextTemplate()))))))))))))))))))))))))))),
h2(new TextTemplate()),
div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(p(new TextTemplate()))))))))))))))))))))))))))),
h2(new TextTemplate()),
div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(p(new TextTemplate()))))))))))))))))))))))))))),
h2(new TextTemplate()),
div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(p(new TextTemplate()))))))))))))))))))))))))))),
h2(new TextTemplate()),
div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(p(new TextTemplate())))))))))))))))))))))))))))
)
);
// @formatter:on
}
private DomContent getDomContent(PageModel pageModel) throws Exception {
return
// @formatter:off
html(
head(
title(pageModel.getTitle())
),
body(
h1(pageModel.getText()),
div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(p(pageModel.getText()))))))))))))))))))))))))))),
h2(attrs("#title.visible-small"), pageModel.getText()),
div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(p(pageModel.getText()))))))))))))))))))))))))))),
h2(pageModel.getText()),
div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(p(pageModel.getText()))))))))))))))))))))))))))),
h2(attrs("#title.visible-small"),pageModel.getText()),
div()
.withClass("button")
.with(
div()
.withClass("button-text")
.withText(pageModel.getButtonModel().getText())
),
div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(p(pageModel.getText()))))))))))))))))))))))))))),
h2(pageModel.getText()),
div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(p(pageModel.getText()))))))))))))))))))))))))))),
h1(pageModel.getText()),
div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(p(pageModel.getText()))))))))))))))))))))))))))),
h2(pageModel.getText()),
div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(p(pageModel.getText()))))))))))))))))))))))))))),
h2(pageModel.getText()),
div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(p(pageModel.getText()))))))))))))))))))))))))))),
h2(pageModel.getText()),
div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(p(pageModel.getText()))))))))))))))))))))))))))),
h2(pageModel.getText()),
div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(div(p(pageModel.getText())))))))))))))))))))))))))))
)
);
// @formatter:on
}
@Test
public void templatePerfomanceTest() throws Exception {
PageModel pageModel = new PageModel("Browsertitle", "Hello World!", new ButtonModel("Action!"));
StringBuilder stringBuilder = new StringBuilder();
template.renderModel(stringBuilder, pageModel);
assertEquals(expected, stringBuilder.toString());
}
@Test
public void staticPerfomanceTest() throws Exception {
PageModel pageModel = new PageModel("Browsertitle", "Hello World!", new ButtonModel("Action!"));
String result = getDomContent(pageModel).render();
assertEquals(expected, result);
}
}

View File

@@ -0,0 +1,37 @@
package j2html;
import j2html.utils.EscapeUtil;
import j2html.utils.TextEscaper;
import org.junit.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
public class TextEscaperTest {
@Test
public void testTextEscaper() throws Exception {
String expected = "&lt;div&gt;&lt;/div&gt;";
assertThat("default text escaper works",
Config.textEscaper.escape("<div></div>"), is(expected));
Config.textEscaper = new NoOpEscaper();
assertThat("user can change text escaper implementation",
Config.textEscaper, is(instanceOf(NoOpEscaper.class)));
expected = "<div></div>";
assertThat("user provided text escaper actually works",
Config.textEscaper.escape("<div></div>"), is(expected));
Config.textEscaper = EscapeUtil::escape; // reset escaper
}
private static class NoOpEscaper implements TextEscaper {
@Override
public String escape(String text) {
return text;
}
}
}

View File

@@ -0,0 +1,62 @@
package j2html.attributes;
import org.junit.Test;
import static j2html.TagCreator.attrs;
import static j2html.TagCreator.div;
import static j2html.TagCreator.input;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
public class AttrShortFormTest {
@Test
public void addTo_emptyTag() throws Exception {
String expected = "<input id=\"some-id\" class=\"some-class\">";
String actual = input(attrs("#some-id.some-class")).render();
assertThat(actual, is(expected));
}
@Test
public void addTo_containerTag() throws Exception {
String expected = "<div id=\"some-id\" class=\"some-class\"></div>";
String actual = div(attrs("#some-id.some-class")).render();
assertThat(actual, is(expected));
}
@Test
public void addTo_justId() throws Exception {
String expected = "<div id=\"some-id\"></div>";
String actual = div(attrs("#some-id")).render();
assertThat(actual, is(expected));
}
@Test
public void addTo_justClass() throws Exception {
String expected = "<div class=\"some-class\"></div>";
String actual = div(attrs(".some-class")).render();
assertThat(actual, is(expected));
}
@Test
public void addTo_addTwoClasses() throws Exception {
String expected = "<div class=\"some-class some-other-class\"></div>";
String actual = div(attrs(".some-class.some-other-class")).render();
assertThat(actual, is(expected));
}
@Test(expected = IllegalArgumentException.class)
public void addTo_stringWithoutIdOrClass() throws Exception {
div(attrs("some-class")).render();
}
@Test(expected = IllegalArgumentException.class)
public void addTo_stringWithTwoIds() throws Exception {
div(attrs("#id1#id2")).render();
}
@Test(expected = IllegalArgumentException.class)
public void addTo_stringWithStupidlyPlacedId() throws Exception {
div(attrs("id1#id2")).render();
}
}

View File

@@ -1,9 +1,7 @@
package j2html.attributes;
import org.junit.Test;
import j2html.tags.ContainerTag;
import org.junit.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;

View File

@@ -0,0 +1,17 @@
package j2html.comparison;
import j2html.comparison.model.Employee;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class ComparisonData {
public static List<Integer> tableNumbers = IntStream.range(1, 51).boxed().collect(Collectors.toList());
public static List<Employee> fiveHundredEmployees() {
return IntStream.range(0, 500).mapToObj(i -> new Employee(i, "Some name", "Some title")).collect(Collectors.toList());
}
}

View File

@@ -0,0 +1,34 @@
package j2html.comparison;
import com.carrotsearch.junitbenchmarks.BenchmarkOptions;
import com.carrotsearch.junitbenchmarks.BenchmarkRule;
import com.carrotsearch.junitbenchmarks.Clock;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
@Ignore
@BenchmarkOptions(callgc = false, benchmarkRounds = 20_000, warmupRounds = 200, concurrency = 2, clock = Clock.NANO_TIME)
public class RenderPerformanceComparisonTest {
@Rule
public TestRule benchmarkRun = new BenchmarkRule();
@Test
public void j2htmlPerformance() throws Exception {
TestJ2html.helloWorld();
TestJ2html.fiveHundredEmployees();
TestJ2html.macros();
TestJ2html.multiplicationTable();
}
@Test
public void velocityPerformance() throws Exception {
TestVelocity.helloWorld();
TestVelocity.fiveHundredEmployees();
TestVelocity.macros();
TestVelocity.multiplicationTable();
}
}

View File

@@ -0,0 +1,30 @@
package j2html.comparison;
import j2html.comparison.j2html.FiveHundredEmployees;
import j2html.comparison.j2html.HelloWorld;
import j2html.comparison.j2html.Macros;
import j2html.comparison.j2html.MultiplicationTable;
public class TestJ2html {
public static String helloWorld() {
return HelloWorld.tag.render();
}
public static String fiveHundredEmployees() {
return FiveHundredEmployees.tag.render();
}
public static String macros() {
return Macros.tag.render();
}
public static String multiplicationTable() {
return MultiplicationTable.tag.render();
}
public static void main(String[] args) {
System.out.println(MultiplicationTable.tag.renderFormatted());
}
}

View File

@@ -0,0 +1,52 @@
package j2html.comparison;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
public class TestVelocity {
private static VelocityEngine velocityEngine;
static {
velocityEngine = new VelocityEngine();
velocityEngine.setProperty("resource.loader", "class");
velocityEngine.setProperty("class.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
}
private static String render(String templatePath, Map<String, Object> model) {
StringWriter stringWriter = new StringWriter();
velocityEngine.getTemplate(templatePath, StandardCharsets.UTF_8.name()).merge(
new VelocityContext(model), stringWriter
);
return stringWriter.toString();
}
public static String helloWorld() {
return render("/comparison/velocity/helloWorld.vm", null);
}
public static String fiveHundredEmployees() {
Map<String, Object> model = new HashMap<>();
model.put("employees", ComparisonData.fiveHundredEmployees());
return render("/comparison/velocity/fiveHundredEmployees.vm", model);
}
public static String macros() {
return render("/comparison/velocity/macros.vm", null);
}
public static String multiplicationTable() {
Map<String, Object> model = new HashMap<>();
model.put("tableNumbers", ComparisonData.tableNumbers);
return render("/comparison/velocity/multiplicationTable.vm", model);
}
public static void main(String[] args) {
System.out.println(multiplicationTable());
}
}

View File

@@ -0,0 +1,18 @@
package j2html.comparison.j2html;
import j2html.comparison.ComparisonData;
import j2html.tags.ContainerTag;
import static j2html.TagCreator.each;
import static j2html.TagCreator.li;
import static j2html.TagCreator.ul;
import static org.apache.commons.lang3.StringUtils.join;
public class FiveHundredEmployees {
public static ContainerTag tag = ul(
each(ComparisonData.fiveHundredEmployees(), employee ->
li(join(employee.getId(), employee.getName(), employee.getTitle()))
)
);
}

View File

@@ -0,0 +1,27 @@
package j2html.comparison.j2html;
import j2html.tags.ContainerTag;
import static j2html.TagCreator.attrs;
import static j2html.TagCreator.body;
import static j2html.TagCreator.h1;
import static j2html.TagCreator.head;
import static j2html.TagCreator.html;
import static j2html.TagCreator.link;
import static j2html.TagCreator.main;
import static j2html.TagCreator.title;
public class HelloWorld {
public static ContainerTag tag = html(
head(
title("Title"),
link().withRel("stylesheet").withHref("/css/main.css")
),
body(
main(attrs("#main.content"),
h1("Heading!")
)
)
);
}

View File

@@ -0,0 +1,46 @@
package j2html.comparison.j2html;
import j2html.tags.ContainerTag;
import j2html.tags.DomContent;
import static j2html.TagCreator.attrs;
import static j2html.TagCreator.body;
import static j2html.TagCreator.div;
import static j2html.TagCreator.h1;
import static j2html.TagCreator.head;
import static j2html.TagCreator.html;
import static j2html.TagCreator.link;
import static j2html.TagCreator.main;
import static j2html.TagCreator.title;
public class Macros {
public static ContainerTag tag = mainLayout(
div(
h1("Example content"),
someMacro(1),
someMacro(2),
someMacro(3)
)
);
private static ContainerTag mainLayout(DomContent content) {
return html(
head(
title("Title"),
link().withRel("stylesheet").withHref("/css/main.css")
),
body(
main(attrs("#main.content"),
content
)
)
);
}
private static ContainerTag someMacro(int i) {
return div(
"Macro call " + i
);
}
}

View File

@@ -0,0 +1,23 @@
package j2html.comparison.j2html;
import j2html.comparison.ComparisonData;
import j2html.tags.ContainerTag;
import static j2html.TagCreator.each;
import static j2html.TagCreator.table;
import static j2html.TagCreator.tbody;
import static j2html.TagCreator.td;
import static j2html.TagCreator.tr;
public class MultiplicationTable {
public static ContainerTag tag = table(
tbody(
each(ComparisonData.tableNumbers, i -> tr(
each(ComparisonData.tableNumbers, j -> td(
String.valueOf(i * j)
))
))
)
);
}

View File

@@ -0,0 +1,10 @@
package j2html.comparison.model;
import lombok.Value;
@Value
public class Employee {
int id;
String name;
String title;
}

View File

@@ -0,0 +1,11 @@
package j2html.model;
import java.io.IOException;
public class BrowserTitle extends Template<PageModel> {
@Override
public void renderTemplate(Appendable writer, PageModel pageModel) throws IOException {
writer.append(pageModel.getTitle());
}
}

View File

@@ -0,0 +1,38 @@
package j2html.model;
import j2html.tags.ContainerTag;
import java.io.IOException;
import static j2html.TagCreator.div;
public class Button extends Template<PageModel> {
private ContainerTag template;
public Button() {
// @formatter:off
template =
div()
.withClass("button")
.with(
div()
.withClass("button-text")
.with(
new ButtonText()
)
);
// @formatter:on
}
@Override
public void renderTemplate(Appendable writer, PageModel model) throws IOException {
template.renderModel(writer, model.getButtonModel().getText());
}
}
class ButtonText extends Template<String> {
@Override
public void renderTemplate(Appendable writer, String model) throws IOException {
writer.append(model);
}
}

View File

@@ -0,0 +1,13 @@
package j2html.model;
public class ButtonModel {
private String text;
public ButtonModel(String text) {
this.text = text;
}
public String getText() {
return text;
}
}

View File

@@ -0,0 +1,24 @@
package j2html.model;
import j2html.attributes.Attribute;
import java.io.IOException;
public class DynamicHrefAttribute extends Attribute {
public DynamicHrefAttribute() {
super("href");
}
@Override
public void renderModel(Appendable writer, Object model) throws IOException {
writer.append(" ");
writer.append(getName());
writer.append("=\"");
writer.append(getUrl(model));
writer.append("\"");
}
public String getUrl(Object model) {
return "/";
}
}

View File

@@ -0,0 +1,26 @@
package j2html.model;
public class PageModel {
private String title;
private String text;
private ButtonModel buttonModel;
public PageModel(String title, String text, ButtonModel buttonModel) {
this.title = title;
this.text = text;
this.buttonModel = buttonModel;
}
public ButtonModel getButtonModel() {
return buttonModel;
}
public String getTitle() {
return title;
}
public String getText() {
return text;
}
}

View File

@@ -0,0 +1,15 @@
package j2html.model;
import j2html.tags.DomContent;
import java.io.IOException;
public abstract class Template<T> extends DomContent {
@Override
@SuppressWarnings("unchecked")
public final void renderModel(Appendable writer, Object model) throws IOException {
renderTemplate(writer, (T) model);
}
public abstract void renderTemplate(Appendable writer, T model) throws IOException;
}

View File

@@ -0,0 +1,11 @@
package j2html.model;
import java.io.IOException;
public class TextTemplate extends Template<PageModel> {
@Override
public void renderTemplate(Appendable writer, PageModel pageModel) throws IOException {
writer.append(pageModel.getText());
}
}

View File

@@ -1,9 +1,7 @@
package j2html.tags;
import org.junit.Test;
import j2html.attributes.Attr;
import org.junit.Test;
import static j2html.TagCreator.a;
import static j2html.TagCreator.body;
import static j2html.TagCreator.button;
@@ -15,6 +13,7 @@ import static j2html.TagCreator.h2;
import static j2html.TagCreator.head;
import static j2html.TagCreator.header;
import static j2html.TagCreator.html;
import static j2html.TagCreator.iff;
import static j2html.TagCreator.input;
import static j2html.TagCreator.main;
import static j2html.TagCreator.script;
@@ -29,35 +28,139 @@ public class ComplexRenderTest {
boolean USER_SHOULD_LOG_IN = true;
boolean USER_SHOULD_SIGN_UP = false;
return document().render() +
html().with(
head().with(
title().withText("Test")
),
body().with(
header().with(
h1().with(
text("Test Header "),
a("with link").withHref("http://example.com"),
text(".")
)
),
main().with(
h2("Test Form"),
div().with(
input().withType("email").withName("email").withPlaceholder("Email"),
input().withType("password").withName("password").withPlaceholder("Password")
).condWith(USER_SHOULD_LOG_IN, button().withType("submit").withText("Login")
).condWith(USER_SHOULD_SIGN_UP, button().withType("submit").withText("Signup"))
),
footer().attr(Attr.CLASS, "footer").condAttr(1 == 1, Attr.ID, "id").withText("Test Footer"),
script().withSrc("/testScript.js")
html().with(
head().with(
title().withText("Test")
),
body().with(
header().with(
h1().with(
text("Test Header "),
a("with link").withHref("http://example.com"),
text(".")
)
).render();
),
main().with(
h2("Test Form"),
div().with(
input().withType("email").withName("email").withPlaceholder("Email"),
input().withType("password").withName("password").withPlaceholder("Password")
).condWith(USER_SHOULD_LOG_IN, button().withType("submit").withText("Login")
).condWith(USER_SHOULD_SIGN_UP, button().withType("submit").withText("Signup"))
),
footer().attr(Attr.CLASS, "footer").condAttr(1 == 1, Attr.ID, "id").withText("Test Footer"),
script().withSrc("/testScript.js")
)
).render();
}
private String renderTest2() {
boolean USER_SHOULD_LOG_IN = true;
boolean USER_SHOULD_SIGN_UP = false;
return document().render() +
html(
head(
title("Test")
),
body(
header(
h1(
text("Test Header "),
a("with link").withHref("http://example.com"),
text(".")
)
),
main(
h2("Test Form"),
div(
input().withType("email").withName("email").withPlaceholder("Email"),
input().withType("password").withName("password").withPlaceholder("Password"),
iff(USER_SHOULD_LOG_IN, button().withType("submit").withText("Login")),
iff(USER_SHOULD_SIGN_UP, button().withType("submit").withText("Signup"))
)
),
footer("Test Footer").attr(Attr.CLASS, "footer").condAttr(1 == 1, Attr.ID, "id"),
script().withSrc("/testScript.js")
)
).render();
}
private String renderTest3() {
boolean USER_SHOULD_LOG_IN = true;
boolean USER_SHOULD_SIGN_UP = false;
return document().render() + "\n" +
html(
head(
title("Test")
),
body(
header(
h1(
text("Test Header "),
a("with link").withHref("http://example.com"),
text(".")
)
),
main(
h2("Test Form"),
div(
input().withType("email").withName("email").withPlaceholder("Email"),
input().withType("password").withName("password").withPlaceholder("Password"),
iff(USER_SHOULD_LOG_IN, button().withType("submit").withText("Login")),
iff(USER_SHOULD_SIGN_UP, button().withType("submit").withText("Signup"))
)
),
footer("Test Footer").attr(Attr.CLASS, "footer").condAttr(1 == 1, Attr.ID, "id"),
script().withSrc("/testScript.js")
)
).renderFormatted();
}
@Test
public void testComplexRender() {
String expectedResult = "<!DOCTYPE html><html><head><title>Test</title></head><body><header><h1>Test Header <a href=\"http://example.com\">with link</a>.</h1></header><main><h2>Test Form</h2><div><input type=\"email\" name=\"email\" placeholder=\"Email\"><input type=\"password\" name=\"password\" placeholder=\"Password\"><button type=\"submit\">Login</button></div></main><footer class=\"footer\" id=\"id\">Test Footer</footer><script src=\"/testScript.js\"></script></body></html>";
assertThat(renderTest(), is(expectedResult));
assertThat(renderTest2(), is(expectedResult));
}
@Test
public void testComplexRender_formatted() {
assertThat(renderTest3(),
is("<!DOCTYPE html>\n"
+ "<html>\n"
+ " <head>\n"
+ " <title>\n"
+ " Test\n"
+ " </title>\n"
+ " </head>\n"
+ " <body>\n"
+ " <header>\n"
+ " <h1>\n"
+ " Test Header \n"
+ " <a href=\"http://example.com\">\n"
+ " with link\n"
+ " </a>\n"
+ " .\n"
+ " </h1>\n"
+ " </header>\n"
+ " <main>\n"
+ " <h2>\n"
+ " Test Form\n"
+ " </h2>\n"
+ " <div>\n"
+ " <input type=\"email\" name=\"email\" placeholder=\"Email\">\n"
+ " <input type=\"password\" name=\"password\" placeholder=\"Password\">\n"
+ " <button type=\"submit\">\n"
+ " Login\n"
+ " </button>\n"
+ " </div>\n"
+ " </main>\n"
+ " <footer class=\"footer\" id=\"id\">\n"
+ " Test Footer\n"
+ " </footer>\n"
+ " <script src=\"/testScript.js\">\n"
+ " </script>\n"
+ " </body>\n"
+ "</html>\n"));
}
}

View File

@@ -1,7 +1,6 @@
package j2html.tags;
import org.junit.Test;
import static j2html.TagCreator.a;
import static j2html.TagCreator.div;
import static j2html.TagCreator.form;
@@ -32,6 +31,7 @@ public class ConvenienceMethodTest {
assertThat(input().withName("test-name").render(), is("<input name=\"test-name\">"));
assertThat(input().withPlaceholder("test-placeholder").render(), is("<input placeholder=\"test-placeholder\">"));
assertThat(a().withTarget("_blank").render(), is("<a target=\"_blank\"></a>"));
assertThat(a().withTitle("Title").render(), is("<a title=\"Title\"></a>"));
assertThat(input().withType("email").render(), is("<input type=\"email\">"));
assertThat(link().withRel("stylesheet").render(), is("<link rel=\"stylesheet\">"));
assertThat(link().withRole("role").render(), is("<link role=\"role\">"));

View File

@@ -0,0 +1,45 @@
package j2html.tags;
import org.junit.Test;
import static j2html.TagCreator.fileAsEscapedString;
import static j2html.TagCreator.fileAsString;
import static j2html.TagCreator.scriptWithInlineFile_min;
import static j2html.TagCreator.styleWithInlineFile_min;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
public class InlineStaticResourceTest {
private static final String EOL = System.getProperty("line.separator"); // System independent End Of Line
@Test
public void testAllTags() throws Exception {
String expectedCss = "<style>body{background:#daa520;margin-bottom:10px;margin-left:10px;margin-right:10px;margin-top:10px}</style>";
String expectedJs = "<script>(function(){var test=5;var tast=10;var testTast=test+tast;console.log(testTast);})();</script>";
String expectedHtml = "<body>" + EOL + " Any content" + EOL + "</body>" + EOL;
String expectedEscapedHtml = "&lt;body&gt;" + EOL + " Any content" + EOL + "&lt;/body&gt;" + EOL;
String expectedAnyContent = "public class AnyContent {" + EOL + "}" + EOL;
// classpath files
assertThat(styleWithInlineFile_min("/test.css").render(), is(expectedCss));
assertThat(styleWithInlineFile_min("/test-without-trailing-semis.css").render(), is(expectedCss));
assertThat(scriptWithInlineFile_min("/test.js").render(), is(expectedJs));
assertThat(fileAsString("/test.html").render(), is(expectedHtml));
assertThat(fileAsEscapedString("/test.html").render(), is(expectedEscapedHtml));
assertThat(fileAsString("/AnyContent.java").render(), is(expectedAnyContent));
// files outside classpath
assertThat(styleWithInlineFile_min("src/test/files/test.css").render(), is(expectedCss));
assertThat(scriptWithInlineFile_min("src/test/files/test.js").render(), is(expectedJs));
assertThat(fileAsString("src/test/files/test.html").render(), is(expectedHtml));
assertThat(fileAsEscapedString("src/test/files/test.html").render(), is(expectedEscapedHtml));
assertThat(fileAsString("src/test/files/AnyContent.java").render(), is(expectedAnyContent));
}
@Test(expected = RuntimeException.class)
public void testExceptionForBadPath() throws Exception {
styleWithInlineFile_min("NOT A FILE");
}
}

View File

@@ -0,0 +1,58 @@
package j2html.tags;
import org.junit.Test;
import static j2html.TagCreator.div;
import static j2html.TagCreator.each;
import static j2html.TagCreator.li;
import static j2html.TagCreator.p;
import static j2html.TagCreator.pre;
import static j2html.TagCreator.textarea;
import static j2html.TagCreator.ul;
import static java.util.Arrays.asList;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
public class RenderFormattedTest {
@Test
public void testFormattedTags() throws Exception {
assertThat(div(p("Hello")).renderFormatted(), is("<div>\n <p>\n Hello\n </p>\n</div>\n"));
}
@Test
public void testFormattedTags_doesntFormatPre() throws Exception {
assertThat(div(pre("public void renderModel(Appendable writer, Object model) throws IOException {\n" +
" writer.append(text);\n" +
" }")).renderFormatted(), is("<div>\n" +
" <pre>public void renderModel(Appendable writer, Object model) throws IOException {\n" +
" writer.append(text);\n" +
" }</pre>\n" +
"</div>\n"));
}
@Test
public void testFormattedTags_doesntFormatTextArea() throws Exception {
assertThat(div(textarea("fred\ntom")).renderFormatted(), is("<div>\n" +
" <textarea>fred\n" +
"tom</textarea>\n" +
"</div>\n"));
}
@Test
public void testFormattedTags_each() throws Exception {
assertThat(ul(each(asList(1, 2, 3), i -> li("Number " + i))).renderFormatted(), is(
"<ul>\n" +
" <li>\n" +
" Number 1\n" +
" </li>\n" +
" <li>\n" +
" Number 2\n" +
" </li>\n" +
" <li>\n" +
" Number 3\n" +
" </li>\n" +
"</ul>\n"
));
}
}

View File

@@ -1,14 +1,18 @@
package j2html.tags;
import j2html.Config;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import org.junit.Before;
import org.junit.Test;
import static j2html.TagCreator.*;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
public class TagCreatorTest {
@@ -16,44 +20,136 @@ public class TagCreatorTest {
List<Employee> employees = Arrays.asList(new Employee(1, "Name 1", "Title 1"), new Employee(2, "Name 2", "Title 2"), new Employee(3, "Name 3", "Title 3"));
Map<Integer, Employee> employeeMap = new HashMap<>();
@Before
public void setUp() {
employeeMap.put(1, new Employee(1, "Name 1", "Title 1"));
employeeMap.put(2, new Employee(2, "Name 2", "Title 2"));
employeeMap.put(3, new Employee(3, "Name 3", "Title 3"));
}
@Test
public void testDocument() throws Exception {
Config.closeEmptyTags = true;
assertEquals("<!DOCTYPE html>", document().render());
assertEquals("<!DOCTYPE html><html></html>", document(html()));
Config.closeEmptyTags = false;
assertEquals("<!DOCTYPE html>", document().render());
assertEquals("<!DOCTYPE html><html></html>", document(html()));
}
@Test
public void testIff() throws Exception {
String expected = "<div><p>Test</p><a href=\"#\">Test</a></div>";
String actual = div(
p("Test"),
iff(1 == 1, a("Test").withHref("#")),
iff(1 == 2, a("Tast").withHref("#"))
).render();
assertThat(actual, is(expected));
}
@Test
public void testIffOptional() {
String expected = "<div><p>Test</p><a href=\"#1\">Test</a></div>";
String actual = div(
p("Test"),
iff(Optional.of(1), i -> a("Test").withHref("#" + i)),
iff(Optional.empty(), i -> a("Tast").withHref("#2"))
).render();
assertThat(actual, is(expected));
}
@Test
public void testIffElse() throws Exception {
String expected = "<div><p>Tast</p></div>";
String actual = div(iffElse(1 == 2, p("Test"), p("Tast"))).render();
assertThat(actual, is(expected));
}
@Test
public void testJoin() throws Exception {
String expected = "This is my joined string. It has a <a href=\"#\">link in the middle</a> and <code>code at the end</code>.";
String actual = join("This is my joined string. It has a", a("link in the middle").withHref("#"), "and", code("code at the end"), ".").render();
assertThat(actual, is(expected));
}
@Test
public void testJoinWithNulls() throws Exception {
String expected = "This is my joined string. It has ignored null content in the middle.";
String actual = join("This is my joined string.", iff(false, "this should not be displayed"), "It has ignored null content in the middle.").render();
assertThat(actual, is(expected));
}
@Test
public void testEach() throws Exception {
String j2htmlMap = ul().with(
li("Begin list"),
each(employees, employee -> li().with(
h2(employee.name),
p(employee.title)
))
li("Begin list"),
each(employees, employee -> li(
h2(employee.name),
p(employee.title)
))
).render();
String javaMap = ul().with(
li("Begin list"),
rawHtml(employees.stream().map(employee -> li().with(
h2(employee.name),
p(employee.title)
)).map(DomContent::render).collect(Collectors.joining()))
li("Begin list"),
rawHtml(employees.stream().map(employee -> li(
h2(employee.name),
p(employee.title)
)).map(DomContent::render).collect(Collectors.joining()))
).render();
assertThat(j2htmlMap.equals(javaMap), is(true));
assertThat(j2htmlMap, is("<ul><li>Begin list</li><li><h2>Name 1</h2><p>Title 1</p></li><li><h2>Name 2</h2><p>Title 2</p></li><li><h2>Name 3</h2><p>Title 3</p></li></ul>"));
assertThat(j2htmlMap.equals(javaMap), is(true));
}
@Test
public void testEachWithMap() {
final String j2htmlMap = ul().with(
li("Begin list"),
each(employeeMap, entry -> li(entry.getKey() + "-" + entry.getValue().name))
).render();
assertThat(j2htmlMap, is("<ul><li>Begin list</li><li>1-Name 1</li><li>2-Name 2</li><li>3-Name 3</li></ul>"));
}
@Test
public void testEachWithMapAndBiFunction() {
final String j2htmlMap = ul().with(
li("Begin list"),
each(employeeMap, (id, employee) -> li(id + "-" + employee.name))
).render();
assertThat(j2htmlMap, is("<ul><li>Begin list</li><li>1-Name 1</li><li>2-Name 2</li><li>3-Name 3</li></ul>"));
}
@Test
public void testFilter() throws Exception {
String j2htmlFilter = ul().with(
li("Begin list"),
each(filter(employees, e -> e.id % 2 == 1), employee -> li().with(
h2(employee.name),
p(employee.title)
))
li("Begin list"),
each(filter(employees, e -> e.id % 2 == 1), employee -> li(
h2(employee.name),
p(employee.title)
))
).render();
String javaFilter = ul().with(
li("Begin list"),
rawHtml(employees.stream().filter(e -> e.id % 2 == 1).map(employee -> li().with(
h2(employee.name),
p(employee.title)
)).map(DomContent::render).collect(Collectors.joining()))
li("Begin list"),
rawHtml(employees.stream().filter(e -> e.id % 2 == 1).map(employee -> li(
h2(employee.name),
p(employee.title)
)).map(DomContent::render).collect(Collectors.joining()))
).render();
assertThat(j2htmlFilter.equals(javaFilter), is(true));
assertThat(j2htmlFilter, is("<ul><li>Begin list</li><li><h2>Name 1</h2><p>Title 1</p></li><li><h2>Name 3</h2><p>Title 3</p></li></ul>"));
assertThat(j2htmlFilter.equals(javaFilter), is(true));
}
@Test
public void testEachWithStream() throws Exception {
final String j2htmlMap = ul().with(
li("Begin list"),
each(employeeMap.entrySet().stream().map(e -> li(e.getKey() + "-" + e.getValue().name)))
).render();
assertThat(j2htmlMap, is("<ul><li>Begin list</li><li>1-Name 1</li><li>2-Name 2</li><li>3-Name 3</li></ul>"));
}
@Test
@@ -65,11 +161,6 @@ public class TagCreatorTest {
assertThat(text("text").render(), is("text"));
assertThat(text("<script> and \"</script>\"").render(), is("&lt;script&gt; and &quot;&lt;/script&gt;&quot;"));
assertThat(rawHtml("<script>").render(), is("<script>"));
assertThat(styleWithInlineFile_min("/test.css").render(), is("<style>body{background:#daa520;margin-bottom:10px;margin-left:10px;margin-right:10px;margin-top:10px}</style>"));
assertThat(scriptWithInlineFile_min("/test.js").render(), is("<script>(function(){var test=5;var tast=10;var testTast=test+tast;console.log(testTast);})();</script>"));
assertThat(fileAsString("/test.html").render(), is("<body>" + EOL + " Any content" + EOL + "</body>" + EOL));
assertThat(fileAsEscapedString("/test.html").render(), is("&lt;body&gt;" + EOL + " Any content" + EOL + "&lt;/body&gt;" + EOL));
assertThat(fileAsString("/AnyContent.java").render(), is("public class AnyContent{}" + EOL));
//EmptyTags
assertThat(document().render(), is("<!DOCTYPE html>"));

View File

@@ -1,11 +1,17 @@
package j2html.tags;
import j2html.Config;
import j2html.model.DynamicHrefAttribute;
import java.io.FileWriter;
import org.junit.Test;
import static j2html.TagCreator.body;
import static j2html.TagCreator.div;
import static j2html.TagCreator.footer;
import static j2html.TagCreator.header;
import static j2html.TagCreator.html;
import static j2html.TagCreator.iff;
import static j2html.TagCreator.img;
import static j2html.TagCreator.input;
import static j2html.TagCreator.main;
import static j2html.TagCreator.p;
import static j2html.TagCreator.tag;
@@ -42,6 +48,19 @@ public class TagTest {
assertThat(testTag.renderCloseTag(), is("</a>"));
}
@Test
public void testSelfClosingTags() throws Exception {
Config.closeEmptyTags = true;
assertThat(img().withSrc("/test.png").render(), is("<img src=\"/test.png\"/>"));
assertThat(input().withType("text").render(), is("<input type=\"text\"/>"));
Config.closeEmptyTags = false;
}
@Test
public void testFormattedTags() throws Exception { // better test in ComplexRenderTest.java
assertThat(div(p("Hello")).renderFormatted(), is("<div>\n <p>\n Hello\n </p>\n</div>\n"));
}
@Test
public void testEquals() throws Exception {
Tag tagOne = tag("p").withClass("class").withText("Test");
@@ -49,4 +68,49 @@ public class TagTest {
assertThat(tagOne.equals(tagTwo), is(true));
}
@Test
public void testAcceptObjectValueAttribute() throws Exception {
ContainerTag complexTestTag = new ContainerTag("input")
.attr("attr1", "value1")
.attr("attr2", 2)
.attr("attr3", null);
String expectedResult = "<input attr1=\"value1\" attr2=\"2\" attr3>";
assertThat(complexTestTag.renderOpenTag(), is(expectedResult));
}
@Test
public void testWithClasses() throws Exception {
String expected = "<div class=\"c1 c2\"></div>";
String actual = div().withClasses("c1", iff(1 == 1, "c2"), iff(1 == 2, "c3")).render();
assertThat(actual, is(expected));
}
@Test
public void testEmptyAttribute() throws Exception {
ContainerTag testTagWithAttrValueNull = new ContainerTag("a").attr("attribute", null);
assertThat(testTagWithAttrValueNull.render(), is("<a attribute></a>"));
ContainerTag testTagAttrWithoutAttr = new ContainerTag("a").attr("attribute");
assertThat(testTagAttrWithoutAttr.render(), is("<a attribute></a>"));
}
@Test
public void testDynamicAttribute() throws Exception {
ContainerTag testTagWithAttrValueNull = new ContainerTag("a").attr(new DynamicHrefAttribute());
assertThat(testTagWithAttrValueNull.render(), is("<a href=\"/\"></a>"));
}
@Test
public void testDynamicAttributeReplacement() throws Exception {
ContainerTag testTagWithAttrValueNull = new ContainerTag("a").attr("href", "/link").attr(new DynamicHrefAttribute());
assertThat(testTagWithAttrValueNull.render(), is("<a href=\"/\"></a>"));
}
@Test
public void renderToFile() throws Exception {
FileWriter fileWriter = new FileWriter("file.txt");
div("Test").render(fileWriter);
fileWriter.close();
}
}

View File

@@ -1 +1,2 @@
public class AnyContent{}
public class AnyContent {
}

View File

@@ -0,0 +1,7 @@
#* @vtlvariable name="employees" type="java.util.List<j2html.comparison.ComparisonData.Employee>" *#
<ul>
#foreach($employee in $employees)
<li>$employee.id $employee.name $employee.title</li>
#end
</ul>

View File

@@ -0,0 +1,11 @@
<html>
<head>
<title>Title</title>
<link rel="stylesheet" href="/css/main.css">
</head>
<body>
<main id="main" class="content">
<h1>Heading!</h1>
</main>
</body>
</html>

View File

@@ -0,0 +1,28 @@
#macro(mainLayout)
<html>
<head>
<title>Title</title>
<link rel="stylesheet" href="/css/main.css">
</head>
<body>
<main id="main" class="content">
$!bodyContent
</main>
</body>
</html>
#end
#@mainLayout()
<div>
<h1>Example content</h1>
#someMacro(1)
#someMacro(2)
#someMacro(3)
</div>
#end
#macro(someMacro $callNumber)
<div>
Macro call $callNumber
</div>
#end

View File

@@ -0,0 +1,12 @@
<table>
<tbody>
#foreach($i in $tableNumbers)
<tr>
#foreach($j in $tableNumbers)
#set($product = $i * $j)
<td>$product</td>
#end
</tr>
#end
</tbody>
</table>

View File

@@ -0,0 +1,7 @@
body {
background: goldenrod;
margin-top: 10px;
margin-right: 10px;
margin-bottom: 10px;
margin-left: 10px
}