Внимание продвинутых гуру Freemarker:
Я хочу использовать один шаблон freemarker, чтобы иметь возможность выводить таблицы произвольных pojos, столбцы для отображения определяются отдельно от данных. Проблема в том, что я не могу понять, как получить дескриптор функции в pojo во время выполнения, а затем заставить freemarker вызывать эту функцию (лямбда-стиль). Из просмотра документов кажется, что Freemarker поддерживает функциональное программирование, но я не могу сформулировать правильное заклинание.
Я набросал упрощенный конкретный пример. Допустим, у меня есть два списка: список людей с именами firstName и lastName и список автомобилей с маркой и моделью. хотел бы вывести эти две таблицы:
<table>
<tr>
<th>firstName</th>
<th>lastName</th>
</tr>
<tr>
<td>Joe</td>
<td>Blow</d>
</tr>
<tr>
<td>Mary</td>
<td>Jane</d>
</tr>
</table>
и
<table>
<tr>
<th>make</th>
<th>model</th>
</tr>
<tr>
<td>Toyota</td>
<td>Tundra</d>
</tr>
<tr>
<td>Honda</td>
<td>Odyssey</d>
</tr>
</table>
Но я хочу использовать один и тот же шаблон, поскольку он является частью фреймворка, который имеет дело с десятками различных типов pojo.
С учетом следующего кода:
public class FreemarkerTest {
public static class Table {
private final List<Column> columns = new ArrayList<Column>();
public Table(Column[] columns) {
this.columns.addAll(Arrays.asList(columns));
}
public List<Column> getColumns() {
return columns;
}
}
public static class Column {
private final String name;
public Column(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public static class Person {
private final String firstName;
private final String lastName;
public Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
}
public static class Car {
String make;
String model;
public Car(String make, String model) {
this.make = make;
this.model = model;
}
public String getMake() {
return make;
}
public String getModel() {
return model;
}
}
public static void main(String[] args) throws Exception {
final Table personTableDefinition = new Table(new Column[] { new Column("firstName"), new Column("lastName") });
final List<Person> people = Arrays.asList(new Person[] { new Person("Joe", "Blow"), new Person("Mary", "Jane") });
final Table carTable = new Table(new Column[] { new Column("make"), new Column("model") });
final List<Car> cars = Arrays.asList(new Car[] { new Car("Toyota", "Tundra"), new Car("Honda", "Odyssey") });
final Configuration cfg = new Configuration();
cfg.setClassForTemplateLoading(FreemarkerTest.class, "");
cfg.setObjectWrapper(new DefaultObjectWrapper());
final Template template = cfg.getTemplate("test.ftl");
process(template, personTableDefinition, people);
process(template, carTable, cars);
}
private static void process(Template template, Table tableDefinition, List<? extends Object> data) throws Exception {
final Map<String, Object> dataMap = new HashMap<String, Object>();
dataMap.put("tableDefinition", tableDefinition);
dataMap.put("data", data);
final Writer out = new OutputStreamWriter(System.out);
template.process(dataMap, out);
out.flush();
}
}
Все вышесказанное дано для этой проблемы. Итак, вот шаблон, который я взломал. Обратите внимание на комментарий, где у меня возникли проблемы.
<table>
<tr>
<#list tableDefinition.columns as col>
<th>${col.name}</th>
</#list>
</tr>
<#list data as pojo>
<tr>
<#list tableDefinition.columns as col>
<td><#-- what goes here? --></td>
</#list>
</tr>
</#list>
</table>
Итак, у col.name есть имя свойства, к которому я хочу получить доступ из pojo. Я пробовал несколько вещей, таких как
pojo.col.name
и
<#assign property = col.name/>
${pojo.property}
но, конечно, они не работают, я просто включил их, чтобы помочь передать мои намерения. Я ищу способ получить дескриптор функции и вызвать ее с помощью freemarker, или, может быть, какую-то функцию «оценки», которая может принимать произвольное выражение в виде строки и оценивать его во время выполнения.