22

For debugging purposes I would like to list all model attributes available to my thymeleaf template while it is rendering.

Something like:

<table>
    <tr th:each="model : ${*}">
        <td th:text="${model}"></td>
    </tr>
</table>

But obviously that's nonsense, and I get a well-deserved error. (org.springframework.expression.spel.SpelParseException: EL1070E:(pos 0): Problem parsing left operand)

Is there a way of outputting such debug information? I'd settle even for some logging output.

Or, does Thymeleaf provide something similar to Struts 2's struts.devMode where it added a debug section at the bottom of the page listing all available properties?

Roman C
  • 49,761
  • 33
  • 66
  • 176
David Lavender
  • 8,021
  • 3
  • 35
  • 55

4 Answers4

46

Try this:

<table>
    <tr th:each="var : ${#vars}">
        <td th:text="${var.key}"></td>
        <td th:text="${var.value}"></td>
    </tr>
</table>
Mahozad
  • 18,032
  • 13
  • 118
  • 133
the4dK
  • 632
  • 6
  • 13
43

The accepted answer does not seem to work for Thymeleaf 3; here's an update. Please note that I'm using Spring; this might not work for non-Spring apps.

<table>
    <tr th:each="var : ${#vars.getVariableNames()}">
        <td th:text="${var}"></td>
        <td th:text="${#vars.getVariable(var)}"></td>
    </tr>
    <!-- 
        Adding these manually because they are considered special.
        see https://github.com/thymeleaf/thymeleaf/blob/thymeleaf-3.0.3.RELEASE/src/main/java/org/thymeleaf/context/WebEngineContext.java#L199
    -->
    <tr>
        <td>param</td>
        <td th:text="${#vars.getVariable('param')}"></td>
    </tr>
    <tr>
        <td>session</td>
        <td th:text="${#vars.getVariable('session')}"></td>
    </tr>
    <tr>
        <td>application</td>
        <td th:text="${#vars.getVariable('application')}"></td>
    </tr>
</table>

That said, what I've done is created a standalone Bean that makes things a bit prettier and dumps to logs instead of to HTML:

@Component
public class ThymeleafDumper {

    private Logger log = LoggerFactory.getLogger(ThymeleafDumper.class);

    public void dumpToLog(WebEngineContext ctx) {
        log.debug("Thymeleaf context: {}", formatThisUpNicely(ctx));
    }

    // ... etc
}

Where formatThisUpNicely can use ctx.getVariableNames(), put the results into a SortedMap, export to json, whatever. Don't forget those three 'special' variables!

Then expose an instance of it as a @ModelAttribute in a Controller or a ControllerAdvice:

@ControllerAdvice
public class SomeControllerAdvice {

    @Autowired
    private ThymeleafDumper thymeleafDumper;

    @ModelAttribute("dumper")
    public ThymeleafDumper dumper() {
        return this.thymeleafDumper;
    }
}

Then in my template run:

<div th:text="${dumper.dumpToLog(#vars)}"/>
djm.im
  • 3,295
  • 4
  • 30
  • 45
Roy Truelove
  • 22,016
  • 18
  • 111
  • 153
  • Roy, I would have never, never, never figured out – Richard Bradley Smith Feb 21 '20 at 00:53
  • 1
    Roy, I would have never, never, never figured out mav.addObject(Company.getCompany()) would become "string" displaying Tear Drop on the view even though it told me right here: In CompanyController.java mav model is {string=Tear Drop}. I can't wait to define some more fields. I bet they will be "string1...", at least until I figure out what I am supposed to be doing. Thank you so much 3 years later! ==> comments can only be edited for so many minutes. I had better learn to type faster. – Richard Bradley Smith Feb 21 '20 at 01:01
5

these are all the logging available configurations :

log4j.logger.org.thymeleaf=DEBUG
log4j.logger.org.thymeleaf.TemplateEngine.CONFIG=DEBUG
log4j.logger.org.thymeleaf.TemplateEngine.TIMER=DEBUG
log4j.logger.org.thymeleaf.TemplateEngine.cache.TEMPLATE_CACHE=DEBUG
log4j.logger.org.thymeleaf.TemplateEngine.cache.FRAGMENT_CACHE=DEBUG
log4j.logger.org.thymeleaf.TemplateEngine.cache.MESSAGE_CACHE=DEBUG
log4j.logger.org.thymeleaf.TemplateEngine.cache.EXPRESSION_CACHE=DEBUG

these will log all the thymeleaf actions. I hope it is helpful.

Hossein
  • 1,151
  • 9
  • 19
2

Thymeleaf 3.0: To put it short, try the following:

<table>
  <tr th:each="var : ${param.keySet()}">
    <td th:text="${var}"></td>
    <td th:text="${param.get(var)}"></td>
  </tr>
</table>

When a @Controller returns some value stored in a Spring Model, the values are actually stored as request parameters, which is accessible using: request.getParameter("paramName"); Thymeleaf provides a similar functionality: "Web context namespaces for request/session attributes", the syntax is as stated.

The Thymeleaf built-in ${param} kewords returns an WebRequestParamsVariablesMap extends VariablesMap<String,String[]> object, whose keySet() method returns a String[], which contains those variable names within a httprequest.

schen
  • 107
  • 1
  • 2
  • 7