简体   繁体   中英

Using Freemarker to display a table of arbitrary Java objects and their fields

First, I've read this question , but it didn't resolve my issue.

I am trying to create a table that will display an arbitrary list of Java objects. When I say "arbitrary" I mean both that the amount of objects is arbitrary and that the type of objects is arbitrary (they are all going to be instances of the same class though). I want the rows of this table to represent objects, and the columns to represent the value of each object's instance variable (spreadsheet style, basically). The first row, however, will just be a list of instance variable names.

The objects I am currently testing this on has all variables set to private, but I have provided the relevant getters and setters.

Here is a snippet from my Java code. I am pulling objects from an Oracle Coherence cache, and putting them into an ArrayList. Then I make a string array of the instance variable names.:

        /**
     * Get objects in cache and add to ArrayList.
     */

    for(Iterator iter = currentCache.entrySet().iterator();iter.hasNext();){
        Map.Entry entry = (Map.Entry)iter.next();
        String key = (String) entry.getKey();
        Pof tempPof = (Pof)entry.getValue();
        tableList.add(tempPof);
        System.out.println("one loop");
    }

    request.setAttribute("beans",tableList);

    System.out.println("Size of tableList is: " + tableList.size());
    /**
     * Build an array containing the variable names of cached objects.
     */

    Field[] fields = Pof.class.getDeclaredFields();
    String[] variableNames = new String[fields.length];

    for(int j = 0; j < fields.length;j++){
        variableNames[j] = fields[j].getName();
        System.out.println(variableNames[j]);
    }

    request.setAttribute("colNames",variableNames);


    /**
     * numCols determines the number of columns displayed in the table.
     */

    int numCols = fields.length;
    String[] fieldStrings = new String[numCols];
    request.setAttribute("numCols",numCols);
    Pof thing = (Pof) tableList.get(0);

Here is a snippet from the relevant .ftl file:

<table border = "1px">
        <thead>
            <tr>
                <th colspan="${numCols}">${selectedCache}</th>
            </tr>
            <tr>
                <#list colNames as colName>
                    <td>${colName}</td>
                </#list>
            </tr>
        </thead>
        <tbody>
            <#list beans as bean>
                <tr>
                    <#list colNames as colName>
                        <td>${bean[colName]}</td>
                    </#list>
                </tr>
            </#list>
        </tbody>

    </table>

This gets me the following error:


freemarker.core.InvalidReferenceException: The following has evaluated to null or missing: ==> bean[colName] [in template "front.ftl" at line 46, column 35]

Tip: It's the final [] step that caused this error, not those before it.

Tip: If the failing expression is known to be legally refer to something that's sometimes null or missing, either specify a default value like myOptionalVar!myDefault, or use <#if myOptionalVar??>when-present<#else>when-missing. (These only cover the last step of the expression; to cover the whole expression, use parenthesis: (myOptionalVar.foo)!myDefault, (myOptionalVar.foo)?? FTL stack trace ("~" means nesting-related): - Failed at: ${bean[colName]} [in template "front.ftl" at line 46, column 33]

at freemarker.core.InvalidReferenceException.getInstance(InvalidReferenceException.java:134)
at freemarker.core.EvalUtil.coerceModelToTextualCommon(EvalUtil.java:451)
at freemarker.core.EvalUtil.coerceModelToStringOrMarkup(EvalUtil.java:374)
at freemarker.core.DollarVariable.calculateInterpolatedStringOrMarkup(DollarVariable.java:96)
at freemarker.core.DollarVariable.accept(DollarVariable.java:59)
Truncated. see log file for complete stacktrace

The problem seems to be my ftl syntax; that is, it doesn't like the expression ${bean[colName]}.

Questions:

1) Is the syntax wrong?

2) Is this something that Freemarker can't do?

3) Should I try another approach? For example, should I just create an array with each bucket containing an array (or another data structure) of the instance variable values?

It should work, providing that:

  • Pof is a public class
  • There's a public Pof.getFoo() method for each colName "foo"
  • getFoo() returns non- null value. If it sometimes returns null , you have to specify what to display then, for example: ${bean[colName]!'-'}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM