diff --git a/CONTRIBUTING.markdown b/CONTRIBUTING.markdown index c0899e961..72f1345b3 100644 --- a/CONTRIBUTING.markdown +++ b/CONTRIBUTING.markdown @@ -1,252 +1,112 @@ -Contributing to Thymeleaf: Terms and Conditions -=============================================== +# Contributing to Thymeleaf ------------------------------------------------------------------------------- +Thymeleaf is released under the Apache 2.0 license. If you would like to +contribute something, or want to hack on the code this document should help you +get started. -Do you want to contribute your work to Thymeleaf? Well, then first and most important: **THANK YOU!** -Now, in order to accept your contribution, there are some terms you must expressly agree with, so please -read them carefully. They may seem a bit cumbersome but they are there to protect you, your contribution, -and most importantly, the project's future. +## Code of Conduct -**Important**: submitting any contributions to the Thymeleaf project implies your **full acceptance of these terms**, -including the *"Thymeleaf Individual Contributor License Agreement"* detailed at the end of this document. +This project adheres to the Contributor Covenant +[code of conduct][code-of-coduct]. +By participating, you are expected to uphold this code. Please report +unacceptable behavior to [the project leads][thymeleaf-team]. -Who can contribute? -------------------- +## Using GitHub Issues -Anyone, with the unique condition that he/she must be a **private individual**, acting in -his/her own name, and not being endorsed in their contributed work by any company or government. +We use GitHub issues to track bugs and enhancements. +If you have a general usage question please ask on +[Stack Overflow][stackoverflow]. +The Thymeleaf team and the broader community monitor the +[`thymeleaf`][stackoverflow-thymeleaf] tag. -Note that this condition will not only refer to the ownership of the effort invested in contributing -to the project, but also to the fact that *no private or public company will be mentioned as a part -of your contribution on the project's website or code*, including but not limited to web/email addresses -or package names. +If you are reporting a bug, please help to speed up problem diagnosis by +providing as much information as possible. +Ideally, that would include a small sample project that reproduces the problem. -What is the first step to be taken? ------------------------------------ +## Before submitting a Contribution -First of all, **talk to the [project members](http://www.thymeleaf.org/team.html)** (an email should do) about -your ideas: new features, fixes, documentation... whatever you would like to contribute to the project. Let us -discuss the possibilities with you so that we make sure your contribution goes in the right direction and aligns -with the project's standards, intentions and roadmap. +Before submitting a contribution that is not an obvious or trivial fix, +get in contact with the [the project leads][thymeleaf-team] about your +ideas (an email should do). Let us discuss the possibilities with you so that +we make sure your contribution goes in the right direction and aligns with the +project's standards, intentions and roadmap. +Please understand that *not all contributions will be accepted and merged into +the project's repositories*. Talking about your planned contributions with the +project maintainers before creating pull requests can maximize the possibility +of your contributions being accepted. -How will your involvement with the Thymeleaf project work? ----------------------------------------------------------- -All contributions are submitted in the form of GitHub *pull requests*. Note that contributors do not -have read+write (or *pull+push*) access to the project repositories, only project *members* do. -Also, please understand that *not all pull requests will be accepted and merged into the project's -repositories*. Talk about your planned contributions with the project members before creating pull -requests so you can maximize the possibility of your contributions being accepted. +## Signing the Contributor License Agreement -Once your contribution is approved, you will be listed as a *contributor* on the -[Thymeleaf Team page](http://www.thymeleaf.org/team.html). You can opt-out of this if you want. -Also, you will be `@author` for any new Java classes that you write and also co-`@author` of any -existing classes to which you make significant changes. You can also opt-out of this if you want. +Before we accept a non-trivial patch or pull request we will need you to +sign a **Contributor License Agreement**. +There are two versions of the CLA: -About the code you contribute ------------------------------ + * **Individual CLA**: For individuals acting on their own behalf, i.e. not + being backed by any company or government, and not making their + contributions potentially under the effect of any contracts, agreements or + laws that could cause their employeer (or any other entities) claim + any rights on their contribution. + * **Corporate CLA**: For corporate entities allowing some of their employees + to contribute to Thymeleaf on the entity's behalf. -### General guidelines: +For more information on the CLA and the (very easy) process involving this +step, please have a look at the [Thymeleaf CLA repository][cla]. - - Obviously, **your code must both compile and work correctly**. Also, the addition of any new patches to the - codebase should not render it unstable in any way. - - All your code should be easy to read and understand by a human. - - There should be no compilation warnings at all. -### Detailed Java code quality standards: - - All your code should compile and run in **Java 6.0**. - - All comments, names of classes and variables, log messages, etc. must be **in English**. - - All `.java` files must include the standard Thymeleaf copyright header. - - All your code should follow the Java Code Conventions regarding variable/method/class naming. - - Maximum line length is 120 characters. - - Indentation should be made with 4 spaces, not tabs. - - Line feeds should be UNIX-like (`\n`). - - All `.java` source files should be pure ASCII. All `.properties` files should be ISO-8859-1. - - Number autoboxing and/or autounboxing is forbidden. - - Every class should define a constructor, even if it is the no-argument constructor, and include a call to `super()`. - - All method parameters should be declared as `final` so that they cannot be changed or reassigned in the method. - - All non-nullable parameters in a public method should be first validated with a `Validate.notNull(...)` call. - This maintains consistency in the behavior of public methods and the error message used. - - Include a block comment (`/* ... */`) for any non-trivial algorithm you develop. *"Non-trivial"* usually means you - had to make some design decisions to do things in a certain way. Your comment should explain *why* you wrote the - code the way you wrote it. Do not write obvious comments that explain what the code does; the code should be clear - and expressive enough so the *what* and *how* of it is obvious. - - All public methods and classes directly available to users should have comprehensive JavaDoc comments. - -### Detailed HTML/XML code quality standards: - - - All tags, CSS styles, file names, etc. must be **in English**. - - Lower case should be preferred for HTML/XML artifacts. The only exceptions are `DOCTYPE` and `CDATA` clauses. - - All HTML code should be XML-valid (i.e. all tags should be closed, attributes surrounded by commas, etc.) - - Maximum line length is 120 characters. - - Indentation should be made with 4 spaces, not tabs. - - Line feeds should be UNIX-like (`\n`). - - All `.html` and `.xml` source files should be pure ASCII, even if _content-type_ is set to a different encoding. - - All XHTML self-closing (minimized) tags should have a space before `/>` (the XHTML standards say so!). - - All inline scripts must be enclosed inside a commented `` block. - - -About the documentation/articles you contribute ------------------------------------------------ - -Note the following only applies to documentation/articles meant to be published at the Thymeleaf website. - - - All documentation artifacts, including articles, must be written **in correct English**. - - Your name and email will be displayed as *"author"* of any documentation artifacts you create. - - Topic and text structure must be first discussed and agreed upon with the project members. - - Project members may edit and make small changes to your texts—of which you will be informed—before - publishing them. - - Format and visual styles must adhere to the Thymeleaf website standards, of which you will be informed - by the project members. - - -Pay special attention to this ------------------------------ - -All Thymeleaf software is distributed under the **Apache License 2.0** open source license; your contributions -will be licensed in the same way. - -If you work for a company which, by the way or place in which your code was written, by your contract terms -or by the laws in your country, could claim any rights (including but not limited to intellectual or industrial -property) over your contributed code, you will have to send the project members (either by email from your -authorised superiors or by signed fax), a statement indicating that your company agrees with the terms -explained in this page, and that it both authorises your contribution to Thymeleaf and states that it will -never claim any kind of rights over it. - - -Thymeleaf Individual Contributor License Agreement --------------------------------------------------- - -This contributor agreement ("Agreement") documents the rights granted by contributors to the Thymeleaf Project. - -This is a legally binding document, so please read it carefully before agreeing to it. The Agreement -may cover more than one software project managed by Thymeleaf. - - -### 1. Definitions - - * _"Thymeleaf"_ means the "Thymeleaf Project organization and members". - * _"You"_ means the individual who submits a Contribution to Thymeleaf. - * _"Contribution"_ means any work of authorship that is submitted by you to Thymeleaf in which you own - or assert ownership of the Copyright. - * _"Copyright"_ means all rights protecting works of authorship owned or controlled by you, - including copyright, moral and neighboring rights, as appropriate, for the full term of their - existence including any extensions by you. - * _"Material"_ means the work of authorship which is made available by Thymeleaf to third parties. When - this Agreement covers more than one software project, the Material means the work of authorship - to which the Contribution was submitted. After you submit the Contribution, it may be included - in the Material. - * _"Submit"_ means any form of electronic, verbal, or written communication sent to Thymeleaf or its - representatives, including but not limited to electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, Thymeleaf for the purpose of discussing - and improving the Material, but excluding communication that is conspicuously marked or - otherwise designated in writing by you as _"Not a Contribution."_ - * _"Submission Date"_ means the date on which you submit a Contribution to Thymeleaf. - * _"Effective Date"_ means the date you execute this agreement or the date You first submit a - Contribution to Thymeleaf, whichever is earlier. - - -### 2. Grant of Rights - -#### 2.1. Copyright License - - * (a) You retain ownership of the copyright in your Contribution and have the same rights to use or - license the Contribution which you would have had without entering into the agreement. - * (b) To the maximum extent permitted by the relevant law, you grant to Thymeleaf a perpetual, worldwide, - non-exclusive, transferable, royalty-free, irrevocable license under the copyright covering the - Contribution, with the right to sublicense such rights through multiple tiers of sublicensees, to - reproduce, modify, display, perform and distribute the Contribution as part of the Material; provided - that this license is conditioned upon compliance with Section 2.3. +## Conventions and Housekeeping -#### 2.2 Patent License +### General Guidelines: -For patent claims including, without limitation, method, process, and apparatus claims which you -own, control or have the right to grant, now or in the future, you grant to Thymeleaf a perpetual, worldwide, -non-exclusive, transferable, royalty-free, irrevocable patent license, with the right to sublicense these -rights to multiple tiers of sublicensees, to make, have made, use, sell, offer for sale, import and -otherwise transfer the Contribution and the Contribution in combination with the Material (and -portions of such combination). This license is granted only to the extent that the exercise of the -licensed rights infringes such patent claims; and provided that this license is conditioned upon -compliance with Section 2.3. + - Obviously, **your code must both compile and work correctly**. + - All your code should be easy to read and understand by a human. The same + requirement applies to documentation. + - Unless for specific artifacts such as documentation translations, all + code, comments, documentation, names of classes and variables, + log messages, etc. must be **in English**. + - All contribured files must include the standard Thymeleaf copyright header. + - Maximum recommended line length is 120 characters. This is not strictly + enforced. + - Indentation should be made with 4 spaces, not tabs. Line feeds should be + UNIX-like (`\n`). + - All source files should be pure ASCII, except `.properties` files which + should be ISO-8859-1. + - You shall add yourself as _author_ (e.g. Javadoc `@author`) to any files + that you create or modify substantially (more than cosmetic changes). -#### 2.3 Outbound License +### Specific Java Code Gudelines: -As a condition on the grant of rights in Sections 2.1 and 2.2, Thymeleaf agrees to license the Contribution only -under the terms of the Apache License 2.0 (including any right to adopt any future version of this license if -permitted). - -#### 2.4 Moral Rights - -If moral rights apply to the Contribution, to the maximum extent permitted by law, you waive and agree not -to assert such moral rights against Thymeleaf or its successors in interest, or any of our licensees, either -direct or indirect. - -#### 2.5 Thymeleaf Rights - -You acknowledge that Thymeleaf is not obligated to use your Contribution as part of the -Material and may decide to include any Contributions Thymeleaf considers appropriate. - -#### 2.6 Reservation of Rights - -Any rights not expressly assigned or licensed under this section are expressly reserved by you. - - -### 3. Agreement - -You confirm that: - - * (a) You have the legal authority to enter into this Agreement. - * (b) You own the Copyright and patent claims covering the Contribution which are required to grant - the rights under Section 2. - * (c) The grant of rights under Section 2 does not violate any grant of rights which you have made to - third parties, including your employer. If you are an employee, you have had your employer approve - this Agreement. If you are less than eighteen years old, please have your parents or guardian - sign the Agreement. - - -### 4. Disclaimer - -EXCEPT FOR THE EXPRESS WARRANTIES IN SECTION 3, THE CONTRIBUTION IS PROVIDED "AS IS". MORE PARTICULARLY, -ALL EXPRESS OR IMPLIED WARRANTIES INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTY OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE EXPRESSLY DISCLAIMED BY YOU TO THYMELEAF AND BY -THYMELEAF TO YOU. TO THE EXTENT THAT ANY SUCH WARRANTIES CANNOT BE DISCLAIMED, SUCH WARRANTY IS LIMITED IN -DURATION TO THE MINIMUM PERIOD PERMITTED BY LAW. - - -### 5. Consequential Damage Waiver - -TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT WILL YOU OR THYMELEAF BE LIABLE FOR ANY LOSS OF -PROFITS, LOSS OF ANTICIPATED SAVINGS, LOSS OF DATA, INDIRECT, SPECIAL, INCIDENTAL, CONSEQUENTIAL AND EXEMPLARY -DAMAGES ARISING OUT OF THIS AGREEMENT REGARDLESS OF THE LEGAL OR EQUITABLE THEORY (CONTRACT, TORT OR OTHERWISE) -UPON WHICH THE CLAIM IS BASED. - - -### 6. Miscellaneous - - * 6.1 This Agreement will be governed by and construed in accordance with the laws of Spain excluding its - conflicts of law provisions. Under certain circumstances, the governing law in this section might be - superseded by the United Nations Convention on Contracts for the International Sale of Goods ("UN - Convention") and the parties intend to avoid the application of the UN Convention to this Agreement - and, thus, exclude the application of the UN Convention in its entirety to this Agreement. - * 6.2 This Agreement sets out the entire agreement between you and Thymeleaf for your Contributions to Thymeleaf - and overrides all other agreements or understandings. - * 6.3 If You or Thymeleaf assign the rights or obligations received through this Agreement to a third party, as a - condition of the assignment, that third party must agree in writing to abide by all the rights and - obligations in the Agreement. - * 6.4 The failure of either party to require performance by the other party of any provision of this - Agreement in one situation shall not affect the right of a party to require such performance at any time - in the future. A waiver of performance under a provision in one situation shall not be considered a - waiver of the performance of the provision in the future or a waiver of the provision in its entirety. - * 6.5 If any provision of this Agreement is found void and unenforceable, such provision will be - replaced to the extent possible with a provision that comes closest to the meaning of the original - provision and which is enforceable. The terms and conditions set forth in this Agreement shall apply - notwithstanding any failure of essential purpose of this Agreement or any limited remedy to the - maximum extent possible under law. + - All your code should compile and run in the current minimum Java version + of the project. + - All your code should follow the Java Code Conventions regarding + variable/method/class naming. + - Number autoboxing and/or autounboxing is forbidden. + - Every class should define a constructor, even if it is the no-argument + constructor, and include a call to `super()`. + - All method parameters should be declared as `final` so that they cannot be + changed or reassigned in the method. + - All non-nullable parameters in public methods should be first validated for + non-nullity inside the code. + - Existing Javadoc must be maintained along with performed changes. Addition + of new Javadoc for public methods or code comments for any non-trivial + algorithms is always welcome. + - Writing unit tests for new, existing and modified code is always welcome + too. For any new algorithms or functionality contributed, or substantial + modifications made to existing ones, the team might consider these a + requirement. + + + + +[cla]: https://github.com/thymeleaf/thymeleaf-org/blob/CLA_CURRENT/CLA/ +[code-of-coduct]: https://github.com/thymeleaf/thymeleaf-org/blob/CoC_CURRENT/CoC/THYMELEAF_CODE_OF_CONDUCT.markdown +[thymeleaf-team]: https://www.thymeleaf.org/team.html +[stackoverflow]: https://stackoverflow.com +[stackoverflow-thymeleaf]: https://stackoverflow.com/tags/thymeleaf diff --git a/ChangeLog.txt b/ChangeLog.txt index 041db10c5..06dec4ba8 100755 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,6 +1,48 @@ +3.0.16 +====== +- Updated AttoParser dependency to 2.0.6.RELEASE + + +3.0.15 +====== +- Fixed expression parsing inconsistency provoked by empty literal substitutions. +- Blocked static and constructor access to certain classes. +- Block calling methods of blocked classes in expressions. + + +3.0.14 +====== +- Fixed inconsistent restricted variable access check due to caching. +- Improved detection of restricted expression execution scenarios. + + +3.0.13 +====== +(no relevant changes in core module) + + +3.0.12 +====== +- Fixed #numbers.format*() expression utility methods not producing numbers using the correct digit symbols for + locales that use them, in JDK versions where NumberFormat does this (currently >= JDK15). +- Fixed "package-list" not being produced for JavaDoc since JDK 11 started being used for compiling the project. +- Added instantiation of new objects and calls to static classes as forbidden operations in restricted mode. +- Updated OGNL dependency to 3.1.26. +- Updated jackson-databind to 2.11.3 and jackson-datatype to 2.11.3 (due to vulnerabilities in previous versions). + + +3.0.11 +====== +- Updated jackson-databind dependency to 2.9.7 (due to vulnerabilities in previous jackson version). + + 3.0.10 ====== - Fixed StackOverflowError when inserting content before first element of model in a model processor. +- Improved restricted expression evaluation mode to forbid output of textual data from context variables inside + JavaScript event handlers in HTML templates. +- Improved HTML event handler attributes (th:on*) in order to allow processing of their values as fragments + of inlined JavaScript (using JAVASCRIPT template mode). - Improved use of template name abbreviation in logs and exceptions. - Added "Automatic-Module-Name: thymeleaf" to MANIFEST.MF for Java 9+ JPMS. - Updated AttoParser dependency to 2.0.5.RELEASE diff --git a/pom.xml b/pom.xml index 246eb4791..0bd206b1f 100755 --- a/pom.xml +++ b/pom.xml @@ -26,7 +26,7 @@ org.thymeleaf thymeleaf jar - 3.0.10-SNAPSHOT + 3.0.16-SNAPSHOT thymeleaf http://www.thymeleaf.org @@ -94,19 +94,24 @@ - 1.6 - 1.6 + 6 + ${java.version} + ${java.version} + ${java.version} US-ASCII + ISO-8859-1 ${maven.build.timestamp} yyyy-MM-dd'T'HH:mm:ssZ - ${project.artifactId} + + + thymeleaf 2.5 - 3.1.12 - 2.0.5.RELEASE + 3.1.26 + 2.0.6.RELEASE 1.1.6.RELEASE - 2.6.3 + 2.11.3 1.7.25 @@ -163,27 +168,23 @@ org.apache.maven.plugins maven-compiler-plugin - 3.7.0 - - ${maven.compile.source} - ${maven.compile.target} - ${project.build.sourceEncoding} - + 3.8.1 org.apache.maven.plugins maven-resources-plugin - 3.0.2 + 3.2.0 ${project.build.sourceEncoding} + ${project.build.propertiesEncoding} org.apache.maven.plugins maven-jar-plugin - 3.0.2 + 3.2.0 false @@ -195,8 +196,8 @@ - ${maven.compile.source} - ${maven.compile.target} + ${maven.compiler.source} + ${maven.compiler.target} thymeleaf @@ -210,13 +211,17 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.0.0 + 3.3.1 protected java.lang + ${maven.compiler.source} + ${maven.compiler.release} ${basedir}/src/main/javadoc/overview.html ${basedir}/src/main/javadoc - ${project.reporting.outputDirectory}/api/${project.artifactId}/apidocs + ${project.build.directory}/apidocs + + --no-module-directories @@ -231,7 +236,7 @@ org.apache.maven.plugins maven-source-plugin - 3.0.1 + 3.2.1 package @@ -257,12 +262,46 @@ + + org.apache.maven.plugins + maven-deploy-plugin + 2.8.2 + + org.apache.maven.plugins maven-release-plugin 2.5.3 + + + org.apache.maven.plugins + maven-antrun-plugin + 3.0.0 + + + + + + + + + + copy-javadoc-element-list-to-package-list + package + + run + + + + + + + + + + diff --git a/src/main/java/org/thymeleaf/EngineConfiguration.java b/src/main/java/org/thymeleaf/EngineConfiguration.java index f1bdb3b80..6d61b68be 100644 --- a/src/main/java/org/thymeleaf/EngineConfiguration.java +++ b/src/main/java/org/thymeleaf/EngineConfiguration.java @@ -321,9 +321,9 @@ public boolean isModelReshapeable(final TemplateMode templateMode) { /** - * Compares Integer types, taking into account possible null - * values. When null, then the return value will be such that the - * other value will come first in a comparison. If both values are null, + * Compares {@code Integer} types, taking into account possible {@code null} + * values. When {@code null}, then the return value will be such that the + * other value will come first in a comparison. If both values are {@code null}, * then they are effectively equal. * * @param o1 The first value to compare. diff --git a/src/main/java/org/thymeleaf/ITemplateEngine.java b/src/main/java/org/thymeleaf/ITemplateEngine.java index 97c92fd0c..8366aa1fb 100644 --- a/src/main/java/org/thymeleaf/ITemplateEngine.java +++ b/src/main/java/org/thymeleaf/ITemplateEngine.java @@ -89,7 +89,7 @@ public interface ITemplateEngine { *

* Template selectors allow the possibility to process only a part of the specified template, expressing * this selection in a syntax similar to jQuery, CSS or XPath selectors. Note this is only available for - * markup template modes (HTML, XML). For more info on template selectors + * markup template modes ({@code HTML}, {@code XML}). For more info on template selectors * syntax, have a look at AttoParser's markup selectors * documentation. *

@@ -161,7 +161,7 @@ public interface ITemplateEngine { *

* Template selectors allow the possibility to process only a part of the specified template, expressing * this selection in a syntax similar to jQuery, CSS or XPath selectors. Note this is only available for - * markup template modes (HTML, XML). For more info on template selectors + * markup template modes ({@code HTML}, {@code XML}). For more info on template selectors * syntax, have a look at AttoParser's markup selectors * documentation. *

@@ -235,7 +235,7 @@ public interface ITemplateEngine { *

* Template selectors allow the possibility to process only a part of the specified template, expressing * this selection in a syntax similar to jQuery, CSS or XPath selectors. Note this is only available for - * markup template modes (HTML, XML). For more info on template selectors + * markup template modes ({@code HTML}, {@code XML}). For more info on template selectors * syntax, have a look at AttoParser's markup selectors * documentation. *

diff --git a/src/main/java/org/thymeleaf/IThrottledTemplateProcessor.java b/src/main/java/org/thymeleaf/IThrottledTemplateProcessor.java index bad9e3d6c..415a1d59e 100644 --- a/src/main/java/org/thymeleaf/IThrottledTemplateProcessor.java +++ b/src/main/java/org/thymeleaf/IThrottledTemplateProcessor.java @@ -27,13 +27,13 @@ *

* Interface defining operations that can regulate the pace at which the template engine will process a * template (a.k.a. engine throttling). Objects implementing this interface are returned by - * the processThrottled(...) methods at {@link ITemplateEngine}. + * the {@code processThrottled(...)} methods at {@link ITemplateEngine}. *

*

* When the processing of a template is throttled the client classes can tell the engine how much output - * they are prepared to handle by calling any of the process(int,...) methods. As a response to this, + * they are prepared to handle by calling any of the {@code process(int,...)} methods. As a response to this, * the engine will process only the part of the template enough to write at most so many chars - * or bytes as specified at the processThrottled(...) call. Output will be written to a {@link Writer} + * or bytes as specified at the {@code processThrottled(...)} call. Output will be written to a {@link Writer} * in the form of chars, or to an {@link OutputStream} in the form of bytes. *

*

@@ -93,7 +93,7 @@ public interface IThrottledTemplateProcessor { *

*

* NOTE Implementations of this method must be thread-safe as, even if executions - * of the throttled processor (calls to process(...) methods) should never happen concurrently, + * of the throttled processor (calls to {@code process(...)} methods) should never happen concurrently, * determining whether a throttled processor has finished or not can happen concurrently from different * threads as a way of short-cutting the execution of the processor (and avoid excessive consumption of * upstream data, for example). diff --git a/src/main/java/org/thymeleaf/TemplateEngine.java b/src/main/java/org/thymeleaf/TemplateEngine.java index 00533f69c..09f198ff9 100755 --- a/src/main/java/org/thymeleaf/TemplateEngine.java +++ b/src/main/java/org/thymeleaf/TemplateEngine.java @@ -63,7 +63,7 @@ * This is the only implementation of {@link ITemplateEngine} provided out of the box by Thymeleaf. *

* - *

Creating an instance of TemplateEngine

+ *

Creating an instance of {@code TemplateEngine}

*

* An instance of this class can be created at any time by calling its constructor: *

@@ -71,14 +71,14 @@ * final TemplateEngine templateEngine = new TemplateEngine(); * *

- * Creation and configuration of TemplateEngine instances is expensive, so it is + * Creation and configuration of {@code TemplateEngine} instances is expensive, so it is * recommended to create only one instance of this class (or at least one instance per * dialect/configuration) and use it to process multiple templates. *

* - *

Configuring the TemplateEngine

+ *

Configuring the {@code TemplateEngine}

*

- * Once created, an instance of TemplateEngine has to be typically configured a + * Once created, an instance of {@code TemplateEngine} has to be typically configured a * mechanism for resolving templates (i.e. obtaining and reading them): *

*
    @@ -176,7 +176,7 @@ * {@link javax.servlet.ServletContext} objects as constructor arguments: *

    * - * final IContext ctx = new WebContext(request, response, servletContext);
    + * final WebContext ctx = new WebContext(request, response, servletContext);
    * ctx.setVariable("allItems", items); *
    *

    @@ -185,9 +185,9 @@ * *

    2. Template Processing

    *

    - * In order to execute templates, the different process(...) methods should + * In order to execute templates, the different {@code process(...)} methods should * be used. Those are mostly divided into two blocks: those that return the template processing - * result as a String, and those that receive a {@link Writer} as an argument + * result as a {@code String}, and those that receive a {@link Writer} as an argument * and use it for writing the result instead. *

    *

    @@ -206,7 +206,7 @@ * templateEngine.process("mytemplate", ctx, httpServletResponse.getWriter()); * *

    - * The "mytemplate" String argument is the template name, and it + * The {@code "mytemplate"} String argument is the template name, and it * will relate to the physical/logical location of the template itself in a way * configured at the template resolver/s. *

    @@ -225,11 +225,11 @@ public class TemplateEngine implements ITemplateEngine { /** *

    - * Name of the TIMER logger. This logger will output the time required + * Name of the {@code TIMER} logger. This logger will output the time required * for executing each template processing operation. *

    *

    - * The value of this constant is org.thymeleaf.TemplateEngine.TIMER. This + * The value of this constant is {@code org.thymeleaf.TemplateEngine.TIMER}. This * allows you to set a specific configuration and/or appenders for timing info at your logging * system configuration. *

    @@ -261,10 +261,10 @@ public class TemplateEngine implements ITemplateEngine { /** *

    - * Constructor for TemplateEngine objects. + * Constructor for {@code TemplateEngine} objects. *

    *

    - * This is the only way to create a TemplateEngine instance (which + * This is the only way to create a {@code TemplateEngine} instance (which * should be configured after creation). *

    */ @@ -309,7 +309,7 @@ private void checkNotInitialized() { * THIS METHOD IS INTERNAL AND SHOULD NEVER BE CALLED DIRECTLY. *

    *

    - * If a subclass of TemplateEngine needs additional steps for + * If a subclass of {@code TemplateEngine} needs additional steps for * initialization, the {@link #initializeSpecific()} method should * be overridden. *

    @@ -360,7 +360,7 @@ final void initialize() { /** *

    * This method performs additional initializations required for a - * TemplateEngine subclass instance. This method + * {@code TemplateEngine} subclass instance. This method * is called before the first execution of * {@link TemplateEngine#process(String, org.thymeleaf.context.IContext)} * or {@link TemplateEngine#processThrottled(String, org.thymeleaf.context.IContext)} @@ -372,7 +372,7 @@ final void initialize() { *

    *

    * The base implementation of this method does nothing, and it is designed - * for being overridden by subclasses of TemplateEngine. + * for being overridden by subclasses of {@code TemplateEngine}. *

    */ protected void initializeSpecific() { @@ -383,16 +383,16 @@ protected void initializeSpecific() { /** *

    - * Checks whether the TemplateEngine has already been initialized - * or not. A TemplateEngine is initialized when the {@link #initialize()} + * Checks whether the {@code TemplateEngine} has already been initialized + * or not. A {@code TemplateEngine} is initialized when the {@link #initialize()} * method is called the first time a template is processed. *

    *

    * Normally, there is no good reason why users would need to call this method. *

    * - * @return true if the template engine has already been initialized, - * false if not. + * @return {@code true} if the template engine has already been initialized, + * {@code false} if not. */ public final boolean isInitialized() { return this.initialized; diff --git a/src/main/java/org/thymeleaf/TemplateSpec.java b/src/main/java/org/thymeleaf/TemplateSpec.java index 0509e9787..777f8d4c1 100644 --- a/src/main/java/org/thymeleaf/TemplateSpec.java +++ b/src/main/java/org/thymeleaf/TemplateSpec.java @@ -36,7 +36,7 @@ *

    * Specification class containing everything needed by the template engine related to the * template to be processed. Objects of this class are normally used as an argument to the - * different process(...) methods at {@link ITemplateEngine}. + * different {@code process(...)} methods at {@link ITemplateEngine}. *

    *

    * The only required value in a template specification is the template, which normally @@ -107,7 +107,7 @@ public TemplateSpec(final String template, final TemplateMode templateMode) { *

    * Build a new object of this class, specifying template and also output content type * (MIME type). Most of the times this will force a template mode for template execution - * (e.g. text/html, application/javascript), but not always (e.g. text/event-stream). + * (e.g. {@code text/html}, {@code application/javascript}), but not always (e.g. {@code text/event-stream}). *

    *

    * The template normally represents the template name, but can be the entire template @@ -118,16 +118,16 @@ public TemplateSpec(final String template, final TemplateMode templateMode) { * Supported relations between template mode and output content type are: *

    *
      - *
    • HTML: text/html, application/xhtml+xml
    • - *
    • XML: application/xml
    • - *
    • JAVASCRIPT: application/javascript, application/x-javascript, - * application/ecmascript, text/javascript, - * text/ecmascript, application/json
    • - *
    • CSS: text/css
    • - *
    • TEXT: text/plain
    • + *
    • HTML: {@code text/html}, {@code application/xhtml+xml}
    • + *
    • XML: {@code application/xml}
    • + *
    • JAVASCRIPT: {@code application/javascript}, {@code application/x-javascript}, + * {@code application/ecmascript}, {@code text/javascript}, + * {@code text/ecmascript}, {@code application/json}
    • + *
    • CSS: {@code text/css}
    • + *
    • TEXT: {@code text/plain}
    • *
    *

    - * The text/event-stream content type will also be supported, but will have no effect in + * The {@code text/event-stream} content type will also be supported, but will have no effect in * forcing a template mode. Instead, it will put the engine into Server-Sent Event (SSE) output mode. *

    *

    @@ -166,7 +166,7 @@ public TemplateSpec(final String template, final String outputContentType) { * so they will be used as a part of the keys for cached templates. It is therefore * required that template attribute maps contain values with valid {@link #equals(Object)} * and {@link #hashCode()} implementations. Therefore, using simple (and fast) - * Map<String,String> maps is the recommended option. + * {@code Map} maps is the recommended option. *

    *

    * This constructor will set no template selectors or forced template mode. @@ -193,7 +193,7 @@ public TemplateSpec(final String template, final Map templateRes *

    * Template selectors allow the possibility to process only a part of the specified template, expressing * this selection in a syntax similar to jQuery, CSS or XPath selectors. Note this is only available for - * markup template modes (HTML, XML). For more info on template selectors + * markup template modes ({@code HTML}, {@code XML}). For more info on template selectors * syntax, have a look at AttoParser's markup selectors * documentation. *

    @@ -212,7 +212,7 @@ public TemplateSpec(final String template, final Map templateRes * so they will be used as a part of the keys for cached templates. It is therefore * required that template attribute maps contain values with valid {@link #equals(Object)} * and {@link #hashCode()} implementations. Therefore, using simple (and fast) - * Map<String,String> maps is the recommended option. + * {@code Map} maps is the recommended option. *

    * * @param template the template (usually the template name), required. @@ -230,8 +230,8 @@ public TemplateSpec( /** *

    * Build a new object of this class, specifying an output content type (MIME type). Most of the times this - * will force a template mode for template execution (e.g. text/html, application/javascript), - * but not always (e.g. text/event-stream). + * will force a template mode for template execution (e.g. {@code text/html}, {@code application/javascript}), + * but not always (e.g. {@code text/event-stream}). *

    *

    * The template usually represents the template name, but can be the entire template @@ -241,7 +241,7 @@ public TemplateSpec( *

    * Template selectors allow the possibility to process only a part of the specified template, expressing * this selection in a syntax similar to jQuery, CSS or XPath selectors. Note this is only available for - * markup template modes (HTML, XML). For more info on template selectors + * markup template modes ({@code HTML}, {@code XML}). For more info on template selectors * syntax, have a look at AttoParser's markup selectors * documentation. *

    @@ -254,16 +254,16 @@ public TemplateSpec( * Supported relations between template mode and output content type are: *

    *
      - *
    • HTML: text/html, application/xhtml+xml
    • - *
    • XML: application/xml
    • - *
    • JAVASCRIPT: application/javascript, application/x-javascript, - * application/ecmascript, text/javascript, - * text/ecmascript, application/json
    • - *
    • CSS: text/css
    • - *
    • TEXT: text/plain
    • + *
    • HTML: {@code text/html}, {@code application/xhtml+xml}
    • + *
    • XML: {@code application/xml}
    • + *
    • JAVASCRIPT: {@code application/javascript}, {@code application/x-javascript}, + * {@code application/ecmascript}, {@code text/javascript}, + * {@code text/ecmascript}, {@code application/json}
    • + *
    • CSS: {@code text/css}
    • + *
    • TEXT: {@code text/plain}
    • *
    *

    - * The text/event-stream content type will also be supported, but will have no effect in + * The {@code text/event-stream} content type will also be supported, but will have no effect in * forcing a template mode. Instead, it will put the engine into Server-Sent Event (SSE) output mode. *

    *

    @@ -274,7 +274,7 @@ public TemplateSpec( * so they will be used as a part of the keys for cached templates. It is therefore * required that template attribute maps contain values with valid {@link #equals(Object)} * and {@link #hashCode()} implementations. Therefore, using simple (and fast) - * Map<String,String> maps is the recommended option. + * {@code Map} maps is the recommended option. *

    * * @param template the template (usually the template name), required. @@ -378,7 +378,7 @@ public String getTemplate() { * Returns whether this spec has template selectors specified or not. *

    * - * @return true of there are template selectors, false if not. + * @return {@code true} of there are template selectors, {@code false} if not. */ public boolean hasTemplateSelectors() { // Checking for null is enough, as we have already processed this in the constructor @@ -393,12 +393,12 @@ public boolean hasTemplateSelectors() { *

    * Template selectors allow the possibility to process only a part of the specified template, expressing * this selection in a syntax similar to jQuery, CSS or XPath selectors. Note this is only available for - * markup template modes (HTML, XML). For more info on template selectors + * markup template modes ({@code HTML}, {@code XML}). For more info on template selectors * syntax, have a look at AttoParser's markup selectors * documentation. *

    * - * @return the template selectors, or null if there are none. + * @return the template selectors, or {@code null} if there are none. */ public Set getTemplateSelectors() { return this.templateSelectors; @@ -410,7 +410,7 @@ public Set getTemplateSelectors() { * Returns whether this spec has template mode specified or not. *

    * - * @return true of there is a template mode, false if not. + * @return {@code true} of there is a template mode, {@code false} if not. */ public boolean hasTemplateMode() { return this.templateMode != null; @@ -427,7 +427,7 @@ public boolean hasTemplateMode() { * template resolvers. *

    * - * @return the template mode specified, or null if there isn't any. + * @return the template mode specified, or {@code null} if there isn't any. */ public TemplateMode getTemplateMode() { return this.templateMode; @@ -439,7 +439,7 @@ public TemplateMode getTemplateMode() { * Returns whether this spec includes template resolution attributes or not. *

    * - * @return true of there are template resolution attributes, false if not. + * @return {@code true} of there are template resolution attributes, {@code false} if not. */ public boolean hasTemplateResolutionAttributes() { // Checking for null is enough, as we have already processed this in the constructor @@ -461,7 +461,7 @@ public boolean hasTemplateResolutionAttributes() { * so they will be used as a part of the keys for cached templates. It is therefore * required that template attribute maps contain values with valid {@link #equals(Object)} * and {@link #hashCode()} implementations. Therefore, using simple (and fast) - * Map<String,String> maps is the recommended option. + * {@code Map} maps is the recommended option. *

    * * @return the template resolution attributes. @@ -474,30 +474,30 @@ public Map getTemplateResolutionAttributes() { /** *

    * Returns the output content type (MIME type). Most of the times this - * will force a template mode for template execution (e.g. text/html, application/javascript), - * but not always (e.g. text/event-stream). + * will force a template mode for template execution (e.g. {@code text/html}, {@code application/javascript}), + * but not always (e.g. {@code text/event-stream}). *

    *

    * Supported relations between template mode and output content type are: *

    *
      - *
    • HTML: text/html, application/xhtml+xml
    • - *
    • XML: application/xml
    • - *
    • JAVASCRIPT: application/javascript, application/x-javascript, - * application/ecmascript, text/javascript, - * text/ecmascript, application/json
    • - *
    • CSS: text/css
    • - *
    • TEXT: text/plain
    • + *
    • HTML: {@code text/html}, {@code application/xhtml+xml}
    • + *
    • XML: {@code application/xml}
    • + *
    • JAVASCRIPT: {@code application/javascript}, {@code application/x-javascript}, + * {@code application/ecmascript}, {@code text/javascript}, + * {@code text/ecmascript}, {@code application/json}
    • + *
    • CSS: {@code text/css}
    • + *
    • TEXT: {@code text/plain}
    • *
    *

    - * The text/event-stream content type will also be supported, but will have no effect in + * The {@code text/event-stream} content type will also be supported, but will have no effect in * forcing a template mode. Instead, it will put the engine into Server-Sent Event (SSE) output mode. *

    *

    * Note content type parameters will be ignored (only the mime type itself will be used). *

    * - * @return the output content type, or null if none was specified. + * @return the output content type, or {@code null} if none was specified. */ public String getOutputContentType() { return this.outputContentType; @@ -509,7 +509,7 @@ public String getOutputContentType() { * Returns whether output should be Server-Sent Events (SSE) or not. *

    *

    - * Server-Sent Events mode is enabled by setting the text/event-stream mime type + * Server-Sent Events mode is enabled by setting the {@code text/event-stream} mime type * as *output content type* constructor argument. *

    * diff --git a/src/main/java/org/thymeleaf/Thymeleaf.java b/src/main/java/org/thymeleaf/Thymeleaf.java index 85aab7b46..d66081c2f 100644 --- a/src/main/java/org/thymeleaf/Thymeleaf.java +++ b/src/main/java/org/thymeleaf/Thymeleaf.java @@ -22,6 +22,7 @@ import java.util.Properties; import org.thymeleaf.util.ClassLoaderUtils; +import org.thymeleaf.util.VersionUtils; /** @@ -36,15 +37,37 @@ */ public final class Thymeleaf { + private static final String STABLE_RELEASE_QUALIFIER = "RELEASE"; + + /** + * @deprecated Deprecated in 3.0.12. Use {@link #getVersion()} instead. Will be removed in Thymeleaf 3.1. + */ public static final String VERSION; + /** + * @deprecated Deprecated in 3.0.12. Use {@link #getBuildTimestamp()} instead. Will be removed in Thymeleaf 3.1. + */ public static final String BUILD_TIMESTAMP; - + /** + * @deprecated Deprecated in 3.0.12. Use {@link #getVersionMajor()} instead. Will be removed in Thymeleaf 3.1. + */ public static final int VERSION_MAJOR; + /** + * @deprecated Deprecated in 3.0.12. Use {@link #getVersionMinor()} instead. Will be removed in Thymeleaf 3.1. + */ public static final int VERSION_MINOR; + /** + * @deprecated Deprecated in 3.0.12. Use {@link #getVersionPatch()} instead. Will be removed in Thymeleaf 3.1. + */ public static final int VERSION_BUILD; + /** + * @deprecated Deprecated in 3.0.12. Use {@link #getVersionQualifier()} instead. Will be removed in Thymeleaf 3.1. + */ public static final String VERSION_TYPE; + private static final VersionUtils.VersionSpec VERSION_SPEC; + + static { String version = null; @@ -58,51 +81,51 @@ public final class Thymeleaf { // Ignored: we don't have such information, might be due to IDE configuration } - VERSION = version; - BUILD_TIMESTAMP = buildTimestamp; - if (VERSION == null || VERSION.trim().length() == 0) { + VERSION_SPEC = VersionUtils.parseVersion(version, buildTimestamp); - VERSION_MAJOR = 0; - VERSION_MINOR = 0; - VERSION_BUILD = 0; - VERSION_TYPE = "UNKNOWN"; + VERSION = VERSION_SPEC.getVersion(); + BUILD_TIMESTAMP = VERSION_SPEC.getBuildTimestamp(); + VERSION_MAJOR = VERSION_SPEC.getMajor(); + VERSION_MINOR = VERSION_SPEC.getMinor(); + VERSION_BUILD = VERSION_SPEC.getPatch(); + VERSION_TYPE = VERSION_SPEC.getQualifier(); - } else { + } - try { - String versionRemainder = VERSION; - int separatorIdx = versionRemainder.indexOf('.'); - VERSION_MAJOR = Integer.parseInt(versionRemainder.substring(0,separatorIdx)); - versionRemainder = versionRemainder.substring(separatorIdx + 1); - separatorIdx = versionRemainder.indexOf('.'); - VERSION_MINOR = Integer.parseInt(versionRemainder.substring(0, separatorIdx)); - versionRemainder = versionRemainder.substring(separatorIdx + 1); - separatorIdx = versionRemainder.indexOf('.'); - if (separatorIdx < 0) { - separatorIdx = versionRemainder.indexOf('-'); - } - VERSION_BUILD = Integer.parseInt(versionRemainder.substring(0, separatorIdx)); - VERSION_TYPE = versionRemainder.substring(separatorIdx + 1); - } catch (final Exception e) { - throw new ExceptionInInitializerError( - "Exception during initialization of Thymeleaf versioning utilities. Identified Thymeleaf " + - "version is '" + VERSION + "', which does not follow the {major}.{minor}.{build}[.|-]{type} " + - "scheme"); - } - } + public static String getVersion() { + return VERSION_SPEC.getVersion(); + } + + public static String getBuildTimestamp() { + return VERSION_SPEC.getBuildTimestamp(); + } + + public static int getVersionMajor() { + return VERSION_SPEC.getMajor(); + } + + public static int getVersionMinor() { + return VERSION_SPEC.getMinor(); + } + + public static int getVersionPatch() { + return VERSION_SPEC.getPatch(); + } + public static String getVersionQualifier() { + return VERSION_SPEC.getQualifier(); } public static boolean isVersionStableRelease() { - return "RELEASE".equals(VERSION_TYPE); + return STABLE_RELEASE_QUALIFIER.equals(VERSION_SPEC.getQualifier()); } diff --git a/src/main/java/org/thymeleaf/cache/AbstractCacheManager.java b/src/main/java/org/thymeleaf/cache/AbstractCacheManager.java index 09a32106f..f05e90568 100755 --- a/src/main/java/org/thymeleaf/cache/AbstractCacheManager.java +++ b/src/main/java/org/thymeleaf/cache/AbstractCacheManager.java @@ -29,7 +29,7 @@ *

    * Common abstract class for {@link ICacheManager} implementations, useful * for taking care of the lazy initialization of cache objects when their - * corresponding getXCache() methods are called. + * corresponding {@code getXCache()} methods are called. *

    *

    * Note a class with this name existed since 2.0.0, but it was completely reimplemented diff --git a/src/main/java/org/thymeleaf/cache/ICache.java b/src/main/java/org/thymeleaf/cache/ICache.java index 7a7b24f52..742f4879f 100755 --- a/src/main/java/org/thymeleaf/cache/ICache.java +++ b/src/main/java/org/thymeleaf/cache/ICache.java @@ -94,7 +94,7 @@ public interface ICache { *

    * Returns all the keys contained in this cache. Note this method might return keys for entries * that are already invalid, so the result of calling {@link #get(Object)} for these keys might - * be null. + * be {@code null}. *

    * * @return the complete set of cache keys. Might include keys for already-invalid (non-cleaned) entries. diff --git a/src/main/java/org/thymeleaf/cache/ICacheEntryValidity.java b/src/main/java/org/thymeleaf/cache/ICacheEntryValidity.java index 67f2665c7..8e33df7ae 100755 --- a/src/main/java/org/thymeleaf/cache/ICacheEntryValidity.java +++ b/src/main/java/org/thymeleaf/cache/ICacheEntryValidity.java @@ -47,8 +47,8 @@ public interface ICacheEntryValidity { * or not. *

    * - * @return true if the parsed template can be included into the cache, - * false if not. + * @return {@code true} if the parsed template can be included into the cache, + * {@code false} if not. */ public boolean isCacheable(); diff --git a/src/main/java/org/thymeleaf/cache/ICacheEntryValidityChecker.java b/src/main/java/org/thymeleaf/cache/ICacheEntryValidityChecker.java index cbdf8dbb0..68c3ff911 100755 --- a/src/main/java/org/thymeleaf/cache/ICacheEntryValidityChecker.java +++ b/src/main/java/org/thymeleaf/cache/ICacheEntryValidityChecker.java @@ -24,7 +24,7 @@ /** *

    * Defines the logic needed to (optionally) validate an entry living in an - * {@link ICache} object before returning it as the result of a get + * {@link ICache} object before returning it as the result of a {@code get} * operation. If not valid, the entry will be removed * from the cache (and null will be returned). *

    diff --git a/src/main/java/org/thymeleaf/cache/ICacheManager.java b/src/main/java/org/thymeleaf/cache/ICacheManager.java index 85d4e5935..0bf827e15 100755 --- a/src/main/java/org/thymeleaf/cache/ICacheManager.java +++ b/src/main/java/org/thymeleaf/cache/ICacheManager.java @@ -30,7 +30,7 @@ *

    *

    * This class is in charge of providing the corresponding cache objects to - * the template engine. Every call to each of the getXCache() + * the template engine. Every call to each of the {@code getXCache()} * methods must always return the XCache object (i.e. only one cache object * should be ever created for each type of cache, and returned every time it * is requested). @@ -98,7 +98,7 @@ public interface ICacheManager { *

    * Keys are the expressions themselves (their String representation), along with * a type that is normally used for identifying the nature of the object being - * cached (for example {"ognl","person.name"}). + * cached (for example {@code {"ognl","person.name"}}). *

    * * @return the cache of expression artifacts @@ -116,7 +116,7 @@ public interface ICacheManager { * they should use this method to retrieve them by their name. *

    *

    - * Note the default {@link StandardCacheManager} will return null for every + * Note the default {@link StandardCacheManager} will return {@code null} for every * call to this method, as it should be custom implementations of this interface (or * extensions of {@link AbstractCacheManager} or extensions {@link StandardCacheManager}) * who implement these specific caches and offer their names through the @@ -140,7 +140,7 @@ public interface ICacheManager { * Might return null if no specific caches are managed. *

    *

    - * Note the default {@link StandardCacheManager} will return null, as it should + * Note the default {@link StandardCacheManager} will return {@code null}, as it should * be custom implementations of this interface (or * extensions of {@link AbstractCacheManager} or extensions {@link StandardCacheManager}) * who implement these specific caches and offer their names through the diff --git a/src/main/java/org/thymeleaf/cache/StandardCache.java b/src/main/java/org/thymeleaf/cache/StandardCache.java index 4f30c21e6..c7beefb4b 100755 --- a/src/main/java/org/thymeleaf/cache/StandardCache.java +++ b/src/main/java/org/thymeleaf/cache/StandardCache.java @@ -217,7 +217,7 @@ public V get(final K key, final ICacheEntryValidityChecker *

    * Returns all the keys contained in this cache. Note this method might return keys for entries * that are already invalid, so the result of calling {@link #get(Object)} for these keys might - * be null. + * be {@code null}. *

    * * @return the complete set of cache keys. Might include keys for already-invalid (non-cleaned) entries. diff --git a/src/main/java/org/thymeleaf/cache/StandardCacheManager.java b/src/main/java/org/thymeleaf/cache/StandardCacheManager.java index cad0f3bff..b655266c8 100755 --- a/src/main/java/org/thymeleaf/cache/StandardCacheManager.java +++ b/src/main/java/org/thymeleaf/cache/StandardCacheManager.java @@ -40,20 +40,20 @@ *
  • Its maximum size: the maximum size the cache will be allowed to reach. * Some special values: *
      - *
    • -1 means no limit in size.
    • - *
    • 0 means this cache will not be used at - * all (getXCache() will return null).
    • + *
    • {@code -1} means no limit in size.
    • + *
    • {@code 0} means this cache will not be used at + * all ({@code getXCache()} will return {@code null}).
    • *
    *
  • *
  • Whether the cache should use soft references or not - * (java.lang.ref.SoftReference). Using Soft References + * ({@code java.lang.ref.SoftReference}). Using Soft References * allows the cache to be memory-sensitive, allowing the garbage collector * to dispose cache entries if memory is critical, before raising an - * OutOfMemoryError.
  • + * {@code OutOfMemoryError}. *
  • The name of the logger that will output trace information for the * cache object. Configuring this allows a finer-grained log configuration that * allows the more effective inspection of cache behaviour. If not specifically - * set, org.thymeleaf.TemplateEngine.cache.${cacheName} will be used.
  • + * set, {@code org.thymeleaf.TemplateEngine.cache.${cacheName}} will be used. *
  • An (optional) validity checker implementing {@link ICacheEntryValidityChecker}, * which will be applied on each entry upon retrieval from cache in order to ensure * it is still valid and can be used. diff --git a/src/main/java/org/thymeleaf/context/IContext.java b/src/main/java/org/thymeleaf/context/IContext.java index fdc5f31fe..fed90d10f 100644 --- a/src/main/java/org/thymeleaf/context/IContext.java +++ b/src/main/java/org/thymeleaf/context/IContext.java @@ -67,7 +67,7 @@ public interface IContext { *

    * * @param name the name of the variable to be checked. - * @return true if the variable is already contained, false if not. + * @return {@code true} if the variable is already contained, {@code false} if not. */ public boolean containsVariable(final String name); diff --git a/src/main/java/org/thymeleaf/context/IEngineContext.java b/src/main/java/org/thymeleaf/context/IEngineContext.java index 9e27ac8a6..f98ea4236 100644 --- a/src/main/java/org/thymeleaf/context/IEngineContext.java +++ b/src/main/java/org/thymeleaf/context/IEngineContext.java @@ -40,8 +40,8 @@ *

    * Contexts used during template processing by the engine are always implementations of this interface. * If the Template Engine is called with an implementation of this {@link IEngineContext} as - * context, the same object will be used (so that users can actually provide their own implementations). - * On the other side, if the context specified to the Template Engine is not an implementation of this + * {@code context}, the same object will be used (so that users can actually provide their own implementations). + * On the other side, if the {@code context} specified to the Template Engine is not an implementation of this * interface, an implementation of {@link IEngineContext} will be internally created by the engine, the original * context's variables and other info will be cloned, and used instead. *

    @@ -107,10 +107,10 @@ public interface IEngineContext extends ITemplateContext { /** *

    - * Set a selection target. Usually the consequence of executing a th:object processor. + * Set a selection target. Usually the consequence of executing a {@code th:object} processor. *

    *

    - * Once set, all selection expressions (*{...}) will be executed on this target. + * Once set, all selection expressions ({@code *{...}}) will be executed on this target. *

    *

    * This selection target will have the consideration of a local variable and thus depend on @@ -123,7 +123,7 @@ public interface IEngineContext extends ITemplateContext { /** *

    - * Set an inliner. Usually the consequence of executing a th:inline processor. + * Set an inliner. Usually the consequence of executing a {@code th:inline} processor. *

    *

    * This inliner will have the consideration of a local variable and thus depend on @@ -141,7 +141,7 @@ public interface IEngineContext extends ITemplateContext { * decreased below the current level) originally belonged to a different template. *

    *

    - * A call on this method is usually the consequence of th:insert or th:replace. + * A call on this method is usually the consequence of {@code th:insert} or {@code th:replace}. *

    * * @param template the template data. @@ -180,7 +180,7 @@ public interface IEngineContext extends ITemplateContext { *

    * * @param name the name of the variable to be checked. - * @return true if the variable is local (level > 0), false if not (level == 0). + * @return {@code true} if the variable is local (level > 0), {@code false} if not (level == 0). */ public boolean isVariableLocal(final String name); diff --git a/src/main/java/org/thymeleaf/context/IEngineContextFactory.java b/src/main/java/org/thymeleaf/context/IEngineContextFactory.java index 62aef3419..ff510162f 100644 --- a/src/main/java/org/thymeleaf/context/IEngineContextFactory.java +++ b/src/main/java/org/thymeleaf/context/IEngineContextFactory.java @@ -32,7 +32,7 @@ *

    * Engine Contexts (implementations of {@link IEngineContext}) are the type of context really used by the engine * during template processing. These factories will be called in order to create {@link IEngineContext} instances - * from the original {@link IContext} implementations (the much simpler context objects that were used + * from the original {@link IContext} implementations (the much simpler {@code context} objects that were used * for calling the template engine). *

    *

    @@ -62,18 +62,18 @@ public interface IEngineContextFactory { *

    * Note this factory method will be only called once during the processing of a template. Once a engine context * instance has been created, the engine will try to reuse it for any nested processing operations as far as - * possible. This means that, e.g., the templateData specified here will only be the root-level + * possible. This means that, e.g., the {@code templateData} specified here will only be the root-level * template data (the one for the template that is actually being used as an - * {@link org.thymeleaf.ITemplateEngine}.process(...) argument). Any th:insert or - * th:replace operations inside that template will not ask this factory to create a new engine context, + * {@link org.thymeleaf.ITemplateEngine}{@code .process(...)} argument). Any {@code th:insert} or + * {@code th:replace} operations inside that template will not ask this factory to create a new engine context, * but instead just increase the nesting level of the already-existing one * (see {@link IEngineContext#increaseLevel()}) and set the new, nested template data for that level * (see {@link IEngineContext#setTemplateData(TemplateData)}). *

    *

    - * Note also that the context object passed here as an argument will normally correspond to the + * Note also that the {@code context} object passed here as an argument will normally correspond to the * simple {@link IContext} implementation used for calling - * {@link org.thymeleaf.ITemplateEngine}.process(...) and, therefore, will normally be an object + * {@link org.thymeleaf.ITemplateEngine}{@code .process(...)} and, therefore, will normally be an object * of class {@link EngineContext}, {@link WebContext} or similar. *

    * diff --git a/src/main/java/org/thymeleaf/context/IExpressionContext.java b/src/main/java/org/thymeleaf/context/IExpressionContext.java index 9d6880dfb..a9fdf136d 100644 --- a/src/main/java/org/thymeleaf/context/IExpressionContext.java +++ b/src/main/java/org/thymeleaf/context/IExpressionContext.java @@ -56,7 +56,7 @@ public interface IExpressionContext extends IContext { /** *

    * Returns the {@link IExpressionObjects} instance to be used for retrieving (and maybe building - * lazily) expression objects (${#expobj}) to be used at Standard Thymeleaf Expressions. + * lazily) expression objects ({@code ${#expobj}}) to be used at Standard Thymeleaf Expressions. *

    * @return the expression objects instance. */ diff --git a/src/main/java/org/thymeleaf/context/ILazyContextVariable.java b/src/main/java/org/thymeleaf/context/ILazyContextVariable.java index 1d96108ae..bff7d6807 100644 --- a/src/main/java/org/thymeleaf/context/ILazyContextVariable.java +++ b/src/main/java/org/thymeleaf/context/ILazyContextVariable.java @@ -33,7 +33,7 @@ *

    *

    * Note this lazy resolution can only be performed when the lazy variable is added to the context as a - * first-level variable. i.e. ${lazy} will work, but ${container.lazy} + * first-level variable. i.e. {@code ${lazy}} will work, but {@code ${container.lazy}} * will not. *

    *

    diff --git a/src/main/java/org/thymeleaf/context/ITemplateContext.java b/src/main/java/org/thymeleaf/context/ITemplateContext.java index 4a49105c4..61ffa63a6 100644 --- a/src/main/java/org/thymeleaf/context/ITemplateContext.java +++ b/src/main/java/org/thymeleaf/context/ITemplateContext.java @@ -61,7 +61,7 @@ public interface ITemplateContext extends IExpressionContext { *

    * Note that the {@link TemplateData} returned here corresponds with the origin of the elements or * nodes being currently processed. This is, if a processor is being executed for an element inserted - * from an external template (via a th:insert, for example), then this method will return + * from an external template (via a {@code th:insert}, for example), then this method will return * the template data for the template in which the inserted fragment lives, not the one it was inserted * into. *

    @@ -77,7 +77,7 @@ public interface ITemplateContext extends IExpressionContext { *

    * Note that the {@link TemplateMode} returned here corresponds with origin of the elements or nodes being * currently processed. This is, if a processor is being executed for an element inserted from an external - * template (via a th:insert, for example), then this method will return the template mode + * template (via a {@code th:insert}, for example), then this method will return the template mode * for the template in which the inserted fragment lives, not the one it was inserted into. *

    * @@ -96,7 +96,7 @@ public interface ITemplateContext extends IExpressionContext { *

    *

    * The first element in this list will always be the top-level template (the one called at the - * {@link org.thymeleaf.ITemplateEngine} process(...) methods). + * {@link org.thymeleaf.ITemplateEngine} {@code process(...)} methods). *

    * * @return the stack of templates (list of {@link TemplateData}). @@ -129,7 +129,7 @@ public interface ITemplateContext extends IExpressionContext { /** *

    - * Returns the map of configuration items that have been specified at the process(...) methods of + * Returns the map of configuration items that have been specified at the {@code process(...)} methods of * {@link org.thymeleaf.ITemplateEngine}, aimed at further configuring the template being used and its * resolution by means of the {@link org.thymeleaf.templateresolver.ITemplateResolver}s. *

    @@ -158,22 +158,22 @@ public interface ITemplateContext extends IExpressionContext { * execution or not. *

    *

    - * Selection targets are objects on which all *{...} expression will be executed (instead of on the - * root context). They are normally set by means of th:objects. + * Selection targets are objects on which all {@code *{...}} expression will be executed (instead of on the + * root context). They are normally set by means of {@code th:objects}. *

    * - * @return true if there is a selection target, false if not. + * @return {@code true} if there is a selection target, {@code false} if not. */ public boolean hasSelectionTarget(); /** *

    - * Returns the selection target set for the current point of execution (or null if there + * Returns the selection target set for the current point of execution (or {@code null} if there * isn't any). *

    *

    - * Selection targets are objects on which all *{...} expression will be executed (instead of on the - * root context). They are normally set by means of th:objects. + * Selection targets are objects on which all {@code *{...}} expression will be executed (instead of on the + * root context). They are normally set by means of {@code th:objects}. *

    * * @return the selection target, or null if there isn't any. @@ -206,7 +206,7 @@ public interface ITemplateContext extends IExpressionContext { * the case that the message does not exist * (see {@link org.thymeleaf.messageresolver.IMessageResolver}). * @return the requested message, correctly formatted. Or an absent message representation, or - * null if no absent message representations are allowed. + * {@code null} if no absent message representations are allowed. */ public String getMessage( final Class origin, final String key, final Object[] messageParameters, final boolean useAbsentMessageRepresentation); diff --git a/src/main/java/org/thymeleaf/context/IdentifierSequences.java b/src/main/java/org/thymeleaf/context/IdentifierSequences.java index 48a1c7a86..50a278fe3 100644 --- a/src/main/java/org/thymeleaf/context/IdentifierSequences.java +++ b/src/main/java/org/thymeleaf/context/IdentifierSequences.java @@ -28,7 +28,7 @@ /** *

    * Objects of this class are kept at {@link ITemplateContext} in order to provide templates - * with a way to create unique id attribute values during template processing. + * with a way to create unique {@code id} attribute values during template processing. *

    * * @author Daniel Fernández @@ -55,7 +55,7 @@ public IdentifierSequences() { /** *

    * Returns a new index (ID count) for a specific - * value of the id attribute, and increments + * value of the {@code id} attribute, and increments * the count. *

    * @@ -76,7 +76,7 @@ public Integer getAndIncrementIDSeq(final String id) { /** *

    * Returns the index (ID count) for a specific - * value of the id attribute without incrementing + * value of the {@code id} attribute without incrementing * the count. *

    * @@ -96,7 +96,7 @@ public Integer getNextIDSeq(final String id) { /** *

    * Returns the last index (ID count) returned for a specific - * value of the id attribute (without incrementing + * value of the {@code id} attribute (without incrementing * the count). *

    * diff --git a/src/main/java/org/thymeleaf/context/StandardEngineContextFactory.java b/src/main/java/org/thymeleaf/context/StandardEngineContextFactory.java index 54a8cb9a5..d70778295 100644 --- a/src/main/java/org/thymeleaf/context/StandardEngineContextFactory.java +++ b/src/main/java/org/thymeleaf/context/StandardEngineContextFactory.java @@ -33,7 +33,7 @@ * Standard implementation of the {@link IEngineContextFactory} interface. *

    *

    - * This factory will examine the context being passed as a parameter and, depending on whether + * This factory will examine the {@code context} being passed as a parameter and, depending on whether * this context object implements the {@link IWebContext} interface or not (i.e. whether support for the * Servlet API should be enabled or not), return a {@link WebEngineContext} or an {@link EngineContext} * instance as a result. diff --git a/src/main/java/org/thymeleaf/dialect/IProcessorDialect.java b/src/main/java/org/thymeleaf/dialect/IProcessorDialect.java index 68f18f977..5ba4c8226 100644 --- a/src/main/java/org/thymeleaf/dialect/IProcessorDialect.java +++ b/src/main/java/org/thymeleaf/dialect/IProcessorDialect.java @@ -29,12 +29,12 @@ * Base interface for all dialects providing processors ({@link IProcessor} objects) to the template engine. *

    *

    - * Dialects of this kind can specify a prefix (see {@link #getPrefix()}) which will be considered the + * Dialects of this kind can specify a {@code prefix} (see {@link #getPrefix()}) which will be considered the * default prefix for that dialect. Users can however change the prefix to be used at the moment the * dialect is added to the template engine. *

    *

    - * Also, prefix can be null, in which case the dialect's processors will be acting on + * Also, prefix can be {@code null}, in which case the dialect's processors will be acting on * attributes and elements without a namespace. *

    *

    diff --git a/src/main/java/org/thymeleaf/engine/AbstractTemplateHandler.java b/src/main/java/org/thymeleaf/engine/AbstractTemplateHandler.java index 60d894efe..7ae5176e2 100644 --- a/src/main/java/org/thymeleaf/engine/AbstractTemplateHandler.java +++ b/src/main/java/org/thymeleaf/engine/AbstractTemplateHandler.java @@ -40,7 +40,7 @@ * interface and offers a good base for the easy implementation of custom template handlers. *

    *

    - * All handleX() implementations in this class are set to simply delegate to the + * All {@code handleX()} implementations in this class are set to simply delegate to the * next handler in the chain, so that subclasses can override only the handling methods that are * really relevant to them. *

    diff --git a/src/main/java/org/thymeleaf/engine/DataDrivenTemplateIterator.java b/src/main/java/org/thymeleaf/engine/DataDrivenTemplateIterator.java index d26657125..3b396a39e 100644 --- a/src/main/java/org/thymeleaf/engine/DataDrivenTemplateIterator.java +++ b/src/main/java/org/thymeleaf/engine/DataDrivenTemplateIterator.java @@ -158,7 +158,7 @@ public void finishIteration() { * needed or not. The typical use of this is to be able to switch between the "head" and the "data/buffer" phase. *

    * - * @return true if this iterator has been queried, false if not. + * @return {@code true} if this iterator has been queried, {@code false} if not. * * @since 3.0.3 */ diff --git a/src/main/java/org/thymeleaf/engine/TemplateData.java b/src/main/java/org/thymeleaf/engine/TemplateData.java index 84fe36985..4b5c5c7cb 100644 --- a/src/main/java/org/thymeleaf/engine/TemplateData.java +++ b/src/main/java/org/thymeleaf/engine/TemplateData.java @@ -69,7 +69,7 @@ public final class TemplateData { /** *

    - * Builds a new TemplateData object. + * Builds a new {@code TemplateData} object. *

    *

    * This constructor should be considered internal, as there should be no reason why @@ -126,7 +126,7 @@ public String getTemplate() { * Returns whether this spec has template selectors specified or not. *

    * - * @return true of there are template selectors, false if not. + * @return {@code true} of there are template selectors, {@code false} if not. */ public boolean hasTemplateSelectors() { // Checking for null is enough, as we have already processed this in the constructor @@ -141,12 +141,12 @@ public boolean hasTemplateSelectors() { *

    * Template selectors allow the possibility to process only a part of the specified template, expressing * this selection in a syntax similar to jQuery, CSS or XPath selectors. Note this is only available for - * markup template modes (HTML, XML). For more info on template selectors + * markup template modes ({@code HTML}, {@code XML}). For more info on template selectors * syntax, have a look at AttoParser's markup selectors * documentation. *

    * - * @return the template selectors, or null if there are none. + * @return the template selectors, or {@code null} if there are none. */ public Set getTemplateSelectors() { return this.templateSelectors; @@ -162,7 +162,7 @@ public Set getTemplateSelectors() { * {@link org.thymeleaf.templateresolver.ITemplateResolver}. *

    *

    - * Note that, even if this resource object will never be null, the existence of the + * Note that, even if this resource object will never be {@code null}, the existence of the * resource object does not necessarily imply the existence of the resource itself unless * the template resolver was configured for calling {@link ITemplateResource#exists()} upon * template resolution. diff --git a/src/main/java/org/thymeleaf/exceptions/TemplateAssertionException.java b/src/main/java/org/thymeleaf/exceptions/TemplateAssertionException.java index 1bc525840..46c3f5b88 100755 --- a/src/main/java/org/thymeleaf/exceptions/TemplateAssertionException.java +++ b/src/main/java/org/thymeleaf/exceptions/TemplateAssertionException.java @@ -25,7 +25,7 @@ *

    *

    * In the Standard Dialects, this exception might be raised by the - * th:assert attribute. + * {@code th:assert} attribute. *

    * * @author Daniel Fernández diff --git a/src/main/java/org/thymeleaf/expression/Aggregates.java b/src/main/java/org/thymeleaf/expression/Aggregates.java index b811df499..7c8f62766 100755 --- a/src/main/java/org/thymeleaf/expression/Aggregates.java +++ b/src/main/java/org/thymeleaf/expression/Aggregates.java @@ -31,7 +31,7 @@ *

    *

    * An object of this class is usually available in variable evaluation expressions with the name - * #aggregates. + * {@code #aggregates}. *

    * * @author Daniel Fernández diff --git a/src/main/java/org/thymeleaf/expression/Arrays.java b/src/main/java/org/thymeleaf/expression/Arrays.java index ce3f84186..61a11e092 100755 --- a/src/main/java/org/thymeleaf/expression/Arrays.java +++ b/src/main/java/org/thymeleaf/expression/Arrays.java @@ -30,7 +30,7 @@ *

    *

    * An object of this class is usually available in variable evaluation expressions with the name - * #arrays. + * {@code #arrays}. *

    * * @author Daniel Fernández diff --git a/src/main/java/org/thymeleaf/expression/Bools.java b/src/main/java/org/thymeleaf/expression/Bools.java index 5d4a520ff..60cc19a21 100755 --- a/src/main/java/org/thymeleaf/expression/Bools.java +++ b/src/main/java/org/thymeleaf/expression/Bools.java @@ -34,7 +34,7 @@ *

    *

    * An object of this class is usually available in variable evaluation expressions with the name - * #bools. + * {@code #bools}. *

    * * @author Daniel Fernández diff --git a/src/main/java/org/thymeleaf/expression/Calendars.java b/src/main/java/org/thymeleaf/expression/Calendars.java index c274d148d..5c5607d01 100755 --- a/src/main/java/org/thymeleaf/expression/Calendars.java +++ b/src/main/java/org/thymeleaf/expression/Calendars.java @@ -37,7 +37,7 @@ *

    *

    * An object of this class is usually available in variable evaluation expressions with the name - * #calendars. + * {@code #calendars}. *

    * * @author Daniel Fernández diff --git a/src/main/java/org/thymeleaf/expression/Conversions.java b/src/main/java/org/thymeleaf/expression/Conversions.java index cb92e6459..c8ae3b7c4 100755 --- a/src/main/java/org/thymeleaf/expression/Conversions.java +++ b/src/main/java/org/thymeleaf/expression/Conversions.java @@ -32,7 +32,7 @@ *

    *

    * An object of this class is usually available in variable evaluation expressions with the name - * #conversions. + * {@code #conversions}. *

    *

    * Note a class with this name existed since 2.1.0, but it was completely reimplemented diff --git a/src/main/java/org/thymeleaf/expression/Dates.java b/src/main/java/org/thymeleaf/expression/Dates.java index 36cd4fd7e..c0be69574 100755 --- a/src/main/java/org/thymeleaf/expression/Dates.java +++ b/src/main/java/org/thymeleaf/expression/Dates.java @@ -37,7 +37,7 @@ *

    *

    * An object of this class is usually available in variable evaluation expressions with the name - * #dates. + * {@code #dates}. *

    * * @author Daniel Fernández diff --git a/src/main/java/org/thymeleaf/expression/ExecutionInfo.java b/src/main/java/org/thymeleaf/expression/ExecutionInfo.java index a3b7c5b62..6888c20f5 100644 --- a/src/main/java/org/thymeleaf/expression/ExecutionInfo.java +++ b/src/main/java/org/thymeleaf/expression/ExecutionInfo.java @@ -35,7 +35,7 @@ *

    *

    * An object of this class is usually available in variable evaluation expressions with the name - * #execInfo. + * {@code #execInfo}. *

    * * @author Daniel Fernández @@ -63,7 +63,7 @@ public ExecutionInfo(final ITemplateContext context) { *

    * Note that the template name returned here corresponds with origin of the elements or nodes being * currently processed. This is, if a processor is being executed for an element inserted from an external - * template (via a th:insert, for example), then this method will return the template mode + * template (via a {@code th:insert}, for example), then this method will return the template mode * for the template in which the inserted fragment lives, not the one it was inserted into. *

    * @@ -81,7 +81,7 @@ public String getTemplateName() { *

    * Note that the {@link TemplateMode} returned here corresponds with origin of the elements or nodes being * currently processed. This is, if a processor is being executed for an element inserted from an external - * template (via a th:insert, for example), then this method will return the template mode + * template (via a {@code th:insert}, for example), then this method will return the template mode * for the template in which the inserted fragment lives, not the one it was inserted into. *

    * diff --git a/src/main/java/org/thymeleaf/expression/IExpressionObjectFactory.java b/src/main/java/org/thymeleaf/expression/IExpressionObjectFactory.java index f32c8d462..c793903e2 100644 --- a/src/main/java/org/thymeleaf/expression/IExpressionObjectFactory.java +++ b/src/main/java/org/thymeleaf/expression/IExpressionObjectFactory.java @@ -58,7 +58,7 @@ public interface IExpressionObjectFactory { * * @param context the context being used for processing the template. * @param expressionObjectName the name of the expression object to be built. - * @return the built object, or null if the object could not be built. + * @return the built object, or {@code null} if the object could not be built. */ public Object buildObject(final IExpressionContext context, final String expressionObjectName); @@ -72,7 +72,7 @@ public interface IExpressionObjectFactory { * executed during a single template execution. *

    * @param expressionObjectName the name of the expression object. - * @return true is the object is to be considered cacheable, false if not. + * @return {@code true} is the object is to be considered cacheable, {@code false} if not. */ public boolean isCacheable(final String expressionObjectName); diff --git a/src/main/java/org/thymeleaf/expression/Ids.java b/src/main/java/org/thymeleaf/expression/Ids.java index 0953ece44..f36cbb499 100755 --- a/src/main/java/org/thymeleaf/expression/Ids.java +++ b/src/main/java/org/thymeleaf/expression/Ids.java @@ -24,12 +24,12 @@ /** *

    - * Expression Object for performing operations related to markup id attributes inside Thymeleaf + * Expression Object for performing operations related to markup {@code id} attributes inside Thymeleaf * Standard Expressions. *

    *

    * An object of this class is usually available in variable evaluation expressions with the name - * #ids. + * {@code #ids}. *

    * * @author Daniel Fernández diff --git a/src/main/java/org/thymeleaf/expression/Lists.java b/src/main/java/org/thymeleaf/expression/Lists.java index a6dc29b70..2f56c3f70 100755 --- a/src/main/java/org/thymeleaf/expression/Lists.java +++ b/src/main/java/org/thymeleaf/expression/Lists.java @@ -32,7 +32,7 @@ *

    *

    * An object of this class is usually available in variable evaluation expressions with the name - * #lists. + * {@code #lists}. *

    * * @author Daniel Fernández diff --git a/src/main/java/org/thymeleaf/expression/Maps.java b/src/main/java/org/thymeleaf/expression/Maps.java index a39b1291a..b3c9d89ed 100755 --- a/src/main/java/org/thymeleaf/expression/Maps.java +++ b/src/main/java/org/thymeleaf/expression/Maps.java @@ -31,7 +31,7 @@ *

    *

    * An object of this class is usually available in variable evaluation expressions with the name - * #maps. + * {@code #maps}. *

    * * @author Daniel Fernández diff --git a/src/main/java/org/thymeleaf/expression/Messages.java b/src/main/java/org/thymeleaf/expression/Messages.java index 62aeae3a7..6f2c68815 100755 --- a/src/main/java/org/thymeleaf/expression/Messages.java +++ b/src/main/java/org/thymeleaf/expression/Messages.java @@ -33,7 +33,7 @@ *

    *

    * An object of this class is usually available in variable evaluation expressions with the name - * #messages. + * {@code #messages}. *

    * * @author Daniel Fernández diff --git a/src/main/java/org/thymeleaf/expression/Numbers.java b/src/main/java/org/thymeleaf/expression/Numbers.java index dbb1a7fce..385cf6df0 100755 --- a/src/main/java/org/thymeleaf/expression/Numbers.java +++ b/src/main/java/org/thymeleaf/expression/Numbers.java @@ -36,7 +36,7 @@ *

    *

    * An object of this class is usually available in variable evaluation expressions with the name - * #numbers. + * {@code #numbers}. *

    * * @author Daniel Fernández diff --git a/src/main/java/org/thymeleaf/expression/Objects.java b/src/main/java/org/thymeleaf/expression/Objects.java index 9a8216e84..ad5029157 100755 --- a/src/main/java/org/thymeleaf/expression/Objects.java +++ b/src/main/java/org/thymeleaf/expression/Objects.java @@ -34,7 +34,7 @@ *

    *

    * An object of this class is usually available in variable evaluation expressions with the name - * #objects. + * {@code #objects}. *

    * * @author Daniel Fernández diff --git a/src/main/java/org/thymeleaf/expression/Sets.java b/src/main/java/org/thymeleaf/expression/Sets.java index 8cb7e89f4..f61d725f3 100755 --- a/src/main/java/org/thymeleaf/expression/Sets.java +++ b/src/main/java/org/thymeleaf/expression/Sets.java @@ -31,7 +31,7 @@ *

    *

    * An object of this class is usually available in variable evaluation expressions with the name - * #sets. + * {@code #sets}. *

    * * @author Daniel Fernández diff --git a/src/main/java/org/thymeleaf/expression/Strings.java b/src/main/java/org/thymeleaf/expression/Strings.java index e66575535..2763a700c 100755 --- a/src/main/java/org/thymeleaf/expression/Strings.java +++ b/src/main/java/org/thymeleaf/expression/Strings.java @@ -35,7 +35,7 @@ *

    *

    * An object of this class is usually available in variable evaluation expressions with the name - * #strings. + * {@code #strings}. *

    * * @author Daniel Fernández @@ -63,12 +63,12 @@ public Strings(final Locale locale) { /** *

    - * Performs a null-safe toString() operation. + * Performs a null-safe {@code toString()} operation. *

    * * @param target the object on which toString will be executed - * @return the result of calling target.toString() if target is not null, - * null if target is null. + * @return the result of calling {@code target.toString()} if target is not null, + * {@code null} if target is null. * @since 2.0.12 */ public String toString(final Object target) { @@ -81,13 +81,13 @@ public String toString(final Object target) { /** *

    - * Performs a null-safe toString() operation on each + * Performs a null-safe {@code toString()} operation on each * element of the array. *

    * * @param target the array of objects on which toString will be executed - * @return for each element: the result of calling target.toString() - * if target is not null, null if target is null. + * @return for each element: the result of calling {@code target.toString()} + * if target is not null, {@code null} if target is null. * @since 2.0.12 */ public String[] arrayToString(final Object[] target) { @@ -104,13 +104,13 @@ public String[] arrayToString(final Object[] target) { /** *

    - * Performs a null-safe toString() operation on each + * Performs a null-safe {@code toString()} operation on each * element of the list. *

    * * @param target the list of objects on which toString will be executed - * @return for each element: the result of calling target.toString() - * if target is not null, null if target is null. + * @return for each element: the result of calling {@code target.toString()} + * if target is not null, {@code null} if target is null. * @since 2.0.12 */ public List listToString(final List target) { @@ -127,13 +127,13 @@ public List listToString(final List target) { /** *

    - * Performs a null-safe toString() operation on each + * Performs a null-safe {@code toString()} operation on each * element of the set. *

    * * @param target the set of objects on which toString will be executed - * @return for each element: the result of calling target.toString() - * if target is not null, null if target is null. + * @return for each element: the result of calling {@code target.toString()} + * if target is not null, {@code null} if target is null. * @since 2.0.12 */ public Set setToString(final Set target) { @@ -434,7 +434,7 @@ public Set setSubstring(final Set target, final int start, final int * @param target source of the copy. * @param start index where the copy start. * - * @return part of target, or null if target is null. + * @return part of target, or {@code null} if target is null. * * @since 1.1.2 * @@ -455,7 +455,7 @@ public String substring(final Object target, final int start) { * @param target source of the copy. * @param start index where the copy start. * - * @return part of target, or null if target is null. + * @return part of target, or {@code null} if target is null. * * @since 1.1.2 * @@ -480,7 +480,7 @@ public String[] arraySubstring(final Object[] target, final int start) { * @param target source of the copy. * @param start index where the copy start. * - * @return part of target, or null if target is null. + * @return part of target, or {@code null} if target is null. * * @since 1.1.2 * @@ -505,7 +505,7 @@ public List listSubstring(final List target, final int start) { * @param target source of the copy. * @param start index where the copy start. * - * @return part of target, or null if target is null. + * @return part of target, or {@code null} if target is null. * * @since 1.1.2 * diff --git a/src/main/java/org/thymeleaf/expression/Uris.java b/src/main/java/org/thymeleaf/expression/Uris.java index 7945e79de..3b173b084 100644 --- a/src/main/java/org/thymeleaf/expression/Uris.java +++ b/src/main/java/org/thymeleaf/expression/Uris.java @@ -27,7 +27,7 @@ *

    *

    * An object of this class is usually available in variable evaluation expressions with the name - * #uris. + * {@code #uris}. *

    * * @author Daniel Fernández @@ -47,36 +47,36 @@ public Uris() { /** *

    * Perform am URI path escape operation - * on a String input using UTF-8 as encoding. + * on a {@code String} input using {@code UTF-8} as encoding. *

    *

    - * This method simply calls the equivalent method in the UriEscape class from the + * This method simply calls the equivalent method in the {@code UriEscape} class from the * Unbescape library. *

    *

    * The following are the only allowed chars in an URI path (will not be escaped): *

    *
      - *
    • A-Z a-z 0-9
    • - *
    • - . _ ~
    • - *
    • ! $ & ' ( ) * + , ; =
    • - *
    • : @
    • - *
    • /
    • + *
    • {@code A-Z a-z 0-9}
    • + *
    • {@code - . _ ~}
    • + *
    • {@code ! $ & ' ( ) * + , ; =}
    • + *
    • {@code : @}
    • + *
    • {@code /}
    • *
    *

    * All other chars will be escaped by converting them to the sequence of bytes that - * represents them in the UTF-8 and then representing each byte - * in %HH syntax, being HH the hexadecimal representation of the byte. + * represents them in the {@code UTF-8} and then representing each byte + * in {@code %HH} syntax, being {@code HH} the hexadecimal representation of the byte. *

    *

    * This method is thread-safe. *

    * - * @param text the String to be escaped. - * @return The escaped result String. As a memory-performance improvement, will return the exact - * same object as the text input argument if no escaping modifications were required (and - * no additional String objects will be created during processing). Will - * return null if text is null. + * @param text the {@code String} to be escaped. + * @return The escaped result {@code String}. As a memory-performance improvement, will return the exact + * same object as the {@code text} input argument if no escaping modifications were required (and + * no additional {@code String} objects will be created during processing). Will + * return {@code null} if {@code text} is {@code null}. */ public String escapePath(final String text) { return UriEscape.escapeUriPath(text); @@ -85,31 +85,31 @@ public String escapePath(final String text) { /** *

    * Perform am URI path unescape operation - * on a String input using UTF-8 as encoding. + * on a {@code String} input using {@code UTF-8} as encoding. *

    *

    - * This method simply calls the equivalent method in the UriEscape class from the + * This method simply calls the equivalent method in the {@code UriEscape} class from the * Unbescape library. *

    *

    - * This method will unescape every percent-encoded (%HH) sequences present in input, + * This method will unescape every percent-encoded ({@code %HH}) sequences present in input, * even for those characters that do not need to be percent-encoded in this context (unreserved characters * can be percent-encoded even if/when this is not required, though it is not generally considered a * good practice). *

    *

    - * This method will use UTF-8 in order to determine the characters specified in the + * This method will use {@code UTF-8} in order to determine the characters specified in the * percent-encoded byte sequences. *

    *

    * This method is thread-safe. *

    * - * @param text the String to be unescaped. - * @return The unescaped result String. As a memory-performance improvement, will return the exact - * same object as the text input argument if no unescaping modifications were required (and - * no additional String objects will be created during processing). Will - * return null if text is null. + * @param text the {@code String} to be unescaped. + * @return The unescaped result {@code String}. As a memory-performance improvement, will return the exact + * same object as the {@code text} input argument if no unescaping modifications were required (and + * no additional {@code String} objects will be created during processing). Will + * return {@code null} if {@code text} is {@code null}. */ public String unescapePath(final String text) { return UriEscape.unescapeUriPath(text); @@ -118,37 +118,37 @@ public String unescapePath(final String text) { /** *

    * Perform am URI path escape operation - * on a String input. + * on a {@code String} input. *

    *

    - * This method simply calls the equivalent method in the UriEscape class from the + * This method simply calls the equivalent method in the {@code UriEscape} class from the * Unbescape library. *

    *

    * The following are the only allowed chars in an URI path (will not be escaped): *

    *
      - *
    • A-Z a-z 0-9
    • - *
    • - . _ ~
    • - *
    • ! $ & ' ( ) * + , ; =
    • - *
    • : @
    • - *
    • /
    • + *
    • {@code A-Z a-z 0-9}
    • + *
    • {@code - . _ ~}
    • + *
    • {@code ! $ & ' ( ) * + , ; =}
    • + *
    • {@code : @}
    • + *
    • {@code /}
    • *
    *

    * All other chars will be escaped by converting them to the sequence of bytes that * represents them in the specified encoding and then representing each byte - * in %HH syntax, being HH the hexadecimal representation of the byte. + * in {@code %HH} syntax, being {@code HH} the hexadecimal representation of the byte. *

    *

    * This method is thread-safe. *

    * - * @param text the String to be escaped. + * @param text the {@code String} to be escaped. * @param encoding the encoding to be used for unescaping. - * @return The escaped result String. As a memory-performance improvement, will return the exact - * same object as the text input argument if no escaping modifications were required (and - * no additional String objects will be created during processing). Will - * return null if text is null. + * @return The escaped result {@code String}. As a memory-performance improvement, will return the exact + * same object as the {@code text} input argument if no escaping modifications were required (and + * no additional {@code String} objects will be created during processing). Will + * return {@code null} if {@code text} is {@code null}. */ public String escapePath(final String text, final String encoding) { return UriEscape.escapeUriPath(text, encoding); @@ -157,32 +157,32 @@ public String escapePath(final String text, final String encoding) { /** *

    * Perform am URI path unescape operation - * on a String input. + * on a {@code String} input. *

    *

    - * This method simply calls the equivalent method in the UriEscape class from the + * This method simply calls the equivalent method in the {@code UriEscape} class from the * Unbescape library. *

    *

    - * This method will unescape every percent-encoded (%HH) sequences present in input, + * This method will unescape every percent-encoded ({@code %HH}) sequences present in input, * even for those characters that do not need to be percent-encoded in this context (unreserved characters * can be percent-encoded even if/when this is not required, though it is not generally considered a * good practice). *

    *

    - * This method will use the specified encoding in order to determine the characters specified in the + * This method will use the specified {@code encoding} in order to determine the characters specified in the * percent-encoded byte sequences. *

    *

    * This method is thread-safe. *

    * - * @param text the String to be unescaped. + * @param text the {@code String} to be unescaped. * @param encoding the encoding to be used for unescaping. - * @return The unescaped result String. As a memory-performance improvement, will return the exact - * same object as the text input argument if no unescaping modifications were required (and - * no additional String objects will be created during processing). Will - * return null if text is null. + * @return The unescaped result {@code String}. As a memory-performance improvement, will return the exact + * same object as the {@code text} input argument if no unescaping modifications were required (and + * no additional {@code String} objects will be created during processing). Will + * return {@code null} if {@code text} is {@code null}. */ public String unescapePath(final String text, final String encoding) { return UriEscape.unescapeUriPath(text, encoding); @@ -193,35 +193,35 @@ public String unescapePath(final String text, final String encoding) { /** *

    * Perform am URI path segment escape operation - * on a String input using UTF-8 as encoding. + * on a {@code String} input using {@code UTF-8} as encoding. *

    *

    - * This method simply calls the equivalent method in the UriEscape class from the + * This method simply calls the equivalent method in the {@code UriEscape} class from the * Unbescape library. *

    *

    * The following are the only allowed chars in an URI path segment (will not be escaped): *

    *
      - *
    • A-Z a-z 0-9
    • - *
    • - . _ ~
    • - *
    • ! $ & ' ( ) * + , ; =
    • - *
    • : @
    • + *
    • {@code A-Z a-z 0-9}
    • + *
    • {@code - . _ ~}
    • + *
    • {@code ! $ & ' ( ) * + , ; =}
    • + *
    • {@code : @}
    • *
    *

    * All other chars will be escaped by converting them to the sequence of bytes that - * represents them in the UTF-8 and then representing each byte - * in %HH syntax, being HH the hexadecimal representation of the byte. + * represents them in the {@code UTF-8} and then representing each byte + * in {@code %HH} syntax, being {@code HH} the hexadecimal representation of the byte. *

    *

    * This method is thread-safe. *

    * - * @param text the String to be escaped. - * @return The escaped result String. As a memory-performance improvement, will return the exact - * same object as the text input argument if no escaping modifications were required (and - * no additional String objects will be created during processing). Will - * return null if text is null. + * @param text the {@code String} to be escaped. + * @return The escaped result {@code String}. As a memory-performance improvement, will return the exact + * same object as the {@code text} input argument if no escaping modifications were required (and + * no additional {@code String} objects will be created during processing). Will + * return {@code null} if {@code text} is {@code null}. */ public String escapePathSegment(final String text) { return UriEscape.escapeUriPathSegment(text); @@ -230,31 +230,31 @@ public String escapePathSegment(final String text) { /** *

    * Perform am URI path segment unescape operation - * on a String input using UTF-8 as encoding. + * on a {@code String} input using {@code UTF-8} as encoding. *

    *

    - * This method simply calls the equivalent method in the UriEscape class from the + * This method simply calls the equivalent method in the {@code UriEscape} class from the * Unbescape library. *

    *

    - * This method will unescape every percent-encoded (%HH) sequences present in input, + * This method will unescape every percent-encoded ({@code %HH}) sequences present in input, * even for those characters that do not need to be percent-encoded in this context (unreserved characters * can be percent-encoded even if/when this is not required, though it is not generally considered a * good practice). *

    *

    - * This method will use UTF-8 in order to determine the characters specified in the + * This method will use {@code UTF-8} in order to determine the characters specified in the * percent-encoded byte sequences. *

    *

    * This method is thread-safe. *

    * - * @param text the String to be unescaped. - * @return The unescaped result String. As a memory-performance improvement, will return the exact - * same object as the text input argument if no unescaping modifications were required (and - * no additional String objects will be created during processing). Will - * return null if text is null. + * @param text the {@code String} to be unescaped. + * @return The unescaped result {@code String}. As a memory-performance improvement, will return the exact + * same object as the {@code text} input argument if no unescaping modifications were required (and + * no additional {@code String} objects will be created during processing). Will + * return {@code null} if {@code text} is {@code null}. */ public String unescapePathSegment(final String text) { return UriEscape.unescapeUriPathSegment(text); @@ -263,36 +263,36 @@ public String unescapePathSegment(final String text) { /** *

    * Perform am URI path segment escape operation - * on a String input. + * on a {@code String} input. *

    *

    - * This method simply calls the equivalent method in the UriEscape class from the + * This method simply calls the equivalent method in the {@code UriEscape} class from the * Unbescape library. *

    *

    * The following are the only allowed chars in an URI path segment (will not be escaped): *

    *
      - *
    • A-Z a-z 0-9
    • - *
    • - . _ ~
    • - *
    • ! $ & ' ( ) * + , ; =
    • - *
    • : @
    • + *
    • {@code A-Z a-z 0-9}
    • + *
    • {@code - . _ ~}
    • + *
    • {@code ! $ & ' ( ) * + , ; =}
    • + *
    • {@code : @}
    • *
    *

    * All other chars will be escaped by converting them to the sequence of bytes that * represents them in the specified encoding and then representing each byte - * in %HH syntax, being HH the hexadecimal representation of the byte. + * in {@code %HH} syntax, being {@code HH} the hexadecimal representation of the byte. *

    *

    * This method is thread-safe. *

    * - * @param text the String to be escaped. + * @param text the {@code String} to be escaped. * @param encoding the encoding to be used for escaping. - * @return The escaped result String. As a memory-performance improvement, will return the exact - * same object as the text input argument if no escaping modifications were required (and - * no additional String objects will be created during processing). Will - * return null if text is null. + * @return The escaped result {@code String}. As a memory-performance improvement, will return the exact + * same object as the {@code text} input argument if no escaping modifications were required (and + * no additional {@code String} objects will be created during processing). Will + * return {@code null} if {@code text} is {@code null}. */ public String escapePathSegment(final String text, final String encoding) { return UriEscape.escapeUriPathSegment(text, encoding); @@ -301,32 +301,32 @@ public String escapePathSegment(final String text, final String encoding) { /** *

    * Perform am URI path segment unescape operation - * on a String input. + * on a {@code String} input. *

    *

    - * This method simply calls the equivalent method in the UriEscape class from the + * This method simply calls the equivalent method in the {@code UriEscape} class from the * Unbescape library. *

    *

    - * This method will unescape every percent-encoded (%HH) sequences present in input, + * This method will unescape every percent-encoded ({@code %HH}) sequences present in input, * even for those characters that do not need to be percent-encoded in this context (unreserved characters * can be percent-encoded even if/when this is not required, though it is not generally considered a * good practice). *

    *

    - * This method will use specified encoding in order to determine the characters specified in the + * This method will use specified {@code encoding} in order to determine the characters specified in the * percent-encoded byte sequences. *

    *

    * This method is thread-safe. *

    * - * @param text the String to be unescaped. + * @param text the {@code String} to be unescaped. * @param encoding the encoding to be used for unescaping. - * @return The unescaped result String. As a memory-performance improvement, will return the exact - * same object as the text input argument if no unescaping modifications were required (and - * no additional String objects will be created during processing). Will - * return null if text is null. + * @return The unescaped result {@code String}. As a memory-performance improvement, will return the exact + * same object as the {@code text} input argument if no unescaping modifications were required (and + * no additional {@code String} objects will be created during processing). Will + * return {@code null} if {@code text} is {@code null}. */ public String unescapePathSegment(final String text, final String encoding) { return UriEscape.unescapeUriPathSegment(text, encoding); @@ -337,36 +337,36 @@ public String unescapePathSegment(final String text, final String encoding) { /** *

    * Perform am URI fragment identifier escape operation - * on a String input using UTF-8 as encoding. + * on a {@code String} input using {@code UTF-8} as encoding. *

    *

    - * This method simply calls the equivalent method in the UriEscape class from the + * This method simply calls the equivalent method in the {@code UriEscape} class from the * Unbescape library. *

    *

    * The following are the only allowed chars in an URI fragment identifier (will not be escaped): *

    *
      - *
    • A-Z a-z 0-9
    • - *
    • - . _ ~
    • - *
    • ! $ & ' ( ) * + , ; =
    • - *
    • : @
    • - *
    • / ?
    • + *
    • {@code A-Z a-z 0-9}
    • + *
    • {@code - . _ ~}
    • + *
    • {@code ! $ & ' ( ) * + , ; =}
    • + *
    • {@code : @}
    • + *
    • {@code / ?}
    • *
    *

    * All other chars will be escaped by converting them to the sequence of bytes that - * represents them in the UTF-8 and then representing each byte - * in %HH syntax, being HH the hexadecimal representation of the byte. + * represents them in the {@code UTF-8} and then representing each byte + * in {@code %HH} syntax, being {@code HH} the hexadecimal representation of the byte. *

    *

    * This method is thread-safe. *

    * - * @param text the String to be escaped. - * @return The escaped result String. As a memory-performance improvement, will return the exact - * same object as the text input argument if no escaping modifications were required (and - * no additional String objects will be created during processing). Will - * return null if text is null. + * @param text the {@code String} to be escaped. + * @return The escaped result {@code String}. As a memory-performance improvement, will return the exact + * same object as the {@code text} input argument if no escaping modifications were required (and + * no additional {@code String} objects will be created during processing). Will + * return {@code null} if {@code text} is {@code null}. */ public String escapeFragmentId(final String text) { return UriEscape.escapeUriFragmentId(text); @@ -375,31 +375,31 @@ public String escapeFragmentId(final String text) { /** *

    * Perform am URI fragment identifier unescape operation - * on a String input using UTF-8 as encoding. + * on a {@code String} input using {@code UTF-8} as encoding. *

    *

    - * This method simply calls the equivalent method in the UriEscape class from the + * This method simply calls the equivalent method in the {@code UriEscape} class from the * Unbescape library. *

    *

    - * This method will unescape every percent-encoded (%HH) sequences present in input, + * This method will unescape every percent-encoded ({@code %HH}) sequences present in input, * even for those characters that do not need to be percent-encoded in this context (unreserved characters * can be percent-encoded even if/when this is not required, though it is not generally considered a * good practice). *

    *

    - * This method will use UTF-8 in order to determine the characters specified in the + * This method will use {@code UTF-8} in order to determine the characters specified in the * percent-encoded byte sequences. *

    *

    * This method is thread-safe. *

    * - * @param text the String to be unescaped. - * @return The unescaped result String. As a memory-performance improvement, will return the exact - * same object as the text input argument if no unescaping modifications were required (and - * no additional String objects will be created during processing). Will - * return null if text is null. + * @param text the {@code String} to be unescaped. + * @return The unescaped result {@code String}. As a memory-performance improvement, will return the exact + * same object as the {@code text} input argument if no unescaping modifications were required (and + * no additional {@code String} objects will be created during processing). Will + * return {@code null} if {@code text} is {@code null}. */ public String unescapeFragmentId(final String text) { return UriEscape.unescapeUriFragmentId(text); @@ -408,37 +408,37 @@ public String unescapeFragmentId(final String text) { /** *

    * Perform am URI fragment identifier escape operation - * on a String input. + * on a {@code String} input. *

    *

    - * This method simply calls the equivalent method in the UriEscape class from the + * This method simply calls the equivalent method in the {@code UriEscape} class from the * Unbescape library. *

    *

    * The following are the only allowed chars in an URI fragment identifier (will not be escaped): *

    *
      - *
    • A-Z a-z 0-9
    • - *
    • - . _ ~
    • - *
    • ! $ & ' ( ) * + , ; =
    • - *
    • : @
    • - *
    • / ?
    • + *
    • {@code A-Z a-z 0-9}
    • + *
    • {@code - . _ ~}
    • + *
    • {@code ! $ & ' ( ) * + , ; =}
    • + *
    • {@code : @}
    • + *
    • {@code / ?}
    • *
    *

    * All other chars will be escaped by converting them to the sequence of bytes that * represents them in the specified encoding and then representing each byte - * in %HH syntax, being HH the hexadecimal representation of the byte. + * in {@code %HH} syntax, being {@code HH} the hexadecimal representation of the byte. *

    *

    * This method is thread-safe. *

    * - * @param text the String to be escaped. + * @param text the {@code String} to be escaped. * @param encoding the encoding to be used for escaping. - * @return The escaped result String. As a memory-performance improvement, will return the exact - * same object as the text input argument if no escaping modifications were required (and - * no additional String objects will be created during processing). Will - * return null if text is null. + * @return The escaped result {@code String}. As a memory-performance improvement, will return the exact + * same object as the {@code text} input argument if no escaping modifications were required (and + * no additional {@code String} objects will be created during processing). Will + * return {@code null} if {@code text} is {@code null}. */ public String escapeFragmentId(final String text, final String encoding) { return UriEscape.escapeUriFragmentId(text, encoding); @@ -447,32 +447,32 @@ public String escapeFragmentId(final String text, final String encoding) { /** *

    * Perform am URI fragment identifier unescape operation - * on a String input. + * on a {@code String} input. *

    *

    - * This method simply calls the equivalent method in the UriEscape class from the + * This method simply calls the equivalent method in the {@code UriEscape} class from the * Unbescape library. *

    *

    - * This method will unescape every percent-encoded (%HH) sequences present in input, + * This method will unescape every percent-encoded ({@code %HH}) sequences present in input, * even for those characters that do not need to be percent-encoded in this context (unreserved characters * can be percent-encoded even if/when this is not required, though it is not generally considered a * good practice). *

    *

    - * This method will use specified encoding in order to determine the characters specified in the + * This method will use specified {@code encoding} in order to determine the characters specified in the * percent-encoded byte sequences. *

    *

    * This method is thread-safe. *

    * - * @param text the String to be unescaped. + * @param text the {@code String} to be unescaped. * @param encoding the encoding to be used for unescaping. - * @return The unescaped result String. As a memory-performance improvement, will return the exact - * same object as the text input argument if no unescaping modifications were required (and - * no additional String objects will be created during processing). Will - * return null if text is null. + * @return The unescaped result {@code String}. As a memory-performance improvement, will return the exact + * same object as the {@code text} input argument if no unescaping modifications were required (and + * no additional {@code String} objects will be created during processing). Will + * return {@code null} if {@code text} is {@code null}. */ public String unescapeFragmentId(final String text, final String encoding) { return UriEscape.unescapeUriFragmentId(text, encoding); @@ -483,36 +483,36 @@ public String unescapeFragmentId(final String text, final String encoding) { /** *

    * Perform am URI query parameter (name or value) escape operation - * on a String input using UTF-8 as encoding. + * on a {@code String} input using {@code UTF-8} as encoding. *

    *

    - * This method simply calls the equivalent method in the UriEscape class from the + * This method simply calls the equivalent method in the {@code UriEscape} class from the * Unbescape library. *

    *

    * The following are the only allowed chars in an URI query parameter (will not be escaped): *

    *
      - *
    • A-Z a-z 0-9
    • - *
    • - . _ ~
    • - *
    • ! $ ' ( ) * , ;
    • - *
    • : @
    • - *
    • / ?
    • + *
    • {@code A-Z a-z 0-9}
    • + *
    • {@code - . _ ~}
    • + *
    • {@code ! $ ' ( ) * , ;}
    • + *
    • {@code : @}
    • + *
    • {@code / ?}
    • *
    *

    * All other chars will be escaped by converting them to the sequence of bytes that - * represents them in the UTF-8 and then representing each byte - * in %HH syntax, being HH the hexadecimal representation of the byte. + * represents them in the {@code UTF-8} and then representing each byte + * in {@code %HH} syntax, being {@code HH} the hexadecimal representation of the byte. *

    *

    * This method is thread-safe. *

    * - * @param text the String to be escaped. - * @return The escaped result String. As a memory-performance improvement, will return the exact - * same object as the text input argument if no escaping modifications were required (and - * no additional String objects will be created during processing). Will - * return null if text is null. + * @param text the {@code String} to be escaped. + * @return The escaped result {@code String}. As a memory-performance improvement, will return the exact + * same object as the {@code text} input argument if no escaping modifications were required (and + * no additional {@code String} objects will be created during processing). Will + * return {@code null} if {@code text} is {@code null}. */ public String escapeQueryParam(final String text) { return UriEscape.escapeUriQueryParam(text); @@ -521,31 +521,31 @@ public String escapeQueryParam(final String text) { /** *

    * Perform am URI query parameter (name or value) unescape operation - * on a String input using UTF-8 as encoding. + * on a {@code String} input using {@code UTF-8} as encoding. *

    *

    - * This method simply calls the equivalent method in the UriEscape class from the + * This method simply calls the equivalent method in the {@code UriEscape} class from the * Unbescape library. *

    *

    - * This method will unescape every percent-encoded (%HH) sequences present in input, + * This method will unescape every percent-encoded ({@code %HH}) sequences present in input, * even for those characters that do not need to be percent-encoded in this context (unreserved characters * can be percent-encoded even if/when this is not required, though it is not generally considered a * good practice). *

    *

    - * This method will use UTF-8 in order to determine the characters specified in the + * This method will use {@code UTF-8} in order to determine the characters specified in the * percent-encoded byte sequences. *

    *

    * This method is thread-safe. *

    * - * @param text the String to be unescaped. - * @return The unescaped result String. As a memory-performance improvement, will return the exact - * same object as the text input argument if no unescaping modifications were required (and - * no additional String objects will be created during processing). Will - * return null if text is null. + * @param text the {@code String} to be unescaped. + * @return The unescaped result {@code String}. As a memory-performance improvement, will return the exact + * same object as the {@code text} input argument if no unescaping modifications were required (and + * no additional {@code String} objects will be created during processing). Will + * return {@code null} if {@code text} is {@code null}. */ public String unescapeQueryParam(final String text) { return UriEscape.unescapeUriQueryParam(text); @@ -554,37 +554,37 @@ public String unescapeQueryParam(final String text) { /** *

    * Perform am URI query parameter (name or value) escape operation - * on a String input. + * on a {@code String} input. *

    *

    - * This method simply calls the equivalent method in the UriEscape class from the + * This method simply calls the equivalent method in the {@code UriEscape} class from the * Unbescape library. *

    *

    * The following are the only allowed chars in an URI query parameter (will not be escaped): *

    *
      - *
    • A-Z a-z 0-9
    • - *
    • - . _ ~
    • - *
    • ! $ ' ( ) * , ;
    • - *
    • : @
    • - *
    • / ?
    • + *
    • {@code A-Z a-z 0-9}
    • + *
    • {@code - . _ ~}
    • + *
    • {@code ! $ ' ( ) * , ;}
    • + *
    • {@code : @}
    • + *
    • {@code / ?}
    • *
    *

    * All other chars will be escaped by converting them to the sequence of bytes that * represents them in the specified encoding and then representing each byte - * in %HH syntax, being HH the hexadecimal representation of the byte. + * in {@code %HH} syntax, being {@code HH} the hexadecimal representation of the byte. *

    *

    * This method is thread-safe. *

    * - * @param text the String to be escaped. + * @param text the {@code String} to be escaped. * @param encoding the encoding to be used for escaping. - * @return The escaped result String. As a memory-performance improvement, will return the exact - * same object as the text input argument if no escaping modifications were required (and - * no additional String objects will be created during processing). Will - * return null if text is null. + * @return The escaped result {@code String}. As a memory-performance improvement, will return the exact + * same object as the {@code text} input argument if no escaping modifications were required (and + * no additional {@code String} objects will be created during processing). Will + * return {@code null} if {@code text} is {@code null}. */ public String escapeQueryParam(final String text, final String encoding) { return UriEscape.escapeUriQueryParam(text, encoding); @@ -593,32 +593,32 @@ public String escapeQueryParam(final String text, final String encoding) { /** *

    * Perform am URI query parameter (name or value) unescape operation - * on a String input. + * on a {@code String} input. *

    *

    - * This method simply calls the equivalent method in the UriEscape class from the + * This method simply calls the equivalent method in the {@code UriEscape} class from the * Unbescape library. *

    *

    - * This method will unescape every percent-encoded (%HH) sequences present in input, + * This method will unescape every percent-encoded ({@code %HH}) sequences present in input, * even for those characters that do not need to be percent-encoded in this context (unreserved characters * can be percent-encoded even if/when this is not required, though it is not generally considered a * good practice). *

    *

    - * This method will use specified encoding in order to determine the characters specified in the + * This method will use specified {@code encoding} in order to determine the characters specified in the * percent-encoded byte sequences. *

    *

    * This method is thread-safe. *

    * - * @param text the String to be unescaped. + * @param text the {@code String} to be unescaped. * @param encoding the encoding to be used for unescaping. - * @return The unescaped result String. As a memory-performance improvement, will return the exact - * same object as the text input argument if no unescaping modifications were required (and - * no additional String objects will be created during processing). Will - * return null if text is null. + * @return The unescaped result {@code String}. As a memory-performance improvement, will return the exact + * same object as the {@code text} input argument if no unescaping modifications were required (and + * no additional {@code String} objects will be created during processing). Will + * return {@code null} if {@code text} is {@code null}. */ public String unescapeQueryParam(final String text, final String encoding) { return UriEscape.unescapeUriQueryParam(text, encoding); diff --git a/src/main/java/org/thymeleaf/inline/IInliner.java b/src/main/java/org/thymeleaf/inline/IInliner.java index 9fb6dd031..c25dc9c32 100644 --- a/src/main/java/org/thymeleaf/inline/IInliner.java +++ b/src/main/java/org/thymeleaf/inline/IInliner.java @@ -31,7 +31,7 @@ *

    * Inliners are objects in charge of processing logic appearing on textual-oriented nodes * ({@link IText}, {@link ICDATASection} and {@link IComment}), as opposed to on elements. - * For example, inlined output expressions ([[${...}]]), javascript inlining artifacts, etc. + * For example, inlined output expressions ({@code [[${...}]]}), javascript inlining artifacts, etc. *

    * * @author Daniel Fernández diff --git a/src/main/java/org/thymeleaf/linkbuilder/ILinkBuilder.java b/src/main/java/org/thymeleaf/linkbuilder/ILinkBuilder.java index 025e6ba5d..359406a73 100644 --- a/src/main/java/org/thymeleaf/linkbuilder/ILinkBuilder.java +++ b/src/main/java/org/thymeleaf/linkbuilder/ILinkBuilder.java @@ -72,7 +72,7 @@ public interface ILinkBuilder { /** *

    - * Build a link, returning null if not possible. + * Build a link, returning {@code null} if not possible. *

    * * @param context the {@link IExpressionContext} object being used for template processing. Cannot be null. diff --git a/src/main/java/org/thymeleaf/linkbuilder/StandardLinkBuilder.java b/src/main/java/org/thymeleaf/linkbuilder/StandardLinkBuilder.java index e35a73c17..3664b34e6 100644 --- a/src/main/java/org/thymeleaf/linkbuilder/StandardLinkBuilder.java +++ b/src/main/java/org/thymeleaf/linkbuilder/StandardLinkBuilder.java @@ -43,17 +43,17 @@ * This class will build link URLs using (by default) the Java Servlet API when the specified URLs are * context-relative, given the need to obtain the context path and add it to the URL. Also, when an * {@link org.thymeleaf.context.IWebContext} implementation is used as context, URLs will be passed to - * the standard HttpSerlvetResponse.encodeURL(...) method before returning. + * the standard {@code HttpSerlvetResponse.encodeURL(...)} method before returning. *

    *

    * Note however that the Servlet-API specific part of this behaviour is configurable and confined to a set of - * protected methods that can be overwritten by subclasses that want to offer a link building + * {@code protected} methods that can be overwritten by subclasses that want to offer a link building * behaviour very similar to the standard one, but without any dependencies on the Servlet API (e.g. extracting - * URL context paths from a framework artifact other than HttpServletRequest). + * URL context paths from a framework artifact other than {@code HttpServletRequest}). *

    *

    - * This implementation will only return null at {@link #buildLink(IExpressionContext, String, Map)} - * if the specified base argument is null. + * This implementation will only return {@code null} at {@link #buildLink(IExpressionContext, String, Map)} + * if the specified {@code base} argument is {@code null}. *

    * * @author Daniel Fernández @@ -90,6 +90,8 @@ public final String buildLink( final Map linkParameters = (parameters == null || parameters.size() == 0? null : new LinkedHashMap(parameters)); + filterOutJavaScriptLinks(base); + final LinkType linkType; if (isLinkBaseAbsolute(base)) { linkType = LinkType.ABSOLUTE; @@ -239,6 +241,27 @@ private static int findCharInSequence(final CharSequence seq, final char charact } + private static void filterOutJavaScriptLinks(final CharSequence linkBase) { + if (linkBase.length() >= 11 && + Character.toLowerCase(linkBase.charAt(0)) == 'j' && + Character.toLowerCase(linkBase.charAt(1)) == 'a' && + Character.toLowerCase(linkBase.charAt(2)) == 'v' && + Character.toLowerCase(linkBase.charAt(3)) == 'a' && + Character.toLowerCase(linkBase.charAt(4)) == 's' && + Character.toLowerCase(linkBase.charAt(5)) == 'c' && + Character.toLowerCase(linkBase.charAt(6)) == 'r' && + Character.toLowerCase(linkBase.charAt(7)) == 'i' && + Character.toLowerCase(linkBase.charAt(8)) == 'p' && + Character.toLowerCase(linkBase.charAt(9)) == 't' && + Character.toLowerCase(linkBase.charAt(10)) == ':') { + + throw new TemplateProcessingException( + "'javascript:' is forbidden in this context. Link expressions cannot " + + "contain inlined JavaScript code."); + + } + } + private static boolean isLinkBaseAbsolute(final CharSequence linkBase) { @@ -469,8 +492,8 @@ private static void processAllRemainingParametersAsQueryParams(final StringBuild * need a context path to be inserted at their beginning). *

    *

    - * By default, this method will obtain the context path from HttpServletRequest.getContextPath(), - * throwing an exception if context is not an instance of IWebContext given context-relative + * By default, this method will obtain the context path from {@code HttpServletRequest.getContextPath()}, + * throwing an exception if {@code context} is not an instance of {@code IWebContext} given context-relative * URLs are (by default) only allowed in web contexts. *

    *

    @@ -505,9 +528,9 @@ protected String computeContextPath( * Process an already-built URL just before returning it. *

    *

    - * By default, this method will apply the HttpServletResponse.encodeURL(url) mechanism, as standard - * when using the Java Servlet API. Note however that this will only be applied if context is - * an implementation of IWebContext (i.e. the Servlet API will only be applied in web environments). + * By default, this method will apply the {@code HttpServletResponse.encodeURL(url)} mechanism, as standard + * when using the Java Servlet API. Note however that this will only be applied if {@code context} is + * an implementation of {@code IWebContext} (i.e. the Servlet API will only be applied in web environments). *

    *

    * This method can be overridden by any subclasses that want to change this behaviour (e.g. in order to diff --git a/src/main/java/org/thymeleaf/messageresolver/IMessageResolver.java b/src/main/java/org/thymeleaf/messageresolver/IMessageResolver.java index 341578e38..c888eb69d 100755 --- a/src/main/java/org/thymeleaf/messageresolver/IMessageResolver.java +++ b/src/main/java/org/thymeleaf/messageresolver/IMessageResolver.java @@ -34,13 +34,13 @@ *

    * Note that message resolution will return null if no message is found, in which case callers will have the * possibility to choose between asking the resolver to create an absent message representation or not. - * This is precisely what the useAbsentMessageRepresentation flag does in + * This is precisely what the {@code useAbsentMessageRepresentation} flag does in * {@link ITemplateContext#getMessage(Class, String, Object[], boolean)}. *

    *

    - * An absent message representation looks like ??mymessage_gl_ES?? and is useful to quickly determine - * when a message is lacking from the application's configuration. Note #{...} message expressions will - * always ask for an absent message representation, whereas methods in the #messages + * An absent message representation looks like {@code ??mymessage_gl_ES??} and is useful to quickly determine + * when a message is lacking from the application's configuration. Note {@code #{...}} message expressions will + * always ask for an {@code absent message representation}, whereas methods in the {@code #messages} * expression object will do it depending on the specific method being called. *

    *

    @@ -78,12 +78,12 @@ public interface IMessageResolver { /** *

    - * Resolve the message, returning the requested message (or null if not found). + * Resolve the message, returning the requested message (or {@code null} if not found). *

    *

    - * Message resolvers should perform resolution of the key + messageParameters pair - * based on the context and origin specified. The context will provide - * information about the template and the (optional) origin about the point in template execution from + * Message resolvers should perform resolution of the {@code key} + {@code messageParameters} pair + * based on the {@code context} and {@code origin} specified. The context will provide + * information about the template and the (optional) {@code origin} about the point in template execution from * which the message is being requested (usually an {@link org.thymeleaf.processor.IProcessor} or * the {@link org.thymeleaf.standard.expression.MessageExpression} class). *

    @@ -92,7 +92,7 @@ public interface IMessageResolver { * @param origin the origin of the message request, usually a processor or expression class. Can be null. * @param key the message key. * @param messageParameters the (optional) message parameters. - * @return the resolved message, or null if the message could not be resolved. + * @return the resolved message, or {@code null} if the message could not be resolved. */ public String resolveMessage( final ITemplateContext context, final Class origin, final String key, final Object[] messageParameters); @@ -104,8 +104,8 @@ public String resolveMessage( *

    *

    * Once the entire chain of configured {@link IMessageResolver} objects is asked for a specific message - * and all of them return null, the engine will call this method on the first resolver in the chain. - * If the first resolver returns null as a representation, the following resolver will be called, and + * and all of them return {@code null}, the engine will call this method on the first resolver in the chain. + * If the first resolver returns {@code null} as a representation, the following resolver will be called, and * so on until a resolver returns a non-null result. The empty String will be used if all resolvers return null. *

    * @@ -113,7 +113,7 @@ public String resolveMessage( * @param origin the origin of the message request, usually a processor or expression class. Can be null. * @param key the message key. * @param messageParameters the (optional) message parameters. - * @return the absent message representation, of null if the resolver cannot create such representation. + * @return the absent message representation, of {@code null} if the resolver cannot create such representation. */ public String createAbsentMessageRepresentation( final ITemplateContext context, final Class origin, final String key, final Object[] messageParameters); diff --git a/src/main/java/org/thymeleaf/messageresolver/StandardMessageResolver.java b/src/main/java/org/thymeleaf/messageresolver/StandardMessageResolver.java index 079de49b4..f39e3b5c1 100755 --- a/src/main/java/org/thymeleaf/messageresolver/StandardMessageResolver.java +++ b/src/main/java/org/thymeleaf/messageresolver/StandardMessageResolver.java @@ -52,19 +52,19 @@ * at children (inserted fragment) templates. *

    *

    - * For each of these templates, several .properties files will be examined. For example, - * a message in template /WEB-INF/templates/home.html for locale - * gl_ES-gheada ("gl" = language, "ES" = country, "gheada" = variant) would be looked for - * in .properties files in the following sequence: + * For each of these templates, several {@code .properties} files will be examined. For example, + * a message in template {@code /WEB-INF/templates/home.html} for locale + * {@code gl_ES-gheada} ("gl" = language, "ES" = country, "gheada" = variant) would be looked for + * in {@code .properties} files in the following sequence: *

    *
      - *
    • /WEB-INF/templates/home_gl_ES-gheada.properties
    • - *
    • /WEB-INF/templates/home_gl_ES.properties
    • - *
    • /WEB-INF/templates/home_gl.properties
    • - *
    • /WEB-INF/templates/home.properties
    • + *
    • {@code /WEB-INF/templates/home_gl_ES-gheada.properties}
    • + *
    • {@code /WEB-INF/templates/home_gl_ES.properties}
    • + *
    • {@code /WEB-INF/templates/home_gl.properties}
    • + *
    • {@code /WEB-INF/templates/home.properties}
    • *
    *

    - * Note the resolution mechanism used for accessing these template-based .properties files will + * Note the resolution mechanism used for accessing these template-based {@code .properties} files will * be the same used for resolving the templates themselves. So for templates resolved from the ServletContext * its messages files will be searched at the ServletContext, for templates resolved from URL the corresponding * derived URLs will be called, etc. @@ -74,19 +74,19 @@ *

    *

    * If no suitable message value is found during template-based resolution, origin-based resolution - * is performed. This allows the resolution of messages from .properties files living + * is performed. This allows the resolution of messages from {@code .properties} files living * in the classpath (and only in the classpath) in files corresponding with the names of the * classes being used as origin. *

    *

    - * For example, a processor my.company.processor.SomeDataProcessor using its own class + * For example, a processor {@code my.company.processor.SomeDataProcessor} using its own class * as origin will be able to resolve messages from a - * my/company/processor/SomeDataProcessor_gl_ES.properties file in the classpath. + * {@code my/company/processor/SomeDataProcessor_gl_ES.properties} file in the classpath. *

    *

    * Also, if a message is not found there, resolution will be tried for each of the superclasses this - * my.company.processor.SomeDataProcessor class extends, until a suitable message is found, or - * no more superclasses (except java.lang.Object exist). + * {@code my.company.processor.SomeDataProcessor} class extends, until a suitable message is found, or + * no more superclasses (except {@code java.lang.Object} exist). *

    *

    * Step 3: Defaults-based message resolution @@ -105,13 +105,13 @@ *

    * Message resolution will return null if no message is found, in which case callers will have the possibility * to choose between asking the resolver to create an absent message representation or not. - * This is precisely what the useAbsentMessageRepresentation flag does in + * This is precisely what the {@code useAbsentMessageRepresentation} flag does in * {@link ITemplateContext#getMessage(Class, String, Object[], boolean)}. *

    *

    - * An absent message representation looks like ??mymessage_gl_ES?? and is useful to quickly determine - * when a message is lacking from the application's configuration. Note #{...} message expressions will - * always ask for an absent message representation, whereas methods in the #messages + * An absent message representation looks like {@code ??mymessage_gl_ES??} and is useful to quickly determine + * when a message is lacking from the application's configuration. Note {@code #{...}} message expressions will + * always ask for an {@code absent message representation}, whereas methods in the {@code #messages} * expression object will do it depending on the specific method being called. *

    *

    @@ -366,7 +366,7 @@ public final String resolveMessage( * message resolution mechanisms. *

    *

    - * The standard mechanism will look for .properties files at the same location as + * The standard mechanism will look for {@code .properties} files at the same location as * the template (using the same resource resolution mechanism), and with the same name base. *

    * @@ -394,7 +394,7 @@ protected Map resolveMessagesForTemplate( *

    *

    * The standard mechanism will look for files in the classpath (only classpath), - * at the same package and with the same name as the origin class, with .properties + * at the same package and with the same name as the origin class, with {@code .properties} * extension. *

    * diff --git a/src/main/java/org/thymeleaf/model/IAttribute.java b/src/main/java/org/thymeleaf/model/IAttribute.java index a26a3e08c..045207eb5 100644 --- a/src/main/java/org/thymeleaf/model/IAttribute.java +++ b/src/main/java/org/thymeleaf/model/IAttribute.java @@ -72,7 +72,7 @@ public interface IAttribute { * Returns the operator specified for this attribute. *

    *

    - * The operator itself, if present, is always an equals sign (=), but the reason this is specified as a separate + * The operator itself, if present, is always an equals sign ({@code =}), but the reason this is specified as a separate * field is that it could be surrounded by white space, which should be respected in output when present at * the input template. *

    diff --git a/src/main/java/org/thymeleaf/model/ICDATASection.java b/src/main/java/org/thymeleaf/model/ICDATASection.java index d5704f368..a1a803293 100644 --- a/src/main/java/org/thymeleaf/model/ICDATASection.java +++ b/src/main/java/org/thymeleaf/model/ICDATASection.java @@ -35,7 +35,7 @@ public interface ICDATASection extends ITemplateEvent, CharSequence { /** *

    - * Returns the whole CDATA Section, including the <![CDATA[...]]> prefix and suffix. + * Returns the whole CDATA Section, including the {@code } prefix and suffix. *

    * * @return the CDATA Section. diff --git a/src/main/java/org/thymeleaf/model/IComment.java b/src/main/java/org/thymeleaf/model/IComment.java index e51be6825..22fe493c4 100644 --- a/src/main/java/org/thymeleaf/model/IComment.java +++ b/src/main/java/org/thymeleaf/model/IComment.java @@ -35,7 +35,7 @@ public interface IComment extends ITemplateEvent, CharSequence { /** *

    - * Returns the whole Comment, including the <!--...--> prefix and suffix. + * Returns the whole Comment, including the {@code } prefix and suffix. *

    * * @return the Comment. diff --git a/src/main/java/org/thymeleaf/model/IDocType.java b/src/main/java/org/thymeleaf/model/IDocType.java index 26c152747..6c90e760f 100644 --- a/src/main/java/org/thymeleaf/model/IDocType.java +++ b/src/main/java/org/thymeleaf/model/IDocType.java @@ -36,7 +36,7 @@ public interface IDocType extends ITemplateEvent { /** *

    * Returns the keyword of the DOCTYPE clause in its original - * case (usually DOCTYPE). + * case (usually {@code DOCTYPE}). *

    * * @return the DOCTYPE keyword. @@ -46,7 +46,7 @@ public interface IDocType extends ITemplateEvent { /** *

    * Returns the root element name in the DOCTYPE clause. Will normally be - * html in HTML or XHTML documents. + * {@code html} in HTML or XHTML documents. *

    * * @return the element name @@ -55,7 +55,7 @@ public interface IDocType extends ITemplateEvent { /** *

    - * Returns the type of DOCTYPE, usually null, PUBLIC or SYSTEM. + * Returns the type of DOCTYPE, usually {@code null}, {@code PUBLIC} or {@code SYSTEM}. *

    * * @return the type of DOCTYPE (might be null). diff --git a/src/main/java/org/thymeleaf/model/IModel.java b/src/main/java/org/thymeleaf/model/IModel.java index 049e9f547..7562d8c6c 100644 --- a/src/main/java/org/thymeleaf/model/IModel.java +++ b/src/main/java/org/thymeleaf/model/IModel.java @@ -123,7 +123,7 @@ public interface IModel { /** *

    * Add an entire model at the end of the sequence. This effectively appends the - * model argument's sequence to this one. + * {@code model} argument's sequence to this one. *

    * * @param model the model to be appended. diff --git a/src/main/java/org/thymeleaf/model/IModelFactory.java b/src/main/java/org/thymeleaf/model/IModelFactory.java index a7d549da3..70571da6c 100644 --- a/src/main/java/org/thymeleaf/model/IModelFactory.java +++ b/src/main/java/org/thymeleaf/model/IModelFactory.java @@ -73,8 +73,8 @@ public interface IModelFactory { * Parse the template specified as String and return the result as a model. *

    *

    - * Note the template argument specified here is the template content itself, not a name to be resolved - * by a template resolver. The ownerTemplate argument is mandatory, and specifies the template that + * Note the {@code template} argument specified here is the template content itself, not a name to be resolved + * by a template resolver. The {@code ownerTemplate} argument is mandatory, and specifies the template that * is being processed and as a part of which process the String template is being parsed. *

    * @@ -130,7 +130,7 @@ public interface IModelFactory { * Create a DOCTYPE clause event, specifying all its components. *

    * - * @param keyword the keyword value (should be DOCTYPE, but case might vary). + * @param keyword the keyword value (should be {@code DOCTYPE}, but case might vary). * @param elementName the root element name. * @param publicId the public ID (might be null). * @param systemId the system ID (might be null). @@ -184,7 +184,7 @@ public IDocType createDocType( *

    *

    * This is equivalent to calling {@link #createStandaloneElementTag(String, boolean, boolean)} with - * false as a value for synthetic and true as a value for minimized. + * {@code false} as a value for {@code synthetic} and {@code true} as a value for {@code minimized}. *

    * * @param elementName the element name. @@ -198,7 +198,7 @@ public IDocType createDocType( *

    *

    * This is equivalent to calling {@link #createStandaloneElementTag(String, String, String, boolean, boolean)} with - * false as a value for synthetic and true as a value for minimized. + * {@code false} as a value for {@code synthetic} and {@code true} as a value for {@code minimized}. *

    * * @param elementName the element name. @@ -216,8 +216,8 @@ public IDocType createDocType( * @param elementName the element name. * @param synthetic whether the tag is synthetic or not. Synthetic tags are used for balancing of markup and * will not appear on output. - * @param minimized whether the tag is minimized or not, i.e. whether it ends in /> or simply - * >. + * @param minimized whether the tag is minimized or not, i.e. whether it ends in {@code />} or simply + * {@code >}. * @return the standalone tag. */ public IStandaloneElementTag createStandaloneElementTag(final String elementName, final boolean synthetic, final boolean minimized); @@ -232,8 +232,8 @@ public IDocType createDocType( * @param attributeValue the value of the attribute to be added to the tag. * @param synthetic whether the tag is synthetic or not. Synthetic tags are used for balancing of markup and * will not appear on output. - * @param minimized whether the tag is minimized or not, i.e. whether it ends in /> or simply - * >. + * @param minimized whether the tag is minimized or not, i.e. whether it ends in {@code />} or simply + * {@code >}. * @return the standalone tag. */ public IStandaloneElementTag createStandaloneElementTag(final String elementName, final String attributeName, final String attributeValue, final boolean synthetic, final boolean minimized); @@ -248,8 +248,8 @@ public IDocType createDocType( * @param attributeValueQuotes the type of quotes to be used for representing the attribute values. * @param synthetic whether the tag is synthetic or not. Synthetic tags are used for balancing of markup and * will not appear on output. - * @param minimized whether the tag is minimized or not, i.e. whether it ends in /> or simply - * >. + * @param minimized whether the tag is minimized or not, i.e. whether it ends in {@code />} or simply + * {@code >}. * @return the standalone tag. */ public IStandaloneElementTag createStandaloneElementTag(final String elementName, final Map attributes, final AttributeValueQuotes attributeValueQuotes, final boolean synthetic, final boolean minimized); @@ -261,7 +261,7 @@ public IDocType createDocType( *

    *

    * This is equivalent to calling {@link #createOpenElementTag(String, boolean)} with - * false as a value for synthetic. + * {@code false} as a value for {@code synthetic}. *

    * * @param elementName the element name. @@ -275,7 +275,7 @@ public IDocType createDocType( *

    *

    * This is equivalent to calling {@link #createOpenElementTag(String, String, String, boolean)} with - * false as a value for synthetic. + * {@code false} as a value for {@code synthetic}. *

    * * @param elementName the element name. @@ -332,7 +332,7 @@ public IDocType createDocType( *

    *

    * This is equivalent to calling {@link #createCloseElementTag(String, boolean, boolean)} with - * false as a value for synthetic and also false as a value for unmatched. + * {@code false} as a value for {@code synthetic} and also {@code false} as a value for {@code unmatched}. *

    * * @param elementName the element name. diff --git a/src/main/java/org/thymeleaf/model/IXMLDeclaration.java b/src/main/java/org/thymeleaf/model/IXMLDeclaration.java index 08c51e292..fd5ad04e2 100644 --- a/src/main/java/org/thymeleaf/model/IXMLDeclaration.java +++ b/src/main/java/org/thymeleaf/model/IXMLDeclaration.java @@ -36,7 +36,7 @@ public interface IXMLDeclaration extends ITemplateEvent { /** *

    * Returns the keyword of the XML Declaration in its original - * case (usually xml). + * case (usually {@code xml}). *

    * * @return the XML Declaration keyword. @@ -54,7 +54,7 @@ public interface IXMLDeclaration extends ITemplateEvent { /** *

    - * Returns the value of the encoding attribute specified at the + * Returns the value of the {@code encoding} attribute specified at the * XML Declaration (if specified). *

    * @@ -64,7 +64,7 @@ public interface IXMLDeclaration extends ITemplateEvent { /** *

    - * Returns the value of the standalone attribute specified at the + * Returns the value of the {@code standalone} attribute specified at the * XML Declaration (if specified). *

    * diff --git a/src/main/java/org/thymeleaf/processor/element/IElementModelProcessor.java b/src/main/java/org/thymeleaf/processor/element/IElementModelProcessor.java index d0e1da418..895da88a1 100644 --- a/src/main/java/org/thymeleaf/processor/element/IElementModelProcessor.java +++ b/src/main/java/org/thymeleaf/processor/element/IElementModelProcessor.java @@ -60,7 +60,7 @@ * useful for traversing an entire model looking for specific nodes or relevant data the Visitor pattern. *

    *

    - * Using the structureHandler + * Using the {@code structureHandler} *

    *

    * Model processors are passed a structure handler object that allows them to instruct the engine to take diff --git a/src/main/java/org/thymeleaf/processor/element/IElementModelStructureHandler.java b/src/main/java/org/thymeleaf/processor/element/IElementModelStructureHandler.java index 5af36f20e..83128fe4a 100644 --- a/src/main/java/org/thymeleaf/processor/element/IElementModelStructureHandler.java +++ b/src/main/java/org/thymeleaf/processor/element/IElementModelStructureHandler.java @@ -71,8 +71,8 @@ public interface IElementModelStructureHandler { * Instructs the engine to set a new selection target. *

    *

    - * The selection target is the object on which selection expressions (*{...}) are executed. - * In the Standard Dialect, this selection target is usually modified by means of the th:object + * The selection target is the object on which selection expressions {@code (*{...})} are executed. + * In the Standard Dialect, this selection target is usually modified by means of the {@code th:object} * attribute, but custom processors can do it too. Note the selection target has the same scope as a local * variable, and will therefore be accessible only inside the body of the element being processed. *

    diff --git a/src/main/java/org/thymeleaf/processor/element/IElementTagProcessor.java b/src/main/java/org/thymeleaf/processor/element/IElementTagProcessor.java index d3f48b1b3..e174b7c6a 100644 --- a/src/main/java/org/thymeleaf/processor/element/IElementTagProcessor.java +++ b/src/main/java/org/thymeleaf/processor/element/IElementTagProcessor.java @@ -32,7 +32,7 @@ * (see {@link IElementProcessor}. *

    *

    - * Using the structureHandler + * Using the {@code structureHandler} *

    *

    * For any actions involving modifications to the tag being processed or the markup structure, processors will diff --git a/src/main/java/org/thymeleaf/processor/element/IElementTagStructureHandler.java b/src/main/java/org/thymeleaf/processor/element/IElementTagStructureHandler.java index 746a936ca..03fcdf322 100644 --- a/src/main/java/org/thymeleaf/processor/element/IElementTagStructureHandler.java +++ b/src/main/java/org/thymeleaf/processor/element/IElementTagStructureHandler.java @@ -151,8 +151,8 @@ public interface IElementTagStructureHandler { * Instructs the engine to set a new selection target. *

    *

    - * The selection target is the object on which selection expressions (*{...}) are executed. - * In the Standard Dialect, this selection target is usually modified by means of the th:object + * The selection target is the object on which selection expressions {@code (*{...})} are executed. + * In the Standard Dialect, this selection target is usually modified by means of the {@code th:object} * attribute, but custom processors can do it too. Note the selection target has the same scope as a local * variable, and will therefore be accessible only inside the body of the element being processed. *

    @@ -200,11 +200,11 @@ public interface IElementTagStructureHandler { /** *

    - * Instructs the engine to set a new body for the current element, in the form of a CharSequence. + * Instructs the engine to set a new body for the current element, in the form of a {@code CharSequence}. *

    *

    * This is the way a processor can change what is shown inside an element during processing. For example, - * it is this way how th:text changes the contents of its containing element. + * it is this way how {@code th:text} changes the contents of its containing element. *

    * * @param text the text to be used as the new body. @@ -220,7 +220,7 @@ public interface IElementTagStructureHandler { *

    *

    * This is the way a processor can change what is shown inside an element during processing. For example, - * it is this way how th:utext changes the contents of its containing element. + * it is this way how {@code th:utext} changes the contents of its containing element. *

    * * @param model the model to be used as the new body. @@ -262,7 +262,7 @@ public interface IElementTagStructureHandler { /** *

    - * Instructs the engine to replace the current element with the specified text (a CharSequence). + * Instructs the engine to replace the current element with the specified text (a {@code CharSequence}). *

    *

    * Note it is the complete element that will be replaced with the specified text, i.e. the @@ -325,7 +325,7 @@ public interface IElementTagStructureHandler { *

    *

    * This method specifies the name of both the iteration variable name and the iterStatus variable - * name, and also the object that should be iterated (usually a Collection, Iterable or + * name, and also the object that should be iterated (usually a {@code Collection}, {@code Iterable} or * similar). *

    * diff --git a/src/main/java/org/thymeleaf/processor/templateboundaries/ITemplateBoundariesStructureHandler.java b/src/main/java/org/thymeleaf/processor/templateboundaries/ITemplateBoundariesStructureHandler.java index 306782ed8..4a52f533a 100644 --- a/src/main/java/org/thymeleaf/processor/templateboundaries/ITemplateBoundariesStructureHandler.java +++ b/src/main/java/org/thymeleaf/processor/templateboundaries/ITemplateBoundariesStructureHandler.java @@ -70,8 +70,8 @@ public interface ITemplateBoundariesStructureHandler { * Instructs the engine to set a new selection target. *

    *

    - * The selection target is the object on which selection expressions (*{...}) are executed. - * In the Standard Dialect, this selection target is usually modified by means of the th:object + * The selection target is the object on which selection expressions {@code (*{...})} are executed. + * In the Standard Dialect, this selection target is usually modified by means of the {@code th:object} * attribute, but custom processors can do it too. Note the selection target has the same scope as a local * variable, and will therefore be accessible only inside the body of the element being processed. *

    diff --git a/src/main/java/org/thymeleaf/standard/StandardDialect.java b/src/main/java/org/thymeleaf/standard/StandardDialect.java index 6eb50df6a..9f7de4738 100644 --- a/src/main/java/org/thymeleaf/standard/StandardDialect.java +++ b/src/main/java/org/thymeleaf/standard/StandardDialect.java @@ -96,11 +96,11 @@ /** *

    * Standard Dialect. This is the class containing the implementation of Thymeleaf Standard Dialect, including all - * th:* processors, expression objects, etc. + * {@code th:*} processors, expression objects, etc. *

    *

    * Note this dialect uses OGNL as an expression language. There is a Spring-integrated version - * of the Standard Dialect called the SpringStandard Dialect at the thymeleaf-spring* packages, + * of the Standard Dialect called the SpringStandard Dialect at the {@code thymeleaf-spring*} packages, * which uses SpringEL as an expression language. *

    *

    @@ -125,18 +125,18 @@ public class StandardDialect // We will avoid setting this variableExpressionEvaluator variable to "OgnlVariableExpressionEvaluator.INSTANCE" // in order to not cause this OGNL-related class to initialize, therefore introducing a forced dependency on OGNL // to Spring users (who don't need OGNL at all). - private IStandardVariableExpressionEvaluator variableExpressionEvaluator = null; + protected IStandardVariableExpressionEvaluator variableExpressionEvaluator = null; // These variables will be initialized lazily if needed (because no value is set to them via their setters) // This should improve startup times (esp. Jackson for the JS serializer) and avoid losing time initializing // objects that might not be used after all if they are overridden via setter. - private IStandardExpressionParser expressionParser = null; - private IStandardConversionService conversionService = null; - private IStandardJavaScriptSerializer javaScriptSerializer = null; - private IStandardCSSSerializer cssSerializer = null; + protected IStandardExpressionParser expressionParser = null; + protected IStandardConversionService conversionService = null; + protected IStandardJavaScriptSerializer javaScriptSerializer = null; + protected IStandardCSSSerializer cssSerializer = null; // Note this is not settable - just lazily initialized - private IExpressionObjectFactory expressionObjectFactory = null; + protected IExpressionObjectFactory expressionObjectFactory = null; diff --git a/src/main/java/org/thymeleaf/standard/expression/Fragment.java b/src/main/java/org/thymeleaf/standard/expression/Fragment.java index 98f110b48..946d57299 100644 --- a/src/main/java/org/thymeleaf/standard/expression/Fragment.java +++ b/src/main/java/org/thymeleaf/standard/expression/Fragment.java @@ -33,7 +33,7 @@ /** *

    * Class that models the result of a {@link FragmentExpression}, i.e. the result of a fragment expression in - * the form of ~{template :: fragment? (parameters)?} + * the form of {@code ~{template :: fragment? (parameters)?}} *

    * * @author Daniel Fernández diff --git a/src/main/java/org/thymeleaf/standard/expression/FragmentExpression.java b/src/main/java/org/thymeleaf/standard/expression/FragmentExpression.java index 6a43f4698..edfe541bb 100644 --- a/src/main/java/org/thymeleaf/standard/expression/FragmentExpression.java +++ b/src/main/java/org/thymeleaf/standard/expression/FragmentExpression.java @@ -55,7 +55,7 @@ public final class FragmentExpression extends SimpleExpression { private static final long serialVersionUID = -130371297698708001L; /** - * This constant contains the {@link FragmentExpression} object representing the EMPTY FRAGMENT (~{}) + * This constant contains the {@link FragmentExpression} object representing the EMPTY FRAGMENT ({@code ~{}}) */ public static final FragmentExpression EMPTY_FRAGMENT_EXPRESSION = new FragmentExpression(); diff --git a/src/main/java/org/thymeleaf/standard/expression/FragmentSignature.java b/src/main/java/org/thymeleaf/standard/expression/FragmentSignature.java index 953b9c009..354aa0e15 100755 --- a/src/main/java/org/thymeleaf/standard/expression/FragmentSignature.java +++ b/src/main/java/org/thymeleaf/standard/expression/FragmentSignature.java @@ -30,7 +30,7 @@ /** *

    * Represents a fragment signature, including both a name and an (optional) sequence of parameter names to be - * applied. Typically the result of parsing a th:fragment attribute. + * applied. Typically the result of parsing a {@code th:fragment} attribute. *

    * * @author Daniel Fernández diff --git a/src/main/java/org/thymeleaf/standard/expression/FragmentSignatureUtils.java b/src/main/java/org/thymeleaf/standard/expression/FragmentSignatureUtils.java index 69fe3925a..fe6322a43 100755 --- a/src/main/java/org/thymeleaf/standard/expression/FragmentSignatureUtils.java +++ b/src/main/java/org/thymeleaf/standard/expression/FragmentSignatureUtils.java @@ -138,7 +138,7 @@ static FragmentSignature internalParseFragmentSignature(final String input) { *

    *

    * This processing matches the specified parameters against the ones in the signature, allowing the specified - * ones (usually coming from a fragment selection like th:include) to be nameless, so that their values + * ones (usually coming from a fragment selection like {@code th:include}) to be nameless, so that their values * are matched to their corresponding variable name during this parameter processing operation. *

    *

    diff --git a/src/main/java/org/thymeleaf/standard/expression/IStandardConversionService.java b/src/main/java/org/thymeleaf/standard/expression/IStandardConversionService.java index 89cb5224a..a6a6401fd 100755 --- a/src/main/java/org/thymeleaf/standard/expression/IStandardConversionService.java +++ b/src/main/java/org/thymeleaf/standard/expression/IStandardConversionService.java @@ -26,14 +26,14 @@ * Common interface for all implementations of a conversion service, to be used during template execution. *

    *

    - * Thymeleaf conversion services work in a way similar to Spring Framework's ConversionService interface, + * Thymeleaf conversion services work in a way similar to Spring Framework's {@code ConversionService} interface, * but this is a generic mechanism (not dependent on Spring). *

    *

    * Default implementation —registered by {@link org.thymeleaf.standard.StandardDialect}— * is {@link StandardConversionService}, which performs some standard conversions, but the * Spring Standard Dialect used by the Thymeleaf + Spring integration module automatically registers an implementation - * of this interface that delegates on any existing Spring ConversionService objects (thus using + * of this interface that delegates on any existing Spring {@code ConversionService} objects (thus using * the Converters and Formatters registered at the Spring Application Context). *

    *

    diff --git a/src/main/java/org/thymeleaf/standard/expression/IStandardVariableExpressionEvaluator.java b/src/main/java/org/thymeleaf/standard/expression/IStandardVariableExpressionEvaluator.java index c2e8e2870..40b53005e 100755 --- a/src/main/java/org/thymeleaf/standard/expression/IStandardVariableExpressionEvaluator.java +++ b/src/main/java/org/thymeleaf/standard/expression/IStandardVariableExpressionEvaluator.java @@ -23,7 +23,7 @@ /** *

    - * Common interface for all objects in charge of executing variable expressions (${...}) inside + * Common interface for all objects in charge of executing variable expressions ({@code ${...}}) inside * Thymeleaf Standard Expressions. *

    *

    diff --git a/src/main/java/org/thymeleaf/standard/expression/LinkExpression.java b/src/main/java/org/thymeleaf/standard/expression/LinkExpression.java index fb2ade1f7..be2d64677 100755 --- a/src/main/java/org/thymeleaf/standard/expression/LinkExpression.java +++ b/src/main/java/org/thymeleaf/standard/expression/LinkExpression.java @@ -269,6 +269,8 @@ static Object executeLinkExpression(final IExpressionContext context, final Link } if (base == null || StringUtils.isEmptyOrWhitespace((String) base)) { base = ""; + } else { + base = ((String) base).trim(); } /* diff --git a/src/main/java/org/thymeleaf/standard/expression/LiteralSubstitutionUtil.java b/src/main/java/org/thymeleaf/standard/expression/LiteralSubstitutionUtil.java index 6fabeb652..dea52baf0 100755 --- a/src/main/java/org/thymeleaf/standard/expression/LiteralSubstitutionUtil.java +++ b/src/main/java/org/thymeleaf/standard/expression/LiteralSubstitutionUtil.java @@ -69,6 +69,7 @@ static String performLiteralSubstitution(final String input) { boolean inLiteralSubstitution = false; boolean inLiteralSubstitutionInsertion = false; + int literalSubstitutionIndex = -1; int expLevel = 0; boolean inLiteral = false; @@ -86,15 +87,24 @@ static String performLiteralSubstitution(final String input) { strBuilder.append(input,0,i); } inLiteralSubstitution = true; + literalSubstitutionIndex = i; } else if (c == LITERAL_SUBSTITUTION_DELIMITER && inLiteralSubstitution && inNothing) { - if (inLiteralSubstitutionInsertion) { + if ((i - literalSubstitutionIndex) == 1) { + // This was an empty literal substitution, which we are not going to process so that it + // cannot be used to mangle in the parsing, interpretation and validity checks of other + // expressions. + strBuilder + .append(LITERAL_SUBSTITUTION_DELIMITER) + .append(LITERAL_SUBSTITUTION_DELIMITER); + } else if (inLiteralSubstitutionInsertion) { strBuilder.append('\''); inLiteralSubstitutionInsertion = false; } inLiteralSubstitution = false; + literalSubstitutionIndex = -1; } else if (inNothing && (c == VariableExpression.SELECTOR || diff --git a/src/main/java/org/thymeleaf/standard/expression/OGNLVariableExpressionEvaluator.java b/src/main/java/org/thymeleaf/standard/expression/OGNLVariableExpressionEvaluator.java index ae71970d9..a8bab7c29 100644 --- a/src/main/java/org/thymeleaf/standard/expression/OGNLVariableExpressionEvaluator.java +++ b/src/main/java/org/thymeleaf/standard/expression/OGNLVariableExpressionEvaluator.java @@ -19,9 +19,16 @@ */ package org.thymeleaf.standard.expression; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.util.Collections; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import ognl.ClassResolver; +import ognl.DefaultMemberAccess; +import ognl.MemberAccess; import ognl.OgnlContext; import ognl.OgnlException; import ognl.OgnlRuntime; @@ -35,10 +42,11 @@ import org.thymeleaf.exceptions.TemplateProcessingException; import org.thymeleaf.expression.IExpressionObjects; import org.thymeleaf.standard.util.StandardExpressionUtils; +import org.thymeleaf.util.ExpressionUtils; /** *

    - * Evaluator for variable expressions (${...}) in Thymeleaf Standard Expressions, using the + * Evaluator for variable expressions ({@code ${...}}) in Thymeleaf Standard Expressions, using the * OGNL expression language. *

    *

    @@ -65,6 +73,8 @@ public final class OGNLVariableExpressionEvaluator OGNLContextPropertyAccessor.RESTRICT_REQUEST_PARAMETERS, OGNLContextPropertyAccessor.RESTRICT_REQUEST_PARAMETERS); + private static MemberAccess MEMBER_ACCESS = new ThymeleafACLMemberAccess(); + private static ThymeleafACLClassResolver CLASS_RESOLVER = new ThymeleafACLClassResolver(); private final boolean applyOGNLShortcuts; @@ -120,7 +130,7 @@ private static Object evaluate( } final ComputedOGNLExpression parsedExpression = - obtainComputedOGNLExpression(configuration, expression, exp, applyOGNLShortcuts); + obtainComputedOGNLExpression(configuration, expression, exp, expContext, applyOGNLShortcuts); final Map contextVariablesMap; if (parsedExpression.mightNeedExpressionObjects) { @@ -197,9 +207,17 @@ private static Object evaluate( private static ComputedOGNLExpression obtainComputedOGNLExpression( - final IEngineConfiguration configuration, final IStandardVariableExpression expression, final String exp, + final IEngineConfiguration configuration, + final IStandardVariableExpression expression, final String exp, + final StandardExpressionExecutionContext expContext, final boolean applyOGNLShortcuts) throws OgnlException { + if (expContext.getRestrictInstantiationAndStatic() + && StandardExpressionUtils.containsOGNLInstantiationOrStaticOrParam(exp)) { + throw new TemplateProcessingException( + "Instantiation of new objects and access to static classes or parameters is forbidden in this context"); + } + if (expression instanceof VariableExpression) { final VariableExpression vexpression = (VariableExpression) expression; @@ -238,7 +256,8 @@ private static ComputedOGNLExpression obtainComputedOGNLExpression( private static ComputedOGNLExpression parseComputedOGNLExpression( - final IEngineConfiguration configuration, final String exp, final boolean applyOGNLShortcuts) + final IEngineConfiguration configuration, + final String exp, final boolean applyOGNLShortcuts) throws OgnlException { ComputedOGNLExpression parsedExpression = @@ -283,7 +302,8 @@ public String toString() { - private static ComputedOGNLExpression parseExpression(final String expression, final boolean applyOGNLShortcuts) + private static ComputedOGNLExpression parseExpression( + final String expression, final boolean applyOGNLShortcuts) throws OgnlException { final boolean mightNeedExpressionObjects = StandardExpressionUtils.mightNeedExpressionObjects(expression); @@ -312,7 +332,7 @@ private static Object executeExpression( // We create the OgnlContext here instead of just sending the Map as context because that prevents OGNL from // creating the OgnlContext empty and then setting the context Map variables one by one - final OgnlContext ognlContext = new OgnlContext(context); + final OgnlContext ognlContext = new OgnlContext(CLASS_RESOLVER, null, MEMBER_ACCESS, context); return ognl.Ognl.getValue(parsedExpression, ognlContext, root); } @@ -335,5 +355,92 @@ private static final class ComputedOGNLExpression { } + static final class ThymeleafACLClassResolver implements ClassResolver { + + private final ClassResolver classResolver; + + public ThymeleafACLClassResolver() { + super(); + this.classResolver = new ThymeleafDefaultClassResolver(); + } + + @Override + public Class classForName(final String className, final Map context) throws ClassNotFoundException { + if (className != null && !ExpressionUtils.isTypeAllowed(className)) { + throw new TemplateProcessingException( + String.format( + "Access is forbidden for type '%s' in Thymeleaf expressions. " + + "Blocked classes are: %s.", + className, ExpressionUtils.getBlockedClasses())); + } + return this.classResolver.classForName(className, context); + } + + } + + + /* + * We need to implement this instead of directly using OGNL's DefaultClassResolver because OGNL's + * will always try to prepend "java.lang." to classes that it cannot find, which in our case is dangerous. * + * Other than that, the code in this class is the same as "ognl.DefaultClassResolver". + */ + static final class ThymeleafDefaultClassResolver implements ClassResolver { + + private final ConcurrentHashMap classes = new ConcurrentHashMap(101); + + ThymeleafDefaultClassResolver() { + super(); + } + + public Class classForName(final String className, final Map context) throws ClassNotFoundException { + Class result = this.classes.get(className); + if (result != null) { + return result; + } + try { + result = toClassForName(className); + } catch (ClassNotFoundException e) { + throw e; + } + this.classes.putIfAbsent(className, result); + return result; + } + + private Class toClassForName(String className) throws ClassNotFoundException { + return Class.forName(className); + } + + } + + + static final class ThymeleafACLMemberAccess extends DefaultMemberAccess { + + ThymeleafACLMemberAccess() { + super(false); + } + + @Override + public boolean isAccessible(final Map context, final Object target, final Member member, final String propertyName) { + int modifiers = member.getModifiers(); + if (!Modifier.isPublic(modifiers)) { + return false; + } + if (member instanceof Method) { + final Class declaringClass = member.getDeclaringClass(); + if (!ExpressionUtils.isTypeAllowed(declaringClass.getName())) { + // We will only specifically allow calling "Object.getClass()" and "Class.getName()" + if (!(Class.class.equals(declaringClass) && "getName".equals(member.getName())) + && !(Object.class.equals(declaringClass) && "getClass".equals(member.getName()))) { + throw new TemplateProcessingException( + String.format( + "Calling methods is forbidden for type '%s' in Thymeleaf expressions. " + + "Blocked classes are: %s.", + declaringClass.getName(), ExpressionUtils.getBlockedClasses())); + } + } + } + return super.isAccessible(context, target, member, propertyName); + } + } } diff --git a/src/main/java/org/thymeleaf/standard/expression/SelectionVariableExpression.java b/src/main/java/org/thymeleaf/standard/expression/SelectionVariableExpression.java index fc8a761d5..6560efa7c 100755 --- a/src/main/java/org/thymeleaf/standard/expression/SelectionVariableExpression.java +++ b/src/main/java/org/thymeleaf/standard/expression/SelectionVariableExpression.java @@ -26,6 +26,7 @@ import org.slf4j.LoggerFactory; import org.thymeleaf.TemplateEngine; import org.thymeleaf.context.IExpressionContext; +import org.thymeleaf.exceptions.TemplateProcessingException; import org.thymeleaf.util.Validate; @@ -154,8 +155,28 @@ static Object executeSelectionVariableExpression( final StandardExpressionExecutionContext evalExpContext = (expression.getConvertToString()? expContext.withTypeConversion() : expContext.withoutTypeConversion()); - return expressionEvaluator.evaluate(context, expression, evalExpContext); - + final Object result = expressionEvaluator.evaluate(context, expression, evalExpContext); + + if (!expContext.getForbidUnsafeExpressionResults()) { + return result; + } + + // We are only allowing results of type Number and Boolean, and cosidering the rest of data types "unsafe", + // as they could be rendered into a non-trustable String. This is mainly useful for helping prevent code + // injection in th:on* event handlers. + if (result == null + || result instanceof Number + || result instanceof Boolean) { + return result; + } + + throw new TemplateProcessingException( + "Only variable expressions returning numbers or booleans are allowed in this context, any other data" + + "types are not trusted in the context of this expression, including Strings or any other " + + "object that could be rendered as a text literal. A typical case is HTML attributes for event handlers (e.g. " + + "\"onload\"), in which textual data from variables should better be output to \"data-*\" attributes and then " + + "read from the event handler."); + } diff --git a/src/main/java/org/thymeleaf/standard/expression/StandardExpressionExecutionContext.java b/src/main/java/org/thymeleaf/standard/expression/StandardExpressionExecutionContext.java index a8418ab4e..fb377030c 100755 --- a/src/main/java/org/thymeleaf/standard/expression/StandardExpressionExecutionContext.java +++ b/src/main/java/org/thymeleaf/standard/expression/StandardExpressionExecutionContext.java @@ -39,18 +39,35 @@ */ public final class StandardExpressionExecutionContext { - public static final StandardExpressionExecutionContext RESTRICTED = new StandardExpressionExecutionContext(true, false); - public static final StandardExpressionExecutionContext RESTRICTED_WITH_TYPE_CONVERSION = new StandardExpressionExecutionContext(true, true); - public static final StandardExpressionExecutionContext NORMAL = new StandardExpressionExecutionContext(false, false); - public static final StandardExpressionExecutionContext NORMAL_WITH_TYPE_CONVERSION = new StandardExpressionExecutionContext(false, true); + public static final StandardExpressionExecutionContext RESTRICTED = + new StandardExpressionExecutionContext(true, true, false, false); + public static final StandardExpressionExecutionContext RESTRICTED_FORBID_UNSAFE_EXP_RESULTS = + new StandardExpressionExecutionContext(true, true, true, false); + public static final StandardExpressionExecutionContext NORMAL = + new StandardExpressionExecutionContext(false, false, false, false); + + private static final StandardExpressionExecutionContext RESTRICTED_WITH_TYPE_CONVERSION = + new StandardExpressionExecutionContext(true, true, false,true); + private static final StandardExpressionExecutionContext RESTRICTED_FORBID_UNSAFE_EXP_RESULTS_WITH_TYPE_CONVERSION = + new StandardExpressionExecutionContext(true, true, true, true); + private static final StandardExpressionExecutionContext NORMAL_WITH_TYPE_CONVERSION = + new StandardExpressionExecutionContext(false, false, false, true); private final boolean restrictVariableAccess; + private final boolean restrictInstantiationAndStatic; + private final boolean forbidUnsafeExpressionResults; private final boolean performTypeConversion; + - - private StandardExpressionExecutionContext(final boolean restrictVariableAccess, final boolean performTypeConversion) { + private StandardExpressionExecutionContext( + final boolean restrictVariableAccess, + final boolean restrictInstantiationAndStatic, + final boolean forbidUnsafeExpressionResults, + final boolean performTypeConversion) { super(); this.restrictVariableAccess = restrictVariableAccess; + this.restrictInstantiationAndStatic = restrictInstantiationAndStatic; + this.forbidUnsafeExpressionResults = forbidUnsafeExpressionResults; this.performTypeConversion = performTypeConversion; } @@ -58,28 +75,57 @@ public boolean getRestrictVariableAccess() { return this.restrictVariableAccess; } + /** + * Restricts whether this execution context restricts the instantiation of new objects and the + * access to static classes. + * + * @return Whether this restriction should be applied or not. + * @since 3.0.12 + */ + public boolean getRestrictInstantiationAndStatic() { + return this.restrictInstantiationAndStatic; + } + + public boolean getForbidUnsafeExpressionResults() { + return this.forbidUnsafeExpressionResults; + } + public boolean getPerformTypeConversion() { return this.performTypeConversion; } public StandardExpressionExecutionContext withoutTypeConversion() { + if (!getPerformTypeConversion()) { + return this; + } if (this == NORMAL_WITH_TYPE_CONVERSION) { return NORMAL; } if (this == RESTRICTED_WITH_TYPE_CONVERSION) { return RESTRICTED; } - return this; + if (this == RESTRICTED_FORBID_UNSAFE_EXP_RESULTS_WITH_TYPE_CONVERSION) { + return RESTRICTED_FORBID_UNSAFE_EXP_RESULTS; + } + return new StandardExpressionExecutionContext( + getRestrictVariableAccess(), getRestrictInstantiationAndStatic(), getForbidUnsafeExpressionResults(), false); } public StandardExpressionExecutionContext withTypeConversion() { + if (getPerformTypeConversion()) { + return this; + } if (this == NORMAL) { return NORMAL_WITH_TYPE_CONVERSION; } if (this == RESTRICTED) { return RESTRICTED_WITH_TYPE_CONVERSION; } - return this; + if (this == RESTRICTED_FORBID_UNSAFE_EXP_RESULTS) { + return RESTRICTED_FORBID_UNSAFE_EXP_RESULTS_WITH_TYPE_CONVERSION; + } + return new StandardExpressionExecutionContext( + getRestrictVariableAccess(), getRestrictInstantiationAndStatic(), getForbidUnsafeExpressionResults(), true); } diff --git a/src/main/java/org/thymeleaf/standard/expression/StandardExpressionPreprocessor.java b/src/main/java/org/thymeleaf/standard/expression/StandardExpressionPreprocessor.java index 65f34acff..147b572b5 100755 --- a/src/main/java/org/thymeleaf/standard/expression/StandardExpressionPreprocessor.java +++ b/src/main/java/org/thymeleaf/standard/expression/StandardExpressionPreprocessor.java @@ -27,7 +27,7 @@ /** *

    - * Expression preprocessor, in charge of executing __...__ fragments in Thymeleaf Standard Expressions. + * Expression preprocessor, in charge of executing {@code __...__} fragments in Thymeleaf Standard Expressions. *

    *

    * Note a class with this name existed since 2.1.0, but it was completely reimplemented diff --git a/src/main/java/org/thymeleaf/standard/expression/VariableExpression.java b/src/main/java/org/thymeleaf/standard/expression/VariableExpression.java index 5fc620ce2..64650631c 100755 --- a/src/main/java/org/thymeleaf/standard/expression/VariableExpression.java +++ b/src/main/java/org/thymeleaf/standard/expression/VariableExpression.java @@ -26,6 +26,7 @@ import org.slf4j.LoggerFactory; import org.thymeleaf.TemplateEngine; import org.thymeleaf.context.IExpressionContext; +import org.thymeleaf.exceptions.TemplateProcessingException; import org.thymeleaf.util.Validate; @@ -162,7 +163,27 @@ static Object executeVariableExpression( final StandardExpressionExecutionContext evalExpContext = (expression.getConvertToString()? expContext.withTypeConversion() : expContext.withoutTypeConversion()); - return expressionEvaluator.evaluate(context, expression, evalExpContext); + final Object result = expressionEvaluator.evaluate(context, expression, evalExpContext); + + if (!expContext.getForbidUnsafeExpressionResults()) { + return result; + } + + // We are only allowing results of type Number and Boolean, and cosidering the rest of data types "unsafe", + // as they could be rendered into a non-trustable String. This is mainly useful for helping prevent code + // injection in th:on* event handlers. + if (result == null + || result instanceof Number + || result instanceof Boolean) { + return result; + } + + throw new TemplateProcessingException( + "Only variable expressions returning numbers or booleans are allowed in this context, any other data" + + "types are not trusted in the context of this expression, including Strings or any other " + + "object that could be rendered as a text literal. A typical case is HTML attributes for event handlers (e.g. " + + "\"onload\"), in which textual data from variables should better be output to \"data-*\" attributes and then " + + "read from the event handler."); } diff --git a/src/main/java/org/thymeleaf/standard/processor/AbstractStandardAttributeModifierTagProcessor.java b/src/main/java/org/thymeleaf/standard/processor/AbstractStandardAttributeModifierTagProcessor.java index 1831ca33c..896cfe6da 100644 --- a/src/main/java/org/thymeleaf/standard/processor/AbstractStandardAttributeModifierTagProcessor.java +++ b/src/main/java/org/thymeleaf/standard/processor/AbstractStandardAttributeModifierTagProcessor.java @@ -26,6 +26,7 @@ import org.thymeleaf.engine.IAttributeDefinitionsAware; import org.thymeleaf.model.IProcessableElementTag; import org.thymeleaf.processor.element.IElementTagStructureHandler; +import org.thymeleaf.standard.expression.StandardExpressionExecutionContext; import org.thymeleaf.standard.util.StandardProcessorUtils; import org.thymeleaf.templatemode.TemplateMode; import org.thymeleaf.util.EscapedAttributeUtils; @@ -93,6 +94,29 @@ protected AbstractStandardAttributeModifierTagProcessor( } + /** + *

    + * Build a new instance of this tag processor. + *

    + * + * @param templateMode the template mode. + * @param dialectPrefix the dialect prefix. + * @param attrName the attribute name to be matched. + * @param precedence the precedence to be applied. + * @param removeIfEmpty whether the attribute should be removed if the result of executing the expression is empty. + * @param expressionExecutionContext the expression execution context to be applied. + * + * @since 3.0.10 + */ + protected AbstractStandardAttributeModifierTagProcessor( + final TemplateMode templateMode, + final String dialectPrefix, final String attrName, + final int precedence, final boolean removeIfEmpty, + final StandardExpressionExecutionContext expressionExecutionContext) { + this(templateMode, dialectPrefix, attrName, attrName, precedence, removeIfEmpty, expressionExecutionContext); + } + + /** *

    * Build a new instance of this tag processor. @@ -153,6 +177,37 @@ protected AbstractStandardAttributeModifierTagProcessor( } + /** + *

    + * Build a new instance of this tag processor. + *

    + * + * @param templateMode the template mode. + * @param dialectPrefix the dialect prefix. + * @param attrName the attribute name to be matched. + * @param targetAttrCompleteName complete name of target attribut. + * @param precedence the precedence to be applied. + * @param removeIfEmpty whether the attribute should be removed if the result of executing the expression is empty. + * @param expressionExecutionContext the expression execution context to be applied. + * + * @since 3.0.10 + */ + protected AbstractStandardAttributeModifierTagProcessor( + final TemplateMode templateMode, final String dialectPrefix, + final String attrName, final String targetAttrCompleteName, + final int precedence, final boolean removeIfEmpty, + final StandardExpressionExecutionContext expressionExecutionContext) { + + super(templateMode, dialectPrefix, attrName, precedence, false, expressionExecutionContext); + + Validate.notNull(targetAttrCompleteName, "Complete name of target attribute cannot be null"); + + this.targetAttrCompleteName = targetAttrCompleteName; + this.removeIfEmpty = removeIfEmpty; + + } + + public void setAttributeDefinitions(final AttributeDefinitions attributeDefinitions) { diff --git a/src/main/java/org/thymeleaf/standard/processor/AbstractStandardExpressionAttributeTagProcessor.java b/src/main/java/org/thymeleaf/standard/processor/AbstractStandardExpressionAttributeTagProcessor.java index 0f978dd9e..480f91e4e 100644 --- a/src/main/java/org/thymeleaf/standard/processor/AbstractStandardExpressionAttributeTagProcessor.java +++ b/src/main/java/org/thymeleaf/standard/processor/AbstractStandardExpressionAttributeTagProcessor.java @@ -41,7 +41,7 @@ public abstract class AbstractStandardExpressionAttributeTagProcessor extends AbstractAttributeTagProcessor { - private final boolean restrictedExpressionExecution; + private final StandardExpressionExecutionContext expressionExecutionContext; private final boolean removeIfNoop; @@ -60,7 +60,7 @@ public abstract class AbstractStandardExpressionAttributeTagProcessor extends Ab protected AbstractStandardExpressionAttributeTagProcessor( final TemplateMode templateMode, final String dialectPrefix, final String attrName, final int precedence, final boolean removeAttribute) { - this(templateMode, dialectPrefix, attrName, precedence, removeAttribute, false); + this(templateMode, dialectPrefix, attrName, precedence, removeAttribute, StandardExpressionExecutionContext.NORMAL); } /** @@ -82,9 +82,31 @@ protected AbstractStandardExpressionAttributeTagProcessor( final TemplateMode templateMode, final String dialectPrefix, final String attrName, final int precedence, final boolean removeAttribute, final boolean restrictedExpressionExecution) { + this(templateMode, dialectPrefix, attrName, precedence, removeAttribute, + (restrictedExpressionExecution? StandardExpressionExecutionContext.RESTRICTED : StandardExpressionExecutionContext.NORMAL)); + } + + /** + *

    + * Build a new instance of this tag processor. + *

    + * + * @param templateMode the template mode + * @param dialectPrefix the dialect prefox + * @param attrName the attribute name to be matched + * @param precedence the precedence to be applied + * @param removeAttribute whether the attribute should be removed after execution + * @param expressionExecutionContext the expression execution context to be applied + * + * @since 3.0.10 + */ + protected AbstractStandardExpressionAttributeTagProcessor( + final TemplateMode templateMode, final String dialectPrefix, + final String attrName, final int precedence, final boolean removeAttribute, + final StandardExpressionExecutionContext expressionExecutionContext) { super(templateMode, dialectPrefix, null, false, attrName, true, precedence, removeAttribute); this.removeIfNoop = !removeAttribute; - this.restrictedExpressionExecution = restrictedExpressionExecution; + this.expressionExecutionContext = expressionExecutionContext; } @@ -119,11 +141,7 @@ protected final void doProcess( * Some attributes will require the execution of the expressions contained in them in RESTRICTED * mode, so that e.g. access to request parameters is forbidden. */ - final StandardExpressionExecutionContext expCtx = - (this.restrictedExpressionExecution? - StandardExpressionExecutionContext.RESTRICTED : StandardExpressionExecutionContext.NORMAL); - - expressionResult = expression.execute(context, expCtx); + expressionResult = expression.execute(context, this.expressionExecutionContext); } diff --git a/src/main/java/org/thymeleaf/standard/processor/StandardDOMEventAttributeTagProcessor.java b/src/main/java/org/thymeleaf/standard/processor/StandardDOMEventAttributeTagProcessor.java index 45182375c..a007236f5 100644 --- a/src/main/java/org/thymeleaf/standard/processor/StandardDOMEventAttributeTagProcessor.java +++ b/src/main/java/org/thymeleaf/standard/processor/StandardDOMEventAttributeTagProcessor.java @@ -19,7 +19,29 @@ */ package org.thymeleaf.standard.processor; +import java.io.Writer; + +import org.thymeleaf.context.ITemplateContext; +import org.thymeleaf.engine.AttributeDefinition; +import org.thymeleaf.engine.AttributeDefinitions; +import org.thymeleaf.engine.AttributeName; +import org.thymeleaf.engine.EngineEventUtils; +import org.thymeleaf.engine.IAttributeDefinitionsAware; +import org.thymeleaf.engine.TemplateManager; +import org.thymeleaf.engine.TemplateModel; +import org.thymeleaf.exceptions.TemplateProcessingException; +import org.thymeleaf.model.IAttribute; +import org.thymeleaf.model.IProcessableElementTag; +import org.thymeleaf.processor.element.AbstractAttributeTagProcessor; +import org.thymeleaf.processor.element.IElementTagStructureHandler; +import org.thymeleaf.standard.expression.IStandardExpression; +import org.thymeleaf.standard.expression.NoOpToken; +import org.thymeleaf.standard.expression.StandardExpressionExecutionContext; +import org.thymeleaf.standard.util.StandardProcessorUtils; import org.thymeleaf.templatemode.TemplateMode; +import org.thymeleaf.util.EscapedAttributeUtils; +import org.thymeleaf.util.FastStringWriter; +import org.thymeleaf.util.Validate; /** * @@ -28,7 +50,9 @@ * @since 3.0.0 * */ -public final class StandardDOMEventAttributeTagProcessor extends AbstractStandardAttributeModifierTagProcessor { +public final class StandardDOMEventAttributeTagProcessor + extends AbstractAttributeTagProcessor + implements IAttributeDefinitionsAware { public static final int PRECEDENCE = 1000; @@ -108,9 +132,122 @@ public final class StandardDOMEventAttributeTagProcessor extends AbstractStandar }; + private final String targetAttrCompleteName; + + private AttributeDefinition targetAttributeDefinition; + + + + public StandardDOMEventAttributeTagProcessor(final String dialectPrefix, final String attrName) { - super(TemplateMode.HTML, dialectPrefix, attrName, PRECEDENCE, true, true); + + super(TemplateMode.HTML, dialectPrefix, null, false, attrName, true, PRECEDENCE, false); + + Validate.notNull(attrName, "Complete name of target attribute cannot be null"); + + this.targetAttrCompleteName = attrName; + + } + + + public void setAttributeDefinitions(final AttributeDefinitions attributeDefinitions) { + Validate.notNull(attributeDefinitions, "Attribute Definitions cannot be null"); + // We precompute the AttributeDefinition of the target attribute in order to being able to use much + // faster methods for setting/replacing attributes on the ElementAttributes implementation + this.targetAttributeDefinition = attributeDefinitions.forName(getTemplateMode(), this.targetAttrCompleteName); + } + + + + protected void doProcess( + final ITemplateContext context, + final IProcessableElementTag tag, + final AttributeName attributeName, final String attributeValue, + final Object expressionResult, + final IElementTagStructureHandler structureHandler) { + + final String newAttributeValue = + EscapedAttributeUtils.escapeAttribute(getTemplateMode(), expressionResult == null ? null : expressionResult.toString()); + + // These attributes are "removable if empty", so we simply remove the target attribute... + if (newAttributeValue == null || newAttributeValue.length() == 0) { + + // We are removing the equivalent attribute name, without the prefix... + structureHandler.removeAttribute(this.targetAttributeDefinition.getAttributeName()); + structureHandler.removeAttribute(attributeName); + + } else { + + // We are setting the equivalent attribute name, without the prefix... + StandardProcessorUtils.replaceAttribute( + structureHandler, attributeName, this.targetAttributeDefinition, this.targetAttrCompleteName, (newAttributeValue == null ? "" : newAttributeValue)); + + } + } -} + @Override + protected void doProcess( + final ITemplateContext context, + final IProcessableElementTag tag, + final AttributeName attributeName, final String attributeValue, + final IElementTagStructureHandler structureHandler) { + + final Object expressionResult; + if (attributeValue != null) { + + IStandardExpression expression = null; + try { + expression = EngineEventUtils.computeAttributeExpression(context, tag, attributeName, attributeValue); + } catch (final TemplateProcessingException e) { + // The attribute value seems not to be a Thymeleaf Standard Expression. This is something that could + // be perfectly OK, as these event handler attributes are allowed to contain a fragment of + // JavaScript as their value, which will be processed as fragments in JAVASCRIPT template mode. + } + + if (expression != null) { + + // This expression will be evaluated using restricted mode including the prohibition to evaluate + // variable expressions that result in a String or in any objects that could be translated to + // untrustable text literals. + expressionResult = expression.execute(context, StandardExpressionExecutionContext.RESTRICTED_FORBID_UNSAFE_EXP_RESULTS); + + } else { + // The attribute value is not parseable as a Thymeleaf Standard Expression, so we will process it + // as a JavaScript fragment, applying the same logic used in AbstractStandardInliner + + final IAttribute attribute = tag.getAttribute(attributeName); + final TemplateManager templateManager = context.getConfiguration().getTemplateManager(); + + final TemplateModel templateModel = + templateManager.parseString( + context.getTemplateData(), attributeValue, + attribute.getLine(), attribute.getCol(), + TemplateMode.JAVASCRIPT, true); + + final Writer stringWriter = new FastStringWriter(50); + templateManager.process(templateModel, context, stringWriter); + + expressionResult = stringWriter.toString(); + + } + + } else { + expressionResult = null; + } + + // If the result of this expression is NO-OP, there is nothing to execute + if (expressionResult == NoOpToken.VALUE) { + structureHandler.removeAttribute(attributeName); + return; + } + + doProcess( + context, tag, + attributeName, attributeValue, + expressionResult, structureHandler); + + } + +} \ No newline at end of file diff --git a/src/main/java/org/thymeleaf/standard/serializer/IStandardCSSSerializer.java b/src/main/java/org/thymeleaf/standard/serializer/IStandardCSSSerializer.java index a556c4af2..a902505d7 100644 --- a/src/main/java/org/thymeleaf/standard/serializer/IStandardCSSSerializer.java +++ b/src/main/java/org/thymeleaf/standard/serializer/IStandardCSSSerializer.java @@ -30,7 +30,7 @@ *

    * CSS serializer objects are in charge of outputting values both in templates using * {@link org.thymeleaf.templatemode.TemplateMode#CSS} and in inlined code by means of e.g. - * th:inline="css" blocks. + * {@code th:inline="css"} blocks. *

    * * @author Daniel Fernández diff --git a/src/main/java/org/thymeleaf/standard/serializer/IStandardJavaScriptSerializer.java b/src/main/java/org/thymeleaf/standard/serializer/IStandardJavaScriptSerializer.java index 1ae1606ea..9652f74b1 100644 --- a/src/main/java/org/thymeleaf/standard/serializer/IStandardJavaScriptSerializer.java +++ b/src/main/java/org/thymeleaf/standard/serializer/IStandardJavaScriptSerializer.java @@ -30,7 +30,7 @@ *

    * JavaScript serializer objects are in charge of outputting values both in templates using * {@link org.thymeleaf.templatemode.TemplateMode#JAVASCRIPT} and in inlined code by means of e.g. - * th:inline="javascript" blocks. + * {@code th:inline="javascript"} blocks. *

    * * @author Daniel Fernández diff --git a/src/main/java/org/thymeleaf/standard/serializer/StandardJavaScriptSerializer.java b/src/main/java/org/thymeleaf/standard/serializer/StandardJavaScriptSerializer.java index 0de22710a..1018a281e 100644 --- a/src/main/java/org/thymeleaf/standard/serializer/StandardJavaScriptSerializer.java +++ b/src/main/java/org/thymeleaf/standard/serializer/StandardJavaScriptSerializer.java @@ -70,7 +70,7 @@ *

    *

    * Note that, even if Jackson is present in the classpath, its usage can be prevented by means of the - * useJacksonIfAvailable constructor flag. + * {@code useJacksonIfAvailable} constructor flag. *

    * * @author Daniel Fernández diff --git a/src/main/java/org/thymeleaf/standard/util/StandardConditionalCommentUtils.java b/src/main/java/org/thymeleaf/standard/util/StandardConditionalCommentUtils.java index 372172101..271d2fd61 100755 --- a/src/main/java/org/thymeleaf/standard/util/StandardConditionalCommentUtils.java +++ b/src/main/java/org/thymeleaf/standard/util/StandardConditionalCommentUtils.java @@ -48,7 +48,7 @@ public final class StandardConditionalCommentUtils { *

    *

    * Result is an object of class {@link ConditionalCommentParsingResult}, or - * null if text does not have the expected format for a conditional comment. + * {@code null} if text does not have the expected format for a conditional comment. *

    * * @param text the text to be parsed diff --git a/src/main/java/org/thymeleaf/standard/util/StandardExpressionUtils.java b/src/main/java/org/thymeleaf/standard/util/StandardExpressionUtils.java index 8460cdc08..7fcc2b20f 100644 --- a/src/main/java/org/thymeleaf/standard/util/StandardExpressionUtils.java +++ b/src/main/java/org/thymeleaf/standard/util/StandardExpressionUtils.java @@ -32,6 +32,11 @@ public final class StandardExpressionUtils { private static final char[] EXEC_INFO_ARRAY = "ofnIcexe".toCharArray(); // Inverted "execInfo" private static final int EXEC_INFO_LEN = EXEC_INFO_ARRAY.length; + private static final char[] NEW_ARRAY = "wen".toCharArray(); // Inverted "new" + private static final int NEW_LEN = NEW_ARRAY.length; + private static final char[] PARAM_ARRAY = "marap".toCharArray(); // Inverted "param" + private static final int PARAM_LEN = PARAM_ARRAY.length; + public static boolean mightNeedExpressionObjects(final String expression) { /* @@ -60,7 +65,7 @@ public static boolean mightNeedExpressionObjects(final String expression) { } } else { if (ei > 0) { - // We 'restart' the matching counter just in case we had a partial match + // We 'restart' the counter (just after the first matched char) in case we had a partial match n += ei; } ei = 0; @@ -70,6 +75,94 @@ public static boolean mightNeedExpressionObjects(final String expression) { } + /** + * + * @since 3.0.12 + */ + public static boolean containsOGNLInstantiationOrStaticOrParam(final String expression) { + + /* + * Checks whether the expression contains instantiation of objects ("new SomeClass") or makes use of + * static methods ("@SomeClass@") as both are forbidden in certain contexts in restricted mode. + */ + + final int explen = expression.length(); + int n = explen; + int ni = 0; // index for computing position in the NEW_ARRAY + int pi = 0; // index for computing position in the PARAM_ARRAY + int si = -1; + char c; + while (n-- != 0) { + + c = expression.charAt(n); + + // When checking for the "new" keyword, we need to identify that it is not a part of a larger + // identifier, i.e. there is whitespace after it and no character that might be a part of an + // identifier before it. + if (ni < NEW_LEN + && c == NEW_ARRAY[ni] + && (ni > 0 || ((n + 1 < explen) && Character.isWhitespace(expression.charAt(n + 1))))) { + ni++; + if (ni == NEW_LEN && (n == 0 || !isSafeIdentifierChar(expression.charAt(n - 1)))) { + return true; // we found an object instantiation + } + continue; + } + + if (ni > 0) { + // We 'restart' the matching counter just in case we had a partial match + n += ni; + ni = 0; + if (si < n) { + // This has to be restarted too + si = -1; + } + continue; + } + + ni = 0; + + // When checking for the "param" keyword, we need to identify that it is not a part of a larger + // identifier. + if (pi < PARAM_LEN + && c == PARAM_ARRAY[pi] + && (pi > 0 || ((n + 1 < explen) && !isSafeIdentifierChar(expression.charAt(n + 1))))) { + pi++; + if (pi == PARAM_LEN && (n == 0 || !isSafeIdentifierChar(expression.charAt(n - 1)))) { + return true; // we found a param access + } + continue; + } + + if (pi > 0) { + // We 'restart' the matching counter just in case we had a partial match + n += pi; + pi = 0; + continue; + } + + pi = 0; + + if (c == '@') { + if (si > n) { + return true; + } + si = n; + } else if (si > n && !(Character.isJavaIdentifierPart(c) || Character.isWhitespace(c) || c == '.')) { + si = -1; + } + + } + + return false; + + } + + + private static boolean isSafeIdentifierChar(final char c) { + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_'; + } + diff --git a/src/main/java/org/thymeleaf/templateparser/markup/decoupled/IDecoupledTemplateLogicResolver.java b/src/main/java/org/thymeleaf/templateparser/markup/decoupled/IDecoupledTemplateLogicResolver.java index 883cfe95f..6ccf78541 100644 --- a/src/main/java/org/thymeleaf/templateparser/markup/decoupled/IDecoupledTemplateLogicResolver.java +++ b/src/main/java/org/thymeleaf/templateparser/markup/decoupled/IDecoupledTemplateLogicResolver.java @@ -67,7 +67,7 @@ public interface IDecoupledTemplateLogicResolver { * @param templateSelectors the selectors to be used, defining the fragments that should be processed. * @param resource the resource of the resolved template. * @param templateMode the template mode to be applied to the resolved template. - * @return the resource containing the decoupled template logic, or null if there isn't any. + * @return the resource containing the decoupled template logic, or {@code null} if there isn't any. */ public ITemplateResource resolveDecoupledTemplateLogic( final IEngineConfiguration configuration, diff --git a/src/main/java/org/thymeleaf/templateparser/markup/decoupled/StandardDecoupledTemplateLogicResolver.java b/src/main/java/org/thymeleaf/templateparser/markup/decoupled/StandardDecoupledTemplateLogicResolver.java index 2a082223c..df5aa58ac 100644 --- a/src/main/java/org/thymeleaf/templateparser/markup/decoupled/StandardDecoupledTemplateLogicResolver.java +++ b/src/main/java/org/thymeleaf/templateparser/markup/decoupled/StandardDecoupledTemplateLogicResolver.java @@ -35,16 +35,16 @@ *

    *

    * By default, the relative location resolved will be formed as - * resource.getBaseName() + DECOUPLED_TEMPLATE_LOGIC_FILE_SUFFIX (see + * {@code resource.getBaseName() + DECOUPLED_TEMPLATE_LOGIC_FILE_SUFFIX} (see * {@link ITemplateResource#getBaseName()} and {@link #DECOUPLED_TEMPLATE_LOGIC_FILE_SUFFIX}. - * So for a template resource /WEB-INF/templates/main.html, the main.th.xml relative + * So for a template resource {@code /WEB-INF/templates/main.html}, the {@code main.th.xml} relative * location will be used to call {@link ITemplateResource#relative(String)}. *

    *

    - * However this can be modified by specifying different prefix and suffix values so that, if a - * prefix with value "../logic/" is specified, for a template resource - * /WEB-INF/templates/main.html, the ../viewlogic/main.th.xml relative path will be resolved, normally - * resulting in the /WEB-INF/viewlogic/main.th.xml resource. + * However this can be modified by specifying different {@code prefix} and {@code suffix} values so that, if a + * {@code prefix} with value {@code "../logic/"} is specified, for a template resource + * {@code /WEB-INF/templates/main.html}, the {@code ../viewlogic/main.th.xml} relative path will be resolved, normally + * resulting in the {@code /WEB-INF/viewlogic/main.th.xml} resource. *

    *

    * This class is thread-safe. diff --git a/src/main/java/org/thymeleaf/templateresolver/AbstractConfigurableTemplateResolver.java b/src/main/java/org/thymeleaf/templateresolver/AbstractConfigurableTemplateResolver.java index 4dfb92910..e9153ab69 100755 --- a/src/main/java/org/thymeleaf/templateresolver/AbstractConfigurableTemplateResolver.java +++ b/src/main/java/org/thymeleaf/templateresolver/AbstractConfigurableTemplateResolver.java @@ -150,9 +150,9 @@ public final void setPrefix(final String prefix) { *

    *

    * Note that this suffix may not be applied to the template name if the template name - * already ends in a known file name suffix: .html, .htm, .xhtml, - * .xml, .js, .json, - * .css, .rss, .atom, .txt. If this behaviour needs to be overridden so + * already ends in a known file name suffix: {@code .html}, {@code .htm}, {@code .xhtml}, + * {@code .xml}, {@code .js}, {@code .json}, + * {@code .css}, {@code .rss}, {@code .atom}, {@code .txt}. If this behaviour needs to be overridden so * that suffix is always applied, the {@link #setForceSuffix(boolean)} will need to be set. *

    * @@ -170,9 +170,9 @@ public final String getSuffix() { *

    *

    * Note that this suffix may not be applied to the template name if the template name - * already ends in a known file name suffix: .html, .htm, .xhtml, - * .xml, .js, .json, - * .css, .rss, .atom, .txt. If this behaviour needs to be overridden so + * already ends in a known file name suffix: {@code .html}, {@code .htm}, {@code .xhtml}, + * {@code .xml}, {@code .js}, {@code .json}, + * {@code .css}, {@code .rss}, {@code .atom}, {@code .txt}. If this behaviour needs to be overridden so * that suffix is always applied, the {@link #setForceSuffix(boolean)} will need to be set. *

    * @@ -190,11 +190,11 @@ public final void setSuffix(final String suffix) { *

    *

    * When forced, suffix will be appended to the template name even if the template - * name ends in a known suffix: .html, .htm, .xhtml, - * .xml, .js, .json, - * .css, .rss, .atom, .txt. + * name ends in a known suffix: {@code .html}, {@code .htm}, {@code .xhtml}, + * {@code .xml}, {@code .js}, {@code .json}, + * {@code .css}, {@code .rss}, {@code .atom}, {@code .txt}. *

    - *

    Default value is false

    . + *

    Default value is {@code false}

    . * * @return whether the suffix will be forced or not. * @since 3.0.6 @@ -211,11 +211,11 @@ public final boolean getForceSuffix() { *

    *

    * When forced, suffix will be appended to the template name even if the template - * name ends in a known suffix: .html, .htm, .xhtml, - * .xml, .js, .json, - * .css, .rss, .atom, .txt. + * name ends in a known suffix: {@code .html}, {@code .htm}, {@code .xhtml}, + * {@code .xml}, {@code .js}, {@code .json}, + * {@code .css}, {@code .rss}, {@code .atom}, {@code .txt}. *

    - *

    Default value is false

    . + *

    Default value is {@code false}

    . * * @param forceSuffix whether the suffix should be forced or not. * @since 3.0.6 @@ -262,9 +262,9 @@ public final void setCharacterEncoding(final String characterEncoding) { *

    *

    * Note that this template mode also may not be applied if the template resource name - * ends in a known file name suffix: .html, .htm, .xhtml, - * .xml, .js, .json, - * .css, .rss, .atom, .txt. If this behaviour needs to be overridden so + * ends in a known file name suffix: {@code .html}, {@code .htm}, {@code .xhtml}, + * {@code .xml}, {@code .js}, {@code .json}, + * {@code .css}, {@code .rss}, {@code .atom}, {@code .txt}. If this behaviour needs to be overridden so * that template name is always applied, the {@link #setForceTemplateMode(boolean)} will need to be set. *

    * @@ -286,9 +286,9 @@ public final TemplateMode getTemplateMode() { *

    *

    * Note that this template mode also may not be applied if the template resource name - * ends in a known file name suffix: .html, .htm, .xhtml, - * .xml, .js, .json, - * .css, .rss, .atom, .txt. If this behaviour needs to be overridden so + * ends in a known file name suffix: {@code .html}, {@code .htm}, {@code .xhtml}, + * {@code .xml}, {@code .js}, {@code .json}, + * {@code .css}, {@code .rss}, {@code .atom}, {@code .txt}. If this behaviour needs to be overridden so * that template name is always applied, the {@link #setForceTemplateMode(boolean)} will need to be set. *

    * @@ -315,9 +315,9 @@ public final void setTemplateMode(final TemplateMode templateMode) { *

    *

    * Note that this template mode also may not be applied if the template resource name - * ends in a known file name suffix: .html, .htm, .xhtml, - * .xml, .js, .json, - * .css, .rss, .atom, .txt. If this behaviour needs to be overridden so + * ends in a known file name suffix: {@code .html}, {@code .htm}, {@code .xhtml}, + * {@code .xml}, {@code .js}, {@code .json}, + * {@code .css}, {@code .rss}, {@code .atom}, {@code .txt}. If this behaviour needs to be overridden so * that template name is always applied, the {@link #setForceTemplateMode(boolean)} will need to be set. *

    * @@ -340,11 +340,11 @@ public final void setTemplateMode(final String templateMode) { *

    * When forced, the configured template mode ({@link #setTemplateMode(TemplateMode)} will * be applied even if the template resource name ends in a known suffix: - * .html, .htm, .xhtml, - * .xml, .js, .json, - * .css, .rss, .atom, .txt. + * {@code .html}, {@code .htm}, {@code .xhtml}, + * {@code .xml}, {@code .js}, {@code .json}, + * {@code .css}, {@code .rss}, {@code .atom}, {@code .txt}. *

    - *

    Default value is false

    . + *

    Default value is {@code false}

    . * * @return whether the suffix will be forced or not. * @since 3.0.6 @@ -362,11 +362,11 @@ public final boolean getForceTemplateMode() { *

    * When forced, the configured template mode ({@link #setTemplateMode(TemplateMode)} will * be applied even if the template resource name ends in a known suffix: - * .html, .htm, .xhtml, - * .xml, .js, .json, - * .css, .rss, .atom, .txt. + * {@code .html}, {@code .htm}, {@code .xhtml}, + * {@code .xml}, {@code .js}, {@code .json}, + * {@code .css}, {@code .rss}, {@code .atom}, {@code .txt}. *

    - *

    Default value is false

    . + *

    Default value is {@code false}

    . * * @param forceTemplateMode whether the configured template mode should be forced or not. * @since 3.0.6 diff --git a/src/main/java/org/thymeleaf/templateresolver/AbstractTemplateResolver.java b/src/main/java/org/thymeleaf/templateresolver/AbstractTemplateResolver.java index 47d855d63..11885ff86 100755 --- a/src/main/java/org/thymeleaf/templateresolver/AbstractTemplateResolver.java +++ b/src/main/java/org/thymeleaf/templateresolver/AbstractTemplateResolver.java @@ -200,11 +200,11 @@ public void setResolvablePatterns(final Set resolvablePatterns) { * Returns whether template resources will be checked for existence before being returned or not. *

    *

    - * Default value is FALSE. + * Default value is {@code FALSE}. *

    *

    * Checking resources for existence will make the template resolver execute {@link ITemplateResource#exists()} - * for each resolved resource before returning a {@link TemplateResolution}, returning null if the + * for each resolved resource before returning a {@link TemplateResolution}, returning {@code null} if the * resource does not exist. *

    *

    @@ -217,10 +217,10 @@ public void setResolvablePatterns(final Set resolvablePatterns) { *

    *

    * If this existence check is enabled and a resource is determined to not exist, - * {@link ITemplateResolver#resolveTemplate(IEngineConfiguration, String, String, Map)} will return null. + * {@link ITemplateResolver#resolveTemplate(IEngineConfiguration, String, String, Map)} will return {@code null}. *

    * - * @return true if resource existence will be checked, false if not + * @return {@code true} if resource existence will be checked, {@code false} if not * * @since 3.0.0 * @@ -235,11 +235,11 @@ public final boolean getCheckExistence() { * Sets whether template resources will be checked for existence before being returned or not. *

    *

    - * Default value is FALSE. + * Default value is {@code FALSE}. *

    *

    * Checking resources for existence will make the template resolver execute {@link ITemplateResource#exists()} - * for each resolved resource before returning a {@link TemplateResolution}, returning null if the + * for each resolved resource before returning a {@link TemplateResolution}, returning {@code null} if the * resource does not exist. *

    *

    @@ -252,10 +252,10 @@ public final boolean getCheckExistence() { *

    *

    * If this existence check is enabled and a resource is determined to not exist, - * {@link ITemplateResolver#resolveTemplate(IEngineConfiguration, String, String, Map)} will return null. + * {@link ITemplateResolver#resolveTemplate(IEngineConfiguration, String, String, Map)} will return {@code null}. *

    * - * @param checkExistence true if resource existence should be checked, false if not + * @param checkExistence {@code true} if resource existence should be checked, {@code false} if not * * @since 3.0.0 * @@ -278,8 +278,8 @@ public void setCheckExistence(final boolean checkExistence) { * interface. *

    *

    - * Note this flag can only be true for the {@link TemplateMode#HTML} and {@link TemplateMode#XML} - * template modes. Also, note that setting this flag to true does not mean that a resource with + * Note this flag can only be {@code true} for the {@link TemplateMode#HTML} and {@link TemplateMode#XML} + * template modes. Also, note that setting this flag to {@code true} does not mean that a resource with * decoupled logic must exist for the resolved template, only that it can exist. *

    *

    @@ -288,10 +288,10 @@ public void setCheckExistence(final boolean checkExistence) { * for non-cacheable templates, and completely removes any overhead for cached templates. *

    *

    - * Default value is FALSE. + * Default value is {@code FALSE}. *

    * - * @return true if decoupled logic resources should be checked, false if not. + * @return {@code true} if decoupled logic resources should be checked, {@code false} if not. * * @since 3.0.0 * @@ -313,8 +313,8 @@ public final boolean getUseDecoupledLogic() { * interface. *

    *

    - * Note this flag can only be true for the {@link TemplateMode#HTML} and {@link TemplateMode#XML} - * template modes. Also, note that setting this flag to true does not mean that a resource with + * Note this flag can only be {@code true} for the {@link TemplateMode#HTML} and {@link TemplateMode#XML} + * template modes. Also, note that setting this flag to {@code true} does not mean that a resource with * decoupled logic must exist for the resolved template, only that it can exist and therefore it should be * checked. *

    @@ -324,10 +324,10 @@ public final boolean getUseDecoupledLogic() { * for non-cacheable templates, and completely removes any overhead for cached templates. *

    *

    - * Default value is FALSE. + * Default value is {@code FALSE}. *

    * - * @param useDecoupledLogic true if resource existence should be checked, false if not + * @param useDecoupledLogic {@code true} if resource existence should be checked, {@code false} if not * * @since 3.0.0 * diff --git a/src/main/java/org/thymeleaf/templateresolver/ITemplateResolver.java b/src/main/java/org/thymeleaf/templateresolver/ITemplateResolver.java index f10daa9f9..84da6c3ed 100755 --- a/src/main/java/org/thymeleaf/templateresolver/ITemplateResolver.java +++ b/src/main/java/org/thymeleaf/templateresolver/ITemplateResolver.java @@ -118,7 +118,7 @@ public interface ITemplateResolver { * return a {@link TemplateResolution} object. *

    *

    - * The ownerTemplate, which might be null, will be specified when the template + * The {@code ownerTemplate}, which might be null, will be specified when the template * is resolved in order to be used as a fragent to be inserted into a higher level * template (the owner). Most template resolver implementations will simply ignore * this argument, but others might change their resolution results depending on the diff --git a/src/main/java/org/thymeleaf/templateresolver/StringTemplateResolver.java b/src/main/java/org/thymeleaf/templateresolver/StringTemplateResolver.java index 8f00b08e1..13595decf 100755 --- a/src/main/java/org/thymeleaf/templateresolver/StringTemplateResolver.java +++ b/src/main/java/org/thymeleaf/templateresolver/StringTemplateResolver.java @@ -38,12 +38,12 @@ * and creates {@link StringTemplateResource} instances for template resources. *

    *

    - * This template resolvers will consider the template being resolved as the template itself, + * This template resolvers will consider the {@code template} being resolved as the template itself, * this is, its contents. No external file or resource will be therefore accessed. *

    *

    * This template resolver will consider its resolved templates non-cacheable by default, - * given its nature of being used for resolving arbitrary String objects. + * given its nature of being used for resolving arbitrary {@code String} objects. *

    *

    * Also, the {@link TemplateMode#HTML} template mode will be used by default. diff --git a/src/main/java/org/thymeleaf/templateresolver/TemplateResolution.java b/src/main/java/org/thymeleaf/templateresolver/TemplateResolution.java index 3300b8661..c711d4597 100755 --- a/src/main/java/org/thymeleaf/templateresolver/TemplateResolution.java +++ b/src/main/java/org/thymeleaf/templateresolver/TemplateResolution.java @@ -99,7 +99,7 @@ public TemplateResolution( * {@link org.thymeleaf.templateresolver.ITemplateResolver}. *

    *

    - * Note that, even if this resource object will never be null, the existence of the + * Note that, even if this resource object will never be {@code null}, the existence of the * resource object does not necessarily imply the existence of the resource itself unless * the template resolver was configured for calling {@link ITemplateResource#exists()} upon * template resolution. @@ -135,11 +135,11 @@ public TemplateMode getTemplateMode() { * been already verified to actually exist by the template resolver during resolution. *

    *

    - * This allows avoiding further checks in case the resource.exists() execution is + * This allows avoiding further checks in case the {@code resource.exists()} execution is * costly. *

    *

    - * Note a false here does not mean the resource does not exist, but simply that + * Note a {@code false} here does not mean the resource does not exist, but simply that * its existence was not verified (true) during resolution. *

    * @@ -156,7 +156,7 @@ public boolean isTemplateResourceExistenceVerified() { * for this template during parsing. *

    *

    - * Note a true here does not mean that a decoupled logic resource has to necessarily exist for this + * Note a {@code true} here does not mean that a decoupled logic resource has to necessarily exist for this * template, only that its existence should be checked and used if it exists. *

    * diff --git a/src/main/java/org/thymeleaf/templateresource/ITemplateResource.java b/src/main/java/org/thymeleaf/templateresource/ITemplateResource.java index 0cc9397b1..98347f008 100644 --- a/src/main/java/org/thymeleaf/templateresource/ITemplateResource.java +++ b/src/main/java/org/thymeleaf/templateresource/ITemplateResource.java @@ -65,14 +65,14 @@ public interface ITemplateResource { /** *

    - * Returns a String describing the resource. + * Returns a {@code String} describing the resource. *

    *

    * Note this should not be taken for a valid resource name, as depending on the implementation * it could be too verbose/descriptive or not unique enough to be used for identification purposes. *

    * - * @return the resource description. Should never return null. + * @return the resource description. Should never return {@code null}. */ public String getDescription(); @@ -86,12 +86,12 @@ public interface ITemplateResource { * the deepest level of the resource path. *

    *

    - * For example, a file resource located at /home/user/template/main.html should return - * main as its base name, so that names like main.properties, - * main.th.xml or similar can be derived, and afterwards resolved using {@link #relative(String)}. + * For example, a file resource located at {@code /home/user/template/main.html} should return + * {@code main} as its base name, so that names like {@code main.properties}, + * {@code main.th.xml} or similar can be derived, and afterwards resolved using {@link #relative(String)}. *

    * - * @return the base name, or null if it cannot be computed for the specific type of resource. + * @return the base name, or {@code null} if it cannot be computed for the specific type of resource. */ public String getBaseName(); @@ -109,10 +109,10 @@ public interface ITemplateResource { * This mechanism will be used by Template Resolvers extending from * {@link org.thymeleaf.templateresolver.AbstractTemplateResolver} for checking real resource existence * if the {@link org.thymeleaf.templateresolver.AbstractTemplateResolver#setCheckExistence(boolean)} flag - * is set to true. + * is set to {@code true}. *

    * - * @return true if the resource exists, false if not. + * @return {@code true} if the resource exists, {@code false} if not. */ public boolean exists(); @@ -129,7 +129,7 @@ public interface ITemplateResource { * Note this readers should be closed after being fully consumed, just like any other resources. *

    * - * @return a {@link Reader} on the template contents. Should never return null. + * @return a {@link Reader} on the template contents. Should never return {@code null}. * @throws IOException if an input/output exception happens or if the resource does not exist (e.g. * {@link java.io.FileNotFoundException}). */ @@ -146,7 +146,7 @@ public interface ITemplateResource { *

    * * @param relativeLocation the location of the resource we want to obtain, relative to the current one. Required. - * @return the relative resource. Should never return null. + * @return the relative resource. Should never return {@code null}. */ public ITemplateResource relative(final String relativeLocation); diff --git a/src/main/java/org/thymeleaf/templateresource/ServletContextTemplateResource.java b/src/main/java/org/thymeleaf/templateresource/ServletContextTemplateResource.java index e799b147d..5b9b44ac4 100644 --- a/src/main/java/org/thymeleaf/templateresource/ServletContextTemplateResource.java +++ b/src/main/java/org/thymeleaf/templateresource/ServletContextTemplateResource.java @@ -37,7 +37,7 @@ *

    * Implementation of {@link ITemplateResource} accessible from the {@link ServletContext} in a web application. * The paths of these resources start at the web application root, and are normally stored inside - * /WEB-INF. + * {@code /WEB-INF}. *

    *

    * Objects of this class are usually created by {@link org.thymeleaf.templateresolver.ServletContextTemplateResolver}. diff --git a/src/main/java/org/thymeleaf/templateresource/StringTemplateResource.java b/src/main/java/org/thymeleaf/templateresource/StringTemplateResource.java index 5dd5d5807..312197285 100644 --- a/src/main/java/org/thymeleaf/templateresource/StringTemplateResource.java +++ b/src/main/java/org/thymeleaf/templateresource/StringTemplateResource.java @@ -29,7 +29,7 @@ /** *

    * Implementation of {@link ITemplateResource} that represents a template completely contained in memory inside - * a String object. + * a {@code String} object. *

    *

    * Objects of this class are usually created by {@link org.thymeleaf.templateresolver.StringTemplateResolver}. diff --git a/src/main/java/org/thymeleaf/util/ClassLoaderUtils.java b/src/main/java/org/thymeleaf/util/ClassLoaderUtils.java index 88b417112..fdbc51d8b 100755 --- a/src/main/java/org/thymeleaf/util/ClassLoaderUtils.java +++ b/src/main/java/org/thymeleaf/util/ClassLoaderUtils.java @@ -90,11 +90,11 @@ public static ClassLoader getClassLoader(final Class clazz) { *

    * First the context class loader will be used. If this class loader is not * able to load the class, then the class class loader - * (ClassLoaderUtils.class.getClassLoader()) will be used if it is different from + * ({@code ClassLoaderUtils.class.getClassLoader()}) will be used if it is different from * the thread context one. Last, the System class loader will be tried. *

    *

    - * This method does never return null. + * This method does never return {@code null}. *

    * * @param className the name of the class to be obtained. @@ -166,15 +166,15 @@ public static Class loadClass(final String className) throws ClassNotFoundExc /** *

    - * Try to obtain a class by name, returning null if not found. + * Try to obtain a class by name, returning {@code null} if not found. *

    *

    - * This method works very similarly to {@link #loadClass(String)} but will just return null + * This method works very similarly to {@link #loadClass(String)} but will just return {@code null} * if the class is not found by the sequence of class loaders being tried. *

    * * @param className the name of the class to be obtained. - * @return the found class, or null if it could not be found. + * @return the found class, or {@code null} if it could not be found. * * @since 3.0.3 * @@ -194,12 +194,12 @@ public static Class findClass(final String className) { * Checks whether a class is present at the application's class path. *

    *

    - * This method works very similarly to {@link #findClass(String)} but will just return true - * or false depending on whether the class could be found or not. + * This method works very similarly to {@link #findClass(String)} but will just return {@code true} + * or {@code false} depending on whether the class could be found or not. *

    * * @param className the name of the class to be checked. - * @return true if the class was found (by any class loader), false if not. + * @return {@code true} if the class was found (by any class loader), {@code false} if not. * * @since 3.0.3 * @@ -213,17 +213,17 @@ public static boolean isClassPresent(final String className) { /** *

    - * Try to obtain a resource by name, returning null if it could not be located. + * Try to obtain a resource by name, returning {@code null} if it could not be located. *

    *

    * First the context class loader will be used. If this class loader is not * able to locate the resource, then the class class loader - * (ClassLoaderUtils.class.getClassLoader()) will be used if it is different from + * ({@code ClassLoaderUtils.class.getClassLoader()}) will be used if it is different from * the thread context one. Last, the System class loader will be tried. *

    * * @param resourceName the name of the resource to be obtained. - * @return the found resource, or null if it could not be located. + * @return the found resource, or {@code null} if it could not be located. * * @since 3.0.3 * @@ -281,12 +281,12 @@ public static URL findResource(final String resourceName) { * Checks whether a resource is present at the application's class path. *

    *

    - * This method works very similarly to {@link #findResource(String)} but will just return true - * or false depending on whether the resource could be located or not. + * This method works very similarly to {@link #findResource(String)} but will just return {@code true} + * or {@code false} depending on whether the resource could be located or not. *

    * * @param resourceName the name of the resource to be checked. - * @return true if the class was located (by any class loader), false if not. + * @return {@code true} if the class was located (by any class loader), {@code false} if not. * * @since 3.0.3 * @@ -305,11 +305,11 @@ public static boolean isResourcePresent(final String resourceName) { *

    * First the context class loader will be used. If this class loader is not * able to locate the resource, then the class class loader - * (ClassLoaderUtils.class.getClassLoader()) will be used if it is different from + * ({@code ClassLoaderUtils.class.getClassLoader()}) will be used if it is different from * the thread context one. Last, the System class loader will be tried. *

    *

    - * This method does never return null. + * This method does never return {@code null}. *

    * * @param resourceName the name of the resource to be obtained. @@ -334,15 +334,15 @@ public static InputStream loadResourceAsStream(final String resourceName) throws /** *

    - * Try to obtain a resource by name, returning null if it could not be located. + * Try to obtain a resource by name, returning {@code null} if it could not be located. *

    *

    - * This method works very similarly to {@link #loadResourceAsStream(String)} but will just return null + * This method works very similarly to {@link #loadResourceAsStream(String)} but will just return {@code null} * if the resource cannot be located by the sequence of class loaders being tried. *

    * * @param resourceName the name of the resource to be obtained. - * @return an input stream on the resource, or null if it could not be located. + * @return an input stream on the resource, or {@code null} if it could not be located. * * @since 3.0.3 * diff --git a/src/main/java/org/thymeleaf/util/ExpressionUtils.java b/src/main/java/org/thymeleaf/util/ExpressionUtils.java new file mode 100644 index 000000000..35cf8f8ac --- /dev/null +++ b/src/main/java/org/thymeleaf/util/ExpressionUtils.java @@ -0,0 +1,72 @@ +/* + * ============================================================================= + * + * Copyright (c) 2011-2022, The THYMELEAF team (http://www.thymeleaf.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ============================================================================= + */ + +package org.thymeleaf.util; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public final class ExpressionUtils { + + private static final Set BLOCKED_CLASS_NAME_PREFIXES = + new HashSet(Arrays.asList( + "java.lang.Runtime", "java.lang.Thread", "java.lang.Class", "java.lang.ClassLoader", + "java.lang.Runnable", "java.lang.reflect.Executable", + "java.util.concurrent.Future", "java.util.concurrent.FutureTask", + "java.util.concurrent.RunnableFuture", "java.util.concurrent.ListenableFuture", + "java.util.concurrent.Executor", + "java.sql.DriverManager")); + + + + public static boolean isTypeAllowed(final String typeName) { + Validate.notNull(typeName, "Type name cannot be null"); + final int i0 = typeName.indexOf('.'); + if (i0 >= 0) { + final String package0 = typeName.substring(0, i0); + if ("java".equals(package0)) { // This is the only prefix that might be blocked + for (final String prefix : BLOCKED_CLASS_NAME_PREFIXES) { + if (typeName.startsWith(prefix)) { + return false; + } + } + } + } + // This is safe assuming we have disabled the capability of calling "java.lang" classes without package + return true; + } + + + + public static List getBlockedClasses() { + final List blocked = new ArrayList(); + blocked.addAll(BLOCKED_CLASS_NAME_PREFIXES); + return blocked; + } + + + private ExpressionUtils() { + super(); + } + +} diff --git a/src/main/java/org/thymeleaf/util/IWritableCharSequence.java b/src/main/java/org/thymeleaf/util/IWritableCharSequence.java index 0798f7708..4713aa7a8 100644 --- a/src/main/java/org/thymeleaf/util/IWritableCharSequence.java +++ b/src/main/java/org/thymeleaf/util/IWritableCharSequence.java @@ -29,8 +29,8 @@ *

    * This will be used by a variety of implementations providing the capability to write text generated by * the engine somehow directly to output (to the output writer, which will correspond to an - * HttpServletResponse#getWriter() writer in most web applications). This avoids the need to generate - * a large number of (possibly large) String object in memory before these values being output. + * {@code HttpServletResponse#getWriter()} writer in most web applications). This avoids the need to generate + * a large number of (possibly large) {@code String} object in memory before these values being output. *

    * * @author Daniel Fernández diff --git a/src/main/java/org/thymeleaf/util/LazyEscapingCharSequence.java b/src/main/java/org/thymeleaf/util/LazyEscapingCharSequence.java index e5ee2c982..b8f59b32d 100644 --- a/src/main/java/org/thymeleaf/util/LazyEscapingCharSequence.java +++ b/src/main/java/org/thymeleaf/util/LazyEscapingCharSequence.java @@ -34,7 +34,7 @@ /** *

    - * Character sequence that performs a lazy escaping of a text, so that it is directly written to a Writer + * Character sequence that performs a lazy escaping of a text, so that it is directly written to a {@code Writer} * output during the escape operation itself. *

    *

    diff --git a/src/main/java/org/thymeleaf/util/NumberUtils.java b/src/main/java/org/thymeleaf/util/NumberUtils.java index 69bbcb4a3..ca98558eb 100755 --- a/src/main/java/org/thymeleaf/util/NumberUtils.java +++ b/src/main/java/org/thymeleaf/util/NumberUtils.java @@ -223,7 +223,7 @@ private static DecimalFormatSymbols computeDecimalFormatSymbols( Validate.notNull(thousandsPointType, "Thousands point type cannot be null"); Validate.notNull(locale, "Locale cannot be null"); - final DecimalFormatSymbols symbols = new DecimalFormatSymbols(Locale.US); + final DecimalFormatSymbols symbols = new DecimalFormatSymbols(locale); switch (decimalPointType) { case POINT : @@ -236,8 +236,7 @@ private static DecimalFormatSymbols computeDecimalFormatSymbols( symbols.setDecimalSeparator(' '); break; case DEFAULT : - final DecimalFormatSymbols dfs = new DecimalFormatSymbols(locale); - symbols.setDecimalSeparator(dfs.getDecimalSeparator()); + // No changes needed to the "symbols" variable defined above break; case NONE : // This should never happen @@ -255,8 +254,7 @@ private static DecimalFormatSymbols computeDecimalFormatSymbols( symbols.setGroupingSeparator(' '); break; case DEFAULT : - final DecimalFormatSymbols dfs = new DecimalFormatSymbols(locale); - symbols.setGroupingSeparator(dfs.getGroupingSeparator()); + // No changes needed to the "symbols" variable defined above break; case NONE : // This should never be shown diff --git a/src/main/java/org/thymeleaf/util/StringUtils.java b/src/main/java/org/thymeleaf/util/StringUtils.java index 09c6b463b..f39b7d5fe 100755 --- a/src/main/java/org/thymeleaf/util/StringUtils.java +++ b/src/main/java/org/thymeleaf/util/StringUtils.java @@ -37,7 +37,7 @@ *

    * This class is used as a basis for the methods offered by * {@link org.thymeleaf.expression.Strings}, which in turn are the - * methods offered by the #strings utility object in variable + * methods offered by the {@code #strings} utility object in variable * expressions. *

    * @@ -55,12 +55,12 @@ public final class StringUtils { /** *

    - * Performs a null-safe toString() operation. + * Performs a null-safe {@code toString()} operation. *

    * * @param target the object on which toString will be executed - * @return the result of calling target.toString() if target is not null, - * null if target is null. + * @return the result of calling {@code target.toString()} if target is not null, + * {@code null} if target is null. * @since 2.0.12 */ public static String toString(final Object target) { @@ -198,7 +198,7 @@ public static String substring(final Object target, final int beginIndex, final * * @param target source of the copy. * @param beginIndex index where the copy start. - * @return part of target, or null if target is null. + * @return part of target, or {@code null} if target is null. * @since 1.1.2 */ public static String substring(final Object target, final int beginIndex) { @@ -551,6 +551,39 @@ public static String trim(final Object target) { } + /** + * Removes all whitespaces and control chars at all positions, and + * transforms to lower case. + * + * @param target the string to be packed + * @return the packed string + * + * @since 3.0.12 + */ + public static String pack(final String target) { + if (target == null) { + return null; + } + final int targetLen = target.length(); + StringBuilder strBuilder = null; + char c; + for (int i = 0; i < targetLen; i++) { + c = target.charAt(i); + if (Character.isWhitespace(c) || c <= ' ') { + if (strBuilder == null) { + strBuilder = new StringBuilder(); + strBuilder.append(target, 0, i); + } + } else { + if (strBuilder != null) { + strBuilder.append(c); + } + } + } + return (strBuilder == null) ? target.toLowerCase() : strBuilder.toString().toLowerCase(); + } + + /** *

    * Convert the first letter of target to uppercase (title-case, in fact). diff --git a/src/main/java/org/thymeleaf/util/TextUtils.java b/src/main/java/org/thymeleaf/util/TextUtils.java index a5503acc5..9e9e9be8b 100644 --- a/src/main/java/org/thymeleaf/util/TextUtils.java +++ b/src/main/java/org/thymeleaf/util/TextUtils.java @@ -22,7 +22,7 @@ /** *

    - * Utility class for char[] operations (mainly matching/comparing) + * Utility class for {@code char[]} operations (mainly matching/comparing) *

    * * @author Daniel Fernández @@ -35,7 +35,7 @@ public final class TextUtils { /** *

    - * Check equality of two CharSequence objects. This is equivalent to {@link java.lang.String#equals(Object)} + * Check equality of two {@code CharSequence} objects. This is equivalent to {@link java.lang.String#equals(Object)} * and {@link java.lang.String#equalsIgnoreCase(String)}. *

    * @@ -68,7 +68,7 @@ public static boolean equals(final boolean caseSensitive, final CharSequence tex /** *

    - * Check equality between a CharSequence and a char[] object. + * Check equality between a {@code CharSequence} and a {@code char[]} object. *

    * * @param caseSensitive whether the comparison must be done in a case-sensitive or case-insensitive way. @@ -83,7 +83,7 @@ public static boolean equals(final boolean caseSensitive, final CharSequence tex /** *

    - * Check equality between two char[] objects. + * Check equality between two {@code char[]} objects. *

    * * @param caseSensitive whether the comparison must be done in a case-sensitive or case-insensitive way. @@ -98,7 +98,7 @@ public static boolean equals(final boolean caseSensitive, final char[] text1, fi /** *

    - * Check equality between two char[] objects, specifying (offset,len) pairs for limiting + * Check equality between two {@code char[]} objects, specifying (offset,len) pairs for limiting * the fragments to be checked. *

    * @@ -173,7 +173,7 @@ public static boolean equals( /** *

    - * Check equality between a CharSequence and a char[] object, specifying (offset,len) pairs + * Check equality between a {@code CharSequence} and a {@code char[]} object, specifying (offset,len) pairs * for limiting the fragments to be checked. *

    * @@ -244,7 +244,7 @@ public static boolean equals( /** *

    - * Check equality between two CharSequence objects, specifying (offset,len) pairs + * Check equality between two {@code CharSequence} objects, specifying (offset,len) pairs * for limiting the fragments to be checked. *

    * @@ -1448,8 +1448,8 @@ public static boolean contains( * @param caseSensitive whether the comparison must be done in a case-sensitive or case-insensitive way. * @param text1 the first text to be compared. * @param text2 the second text to be compared. - * @return the value 0 if both texts are equal; a value less than 0 if the first text - * is lexicographically less than the second text; and a value greater than 0 if the + * @return the value {@code 0} if both texts are equal; a value less than {@code 0} if the first text + * is lexicographically less than the second text; and a value greater than {@code 0} if the * first text is lexicographically greater than the second text. */ public static int compareTo(final boolean caseSensitive, final CharSequence text1, final CharSequence text2) { @@ -1492,8 +1492,8 @@ public static int compareTo(final boolean caseSensitive, final CharSequence text * @param caseSensitive whether the comparison must be done in a case-sensitive or case-insensitive way. * @param text1 the first text to be compared. * @param text2 the second text to be compared. - * @return the value 0 if both texts are equal; a value less than 0 if the first text - * is lexicographically less than the second text; and a value greater than 0 if the + * @return the value {@code 0} if both texts are equal; a value less than {@code 0} if the first text + * is lexicographically less than the second text; and a value greater than {@code 0} if the * first text is lexicographically greater than the second text. */ public static int compareTo(final boolean caseSensitive, final CharSequence text1, final char[] text2) { @@ -1523,8 +1523,8 @@ public static int compareTo(final boolean caseSensitive, final CharSequence text * @param caseSensitive whether the comparison must be done in a case-sensitive or case-insensitive way. * @param text1 the first text to be compared. * @param text2 the second text to be compared. - * @return the value 0 if both texts are equal; a value less than 0 if the first text - * is lexicographically less than the second text; and a value greater than 0 if the + * @return the value {@code 0} if both texts are equal; a value less than {@code 0} if the first text + * is lexicographically less than the second text; and a value greater than {@code 0} if the * first text is lexicographically greater than the second text. */ public static int compareTo(final boolean caseSensitive, final char[] text1, final char[] text2) { @@ -1558,8 +1558,8 @@ public static int compareTo(final boolean caseSensitive, final char[] text1, fin * @param text2 the second text to be compared. * @param text2Offset the offset of the second text. * @param text2Len the length of the second text. - * @return the value 0 if both texts are equal; a value less than 0 if the first text - * is lexicographically less than the second text; and a value greater than 0 if the + * @return the value {@code 0} if both texts are equal; a value less than {@code 0} if the first text + * is lexicographically less than the second text; and a value greater than {@code 0} if the * first text is lexicographically greater than the second text. */ public static int compareTo( @@ -1644,8 +1644,8 @@ public static int compareTo( * @param text2 the second text to be compared. * @param text2Offset the offset of the second text. * @param text2Len the length of the second text. - * @return the value 0 if both texts are equal; a value less than 0 if the first text - * is lexicographically less than the second text; and a value greater than 0 if the + * @return the value {@code 0} if both texts are equal; a value less than {@code 0} if the first text + * is lexicographically less than the second text; and a value greater than {@code 0} if the * first text is lexicographically greater than the second text. */ public static int compareTo( @@ -1726,8 +1726,8 @@ public static int compareTo( * @param text2 the second text to be compared. * @param text2Offset the offset of the second text. * @param text2Len the length of the second text. - * @return the value 0 if both texts are equal; a value less than 0 if the first text - * is lexicographically less than the second text; and a value greater than 0 if the + * @return the value {@code 0} if both texts are equal; a value less than {@code 0} if the first text + * is lexicographically less than the second text; and a value greater than {@code 0} if the * first text is lexicographically greater than the second text. */ public static int compareTo( @@ -1792,11 +1792,11 @@ public static int compareTo( /** *

    - * Searches the specified array of texts (values) for the specified text —or a fragment, using an + * Searches the specified array of texts ({@code values}) for the specified text —or a fragment, using an * (offset,len) specification— using the binary search algorithm. *

    *

    - * Note the specified values parameter must be lexicographically ordered. + * Note the specified {@code values} parameter must be lexicographically ordered. *

    * * @param caseSensitive whether the comparison must be done in a case-sensitive or case-insensitive way. @@ -1806,7 +1806,7 @@ public static int compareTo( * @param textOffset the offset of the text to search. * @param textLen the length of the text to search. * @return index of the search key, if it is contained in the values array; otherwise, - * (-(insertion point) - 1). The insertion point is defined as the point at + * {@code (-(insertion point) - 1)}. The insertion point is defined as the point at * which the key would be inserted into the array. Note that this guarantees that the return value will * be >= 0 if and only if the key is found. */ @@ -1824,11 +1824,11 @@ public static int binarySearch( /** *

    - * Searches the specified array of texts (values) for the specified text —or a fragment, using an + * Searches the specified array of texts ({@code values}) for the specified text —or a fragment, using an * (offset,len) specification— using the binary search algorithm. *

    *

    - * Note the specified values parameter must be lexicographically ordered. + * Note the specified {@code values} parameter must be lexicographically ordered. *

    * * @param caseSensitive whether the comparison must be done in a case-sensitive or case-insensitive way. @@ -1838,7 +1838,7 @@ public static int binarySearch( * @param textOffset the offset of the text to search. * @param textLen the length of the text to search. * @return index of the search key, if it is contained in the values array; otherwise, - * (-(insertion point) - 1). The insertion point is defined as the point at + * {@code (-(insertion point) - 1)}. The insertion point is defined as the point at * which the key would be inserted into the array. Note that this guarantees that the return value will * be >= 0 if and only if the key is found. */ @@ -1856,11 +1856,11 @@ public static int binarySearch( /** *

    - * Searches the specified array of texts (values) for the specified text —or a fragment, using an + * Searches the specified array of texts ({@code values}) for the specified text —or a fragment, using an * (offset,len) specification— using the binary search algorithm. *

    *

    - * Note the specified values parameter must be lexicographically ordered. + * Note the specified {@code values} parameter must be lexicographically ordered. *

    * * @param caseSensitive whether the comparison must be done in a case-sensitive or case-insensitive way. @@ -1870,7 +1870,7 @@ public static int binarySearch( * @param textOffset the offset of the text to search. * @param textLen the length of the text to search. * @return index of the search key, if it is contained in the values array; otherwise, - * (-(insertion point) - 1). The insertion point is defined as the point at + * {@code (-(insertion point) - 1)}. The insertion point is defined as the point at * which the key would be inserted into the array. Note that this guarantees that the return value will * be >= 0 if and only if the key is found. */ @@ -1888,11 +1888,11 @@ public static int binarySearch( /** *

    - * Searches the specified array of texts (values) for the specified text —or a fragment, using an + * Searches the specified array of texts ({@code values}) for the specified text —or a fragment, using an * (offset,len) specification— using the binary search algorithm. *

    *

    - * Note the specified values parameter must be lexicographically ordered. + * Note the specified {@code values} parameter must be lexicographically ordered. *

    * * @param caseSensitive whether the comparison must be done in a case-sensitive or case-insensitive way. @@ -1902,7 +1902,7 @@ public static int binarySearch( * @param textOffset the offset of the text to search. * @param textLen the length of the text to search. * @return index of the search key, if it is contained in the values array; otherwise, - * (-(insertion point) - 1). The insertion point is defined as the point at + * {@code (-(insertion point) - 1)}. The insertion point is defined as the point at * which the key would be inserted into the array. Note that this guarantees that the return value will * be >= 0 if and only if the key is found. */ @@ -1920,11 +1920,11 @@ public static int binarySearch( /** *

    - * Searches the specified array of texts (values) for the specified text —or a fragment, using an + * Searches the specified array of texts ({@code values}) for the specified text —or a fragment, using an * (offset,len) specification— using the binary search algorithm. *

    *

    - * Note the specified values parameter must be lexicographically ordered. + * Note the specified {@code values} parameter must be lexicographically ordered. *

    * * @param caseSensitive whether the comparison must be done in a case-sensitive or case-insensitive way. @@ -1937,7 +1937,7 @@ public static int binarySearch( * @param textOffset the offset of the text to search. * @param textLen the length of the text to search. * @return index of the search key, if it is contained in the values array; otherwise, - * (-(insertion point) - 1). The insertion point is defined as the point at + * {@code (-(insertion point) - 1)}. The insertion point is defined as the point at * which the key would be inserted into the array. Note that this guarantees that the return value will * be >= 0 if and only if the key is found. */ @@ -1984,11 +1984,11 @@ public static int binarySearch( /** *

    - * Searches the specified array of texts (values) for the specified text —or a fragment, using an + * Searches the specified array of texts ({@code values}) for the specified text —or a fragment, using an * (offset,len) specification— using the binary search algorithm. *

    *

    - * Note the specified values parameter must be lexicographically ordered. + * Note the specified {@code values} parameter must be lexicographically ordered. *

    * * @param caseSensitive whether the comparison must be done in a case-sensitive or case-insensitive way. @@ -2001,7 +2001,7 @@ public static int binarySearch( * @param textOffset the offset of the text to search. * @param textLen the length of the text to search. * @return index of the search key, if it is contained in the values array; otherwise, - * (-(insertion point) - 1). The insertion point is defined as the point at + * {@code (-(insertion point) - 1)}. The insertion point is defined as the point at * which the key would be inserted into the array. Note that this guarantees that the return value will * be >= 0 if and only if the key is found. */ @@ -2048,11 +2048,11 @@ public static int binarySearch( /** *

    - * Searches the specified array of texts (values) for the specified text —or a fragment, using an + * Searches the specified array of texts ({@code values}) for the specified text —or a fragment, using an * (offset,len) specification— using the binary search algorithm. *

    *

    - * Note the specified values parameter must be lexicographically ordered. + * Note the specified {@code values} parameter must be lexicographically ordered. *

    * * @param caseSensitive whether the comparison must be done in a case-sensitive or case-insensitive way. @@ -2065,7 +2065,7 @@ public static int binarySearch( * @param textOffset the offset of the text to search. * @param textLen the length of the text to search. * @return index of the search key, if it is contained in the values array; otherwise, - * (-(insertion point) - 1). The insertion point is defined as the point at + * {@code (-(insertion point) - 1)}. The insertion point is defined as the point at * which the key would be inserted into the array. Note that this guarantees that the return value will * be >= 0 if and only if the key is found. */ @@ -2112,11 +2112,11 @@ public static int binarySearch( /** *

    - * Searches the specified array of texts (values) for the specified text —or a fragment, using an + * Searches the specified array of texts ({@code values}) for the specified text —or a fragment, using an * (offset,len) specification— using the binary search algorithm. *

    *

    - * Note the specified values parameter must be lexicographically ordered. + * Note the specified {@code values} parameter must be lexicographically ordered. *

    * * @param caseSensitive whether the comparison must be done in a case-sensitive or case-insensitive way. @@ -2129,7 +2129,7 @@ public static int binarySearch( * @param textOffset the offset of the text to search. * @param textLen the length of the text to search. * @return index of the search key, if it is contained in the values array; otherwise, - * (-(insertion point) - 1). The insertion point is defined as the point at + * {@code (-(insertion point) - 1)}. The insertion point is defined as the point at * which the key would be inserted into the array. Note that this guarantees that the return value will * be >= 0 if and only if the key is found. */ diff --git a/src/main/java/org/thymeleaf/util/VersionUtils.java b/src/main/java/org/thymeleaf/util/VersionUtils.java new file mode 100644 index 000000000..0556bb373 --- /dev/null +++ b/src/main/java/org/thymeleaf/util/VersionUtils.java @@ -0,0 +1,280 @@ +/* + * ============================================================================= + * + * Copyright (c) 2011-2018, The THYMELEAF team (http://www.thymeleaf.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ============================================================================= + */ +package org.thymeleaf.util; + + +/** + *

    + * Utility class for processing version numbers. + *

    + * + * @author Daniel Fernández + * + * @since 3.0.12 + * + */ +public final class VersionUtils { + + + public static VersionSpec parseVersion(final String version) { + return parseVersion(version, null); + } + + + public static VersionSpec parseVersion(final String version, final String buildTimestamp) { + + if (version == null || version.trim().length() == 0) { + + // Build an UNKNOWN version + return new VersionSpec(buildTimestamp); + + } else { + + try { + + final String ver = version.trim(); + + final String numVer; + final Character qualifierSeparator; + final String qualifier; + + final int endOfNumericVersionIdx = findEndOfNumericVersion(ver); + if (endOfNumericVersionIdx < 0) { + numVer = ver; + qualifierSeparator = null; + qualifier = null; + } else { + numVer = ver.substring(0, endOfNumericVersionIdx); + final char c = ver.charAt(endOfNumericVersionIdx); + if (Character.isLetter(c)) { + qualifierSeparator = null; + qualifier = ver.substring(endOfNumericVersionIdx); + } else { + qualifierSeparator = Character.valueOf(ver.charAt(endOfNumericVersionIdx)); + qualifier = ver.substring(endOfNumericVersionIdx + 1); + if (qualifier == null || qualifier.trim().length() == 0) { + // Build an UNKNOWN version + return new VersionSpec(buildTimestamp); + } + } + } + + + final int major; + final Integer minor; + final Integer patch; + + final int separator1Idx = numVer.indexOf('.'); + if (separator1Idx < 0) { + major = Integer.parseInt(numVer); + minor = null; + patch = null; + } else { + major = Integer.parseInt(numVer.substring(0, separator1Idx)); + final int separator2Idx = numVer.indexOf('.', separator1Idx + 1); + if (separator2Idx < 0) { + minor = Integer.valueOf(numVer.substring(separator1Idx + 1)); + patch = null; + } else { + minor = Integer.valueOf(numVer.substring(separator1Idx + 1, separator2Idx)); + patch = Integer.valueOf(numVer.substring(separator2Idx + 1)); + } + } + + return new VersionSpec(major, minor, patch, qualifierSeparator, qualifier, buildTimestamp); + + } catch (final Exception e) { + // Build an UNKNOWN version + return new VersionSpec(buildTimestamp); + } + + } + + } + + + private static int findEndOfNumericVersion(final CharSequence sequence) { + final int seqLen = sequence.length(); + char c; + for (int i = 0; i < seqLen; i++) { + c = sequence.charAt(i); + if (c != '.' && !Character.isDigit(c)) { + if (i > 1 && sequence.charAt(i - 1) == '.') { + return i - 1; + } + return i; + } + } + return -1; + } + + + + + private VersionUtils() { + super(); + } + + + + public static final class VersionSpec { + + private static final String UNKNOWN_VERSION = "UNKNOWN"; + + private boolean unknown; + + private int major; + private int minor; + private int patch; + private String qualifier; + private String buildTimestamp; + + private String versionCore; + private String version; + private String fullVersion; + + + + // UNKNOWN version + private VersionSpec(final String buildTimestamp) { + + super(); + + this.unknown = true; + + this.major = 0; + this.minor = 0; + this.patch = 0; + this.qualifier = null; + this.buildTimestamp = buildTimestamp; + + this.versionCore = UNKNOWN_VERSION; + this.version = this.versionCore; + + // Version might be UNKNOWN but still full version specify a build timestamp + this.fullVersion = + (this.buildTimestamp != null) ? + String.format("%s (%s)", this.version, this.buildTimestamp) : this.version; + + } + + + private VersionSpec( + final int major, final Integer minor, final Integer patch, + final Character qualifierSeparator, final String qualifier, + final String buildTimestamp) { + + super(); + + Validate.isTrue(major >= 0, "Major version must be >= 0"); + Validate.isTrue(minor == null || minor.intValue() >= 0, "Minor version must be >= 0"); + Validate.isTrue(patch == null || patch.intValue() >= 0, "Patch version must be >= 0"); + Validate.isTrue(patch == null || minor != null, "Patch version present without minor"); + + this.unknown = false; + + this.major = major; + this.minor = (minor != null) ? minor.intValue() : 0; + this.patch = (patch != null) ? patch.intValue() : 0; + this.qualifier = qualifier; + this.buildTimestamp = buildTimestamp; + + this.versionCore = + (patch != null) ? + String.format("%d.%d.%d", Integer.valueOf(major), minor, patch) : + (minor != null) ? + String.format("%d.%d", Integer.valueOf(major), minor) : String.valueOf(major); + + this.version = + (qualifier == null) ? + this.versionCore : + (qualifierSeparator != null) ? + String.format("%s%c%s", this.versionCore, qualifierSeparator, qualifier) : + String.format("%s%s", this.versionCore, qualifier); + + // Version might be UNKNOWN but still full version specify a build timestamp + this.fullVersion = + (buildTimestamp != null) ? + String.format("%s (%s)", this.version, this.buildTimestamp) : this.version; + + } + + public boolean isUnknown() { + return this.unknown; + } + + public int getMajor() { + return this.major; + } + + public int getMinor() { + return this.minor; + } + + public int getPatch() { + return this.patch; + } + + public boolean hasQualifier() { + return this.qualifier != null; + } + + public String getQualifier() { + return this.qualifier; + } + + public String getVersionCore() { + return this.versionCore; + } + + public String getVersion() { + return this.version; + } + + public boolean hasBuildTimestamp() { + return this.buildTimestamp != null; + } + + public String getBuildTimestamp() { + return this.buildTimestamp; + } + + public String getFullVersion() { + return this.fullVersion; + } + + public boolean isAtLeast(final int major) { + return isAtLeast(major, 0); + } + + public boolean isAtLeast(final int major, final int minor) { + return isAtLeast(major, minor, 0); + } + + public boolean isAtLeast(final int major, final int minor, final int patch) { + return this.major > major || + (this.major == major && this.minor > minor) || + (this.major == major && this.minor == minor && this.patch >= patch); + } + + } + + +} \ No newline at end of file