0

I am using Spring Boot and Thymeleaf to create a single landing page for my application. For this, I need to render a List of Host objects that all contain a Container. Here is the relevant code:

public class Container {
    private String name;
    private String baseUrl;
    private String status;

    public Container(String name, String baseUrl, String status) {
        this.name = name;
        this.baseUrl = baseUrl;
        this.status = status;
    }

    public String getName() { return name; }
    public String getBaseUrl() { return baseUrl; }
    public String getStatus() { return status; }
}

public class Host {
    private HashMap<String, Container> containers;
    ....
    public List<Container> getContainers() {
         return containers.values();
    }
}

@RequestMapping("/")
public class IndexController {
      @RequestMapping("/")
      public String getIndex(Model model) {
          model.addAttribute("hosts", hostRepository.getAllServers());
          return "index";
      }
}

Now I want to iterate over all servers and display the information about each Container in a table. My Thymeleaf template looks like this:

<div class="panel panel-default" th:each="host : ${hosts}">
            <div class="panel-heading">
                <b th:text="${host.name}">Host X</b>
                <div class="panel-body">
                    <table class="table">
                        <thead>
                            <tr>
                                <th>Name</th>
                                <th>URL</th>
                                <th>Status</th>
                            </tr>
                        </thead>
                        <tbody>
                            <tr th:each="container : ${host.getContainers()}">
           <!-- HERE IS THE PROBLEM -->
                                <td th:text="${container.name}">Service1</td>
                                <td th:text="${container.baseUrl}">domain.com/api/url</td>
                                <td th:text="${container.status}">RUNNING</td>
           <!-- HERE ENDS THE PROBLEM -->
                            </tr>
                        </tbody>
                    </table>
                </div>
            </div>
</div>

My problem is the part where is access the container's properties (marked by the commentary). Every time I get a SpringEL Exception. If I remove the th:text="${container.xy}" and replaces it with th:text="${container} a String version of the container is shown so I have access to the object and the loop it working properly. I also tried to replace the field access with getters (e.g. getStatus()) but it also does not work.

Thanks for your help. If you need more information, feel free to ask.

Setup:

  • Java 8
  • Spring Boot Starter Web
  • Thymeleaf

edit: The exception thrown is: nested exception is org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating SpringEL expression: "container.name" (index:35) where index:35 is the first problematic line.

The toString() output when using ${container} is jenkins=com.my.app.Container@7552c269 and jenkins is the name attribute of the Container instance.

Solution It seemed that the nested loop was iterating over a Map instead of a List. Changing ${container.xy} to ${container.getValue().xy} solved the problem.

13
  • What exception? This most likely means that you have a typo in your SpEL expression, if you're getting a correct toString output when you drop the .xy. Commented Nov 11, 2016 at 16:16
  • ${host.getContainer()} should be ${host.getContainers()} Commented Nov 11, 2016 at 16:17
  • @TommySchmidt Made a typo in the class, fixed that. Commented Nov 11, 2016 at 16:26
  • @chrylis: nested exception is org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating SpringEL expression: "container.name" (index:35) is the exception where index:35 is the line where I use container.name. Commented Nov 11, 2016 at 16:30
  • Thanks. Please edit that into your question. Commented Nov 11, 2016 at 16:38

1 Answer 1

2

Solution

It seemes that the nested loop was iterating over a org.thymeleaf.util.EvaluationUtil$MapEntry instead of a List. Changing ${container.xy} to ${container.getValue().xy} solved the problem.

Bits learned along the way:

  • Override the toString() method to obtain formatted information about the object iterating over. In this case the output was key=value which altough value was expected. This gave a hint that the current object must be something else than a Container instance
  • Look at the stack trace of Thymeleaf (usually its a hint that something is null or not public)
  • Use getClass() on the current object during the iteration to check if something went wrong here
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.