1

How can I convert object types within EL expressions? Thymeleaf engine doesn't seem to understand something like this:

<span th:text="${((NewObjectType)obj).amount"></span>

Thanks.

Update:

Class hierarchy in which I store data. They are used to populate the HTML table.

public class RootBase implements Serializable {
    ...
}

public class ColBase<T extends RootBase> implements Serializable {

    private ArrayList<T> internalList;

    public int getSize() {
       ...
    }

    public T get(int index) {
       return internalList(index);
    }
}

public class Row extends RootBase {
    ...
}

public class Rows extends ColBase<Row> {
    ...
}

Controller:

Rows rowsColObj = xxxJaxProxyService.getRows();
model.addAttribute("rows", rowsColObj);

View:

<table style="width:100%; border:solid 1px" th:if="${statement}">
  <thead>
    <tr>
      <th style="text-align: left">#</th>
      <th style="text-align: left">Amount</th>
    </tr>
  </thead>
  <tbody th:object="${rows}">
    <tr th:each="index : *{#numbers.sequence(0, size - 1)}" th:with="entry=${#object.get(index)}">
      <td th:text="${index} + 1">1</td>
      <td th:text="${entry.amount}">0</td>
    </tr>
  </tbody>
</table>
  • why is it necessary to type cast obj? – Scary Wombat May 23 '13 at 07:29
  • Because "obj" was retrieved from a generic list and type erasure has removed its type information. I've considered different possibilities to go around type erasure and decided it's best to cast "obj" to its original type in client code. – Alex Medvedeov May 23 '13 at 17:17

1 Answers1

0

Can you wrap the list in your own model? Part of the value proposition of SpringMVC and Thymeleaf is to remove the application logic from the view layer. Casting is application logic and should be done within the Controller or if you must...the Model. So if might look like this:

/**
 * Custom model for attributes displayed on the page.
 */    
MyPageModel
    List<TableRows> tableRows;
    public List<TableRows> getTableRows(){...}
    ...

Next, add the model within the controller method. And here is how it might be used in a template to bind the model to the html table:

<table>
    <tr th:each="tableRow : ${model.tableRows}">
        <td class="date" th:text="${tableRow.amount}">$103</td>
    </tr>
    <tr th:unless="*{tableRow}">
        <td colspan="3">No amounts available</td>
    </tr>
</table>
hubbardr
  • 3,025
  • 1
  • 19
  • 25
  • Thanks. And I agree. But maybe I should ask my question this way then. How can I bind a collection to a HTML table? Because right now I'm using "th:each" to loop through a collection and display each item in a row. That's when I need to convert the type. – Alex Medvedeov May 23 '13 at 19:43
  • Edited my original response with an example – hubbardr May 23 '13 at 20:04
  • Thanks for follow up. Appreciate it. See, this is almost what I have. The problem is in 2nd line of your HTML code (th:each). tableRow's type isn't what it should be. For example, if tableRow's type is TableRow (that has the "amount" attribute) and TableRow is inherited from ParentClass, in the html code, tableRow's type during runtime is ParentClass. Thus, you'll get an exception indicating the "getAmount" is not in "ParentClass". – Alex Medvedeov May 23 '13 at 20:47
  • It should not be ParentClass no unless the model's implementing an interface or something...no I dont even see that as possible. Are your methods typed (with generics)? If the model that is being used in the template says the method returns a List of TableRow objects then thymeleaf should be getting a TableRow...not whatever TableRow is extending. Can you show us the code inthe controller where you add the model? – hubbardr May 23 '13 at 22:27
  • Updated the original post. During runtime, type erasure removes T's type information from byte code and when returned from "get" method the type is RootBase. – Alex Medvedeov May 23 '13 at 22:52
  • No, that doesnt make any sense. :) The type is compiled into the bytecode of the class. You might have to include some example code so we can try to reproduce your situation. – hubbardr May 24 '13 at 18:41
  • Thanks. But I'm beginning to think you aren't familiar with Type erasure.. http://gafter.blogspot.ca/2004/09/puzzling-through-erasure-answer.html http://stackoverflow.com/questions/339699/java-generics-type-erasure-when-and-what-happens – Alex Medvedeov May 24 '13 at 20:26
  • I'm very familiar with generics and type erasure - I'm just saying I don't understand how it applies here. SpringEL uses a conversion service which is Generics aware. So the type should always be retained. See http://static.springsource.org/spring/docs/3.0.x/reference/expressions.html#d0e11802 – hubbardr May 29 '13 at 19:05