I have following map

Map<String, Map<String, Long>>

This map is accessible through following method in java file.

public List<Entry<String, List<Entry<String, Long>>>> getByEventTypeSorted() {
    List<Entry<String, List<Entry<String, Long>>>> ret = new ArrayList<Entry<String, List<Entry<String, Long>>>>();
    ret.addAll((Collection<? extends Entry<String, List<Entry<String, Long>>>>) byEventType.entrySet());
    return ret;
}

Thus I am converting Map<String, Map<String, Long>> into List<Entry<String, List<Entry<String, Long>>>> and returning it.

Now, in my tml file I am trying to loop through it like this.

<tr t:type="Loop" t:source="summarizer.byEventTypeSorted" t:value="entry">
    <td style="border: 1px solid #EEEEEE; padding: 3px">${entry.key}</td>
    <td style="border: 1px solid #EEEEEE; padding: 3px" t:type="Loop" t:source="${entry.value}" t:value="entry2"> 
        ${entry2.key}
    </td>
</tr>

Corresponding java file has following properties.

@Property
private Entry<String,Long> entry;
@Property
private Entry<String,Long> entry2;

When I run the above code. Following exception is generated.

Failure writing parameter 'value' of component ConceptSummaries:loop_1: Could not find a coercion from type java.lang.String to type java.util.Map$Entry.

If I change the type of property entry2 to String in java file like below.....

@Property
private Entry<String,Long> entry;
@Property
private String entry2;

And loop in tml file like below.

<tr t:type="Loop" t:source="summarizer.byEventTypeSorted" t:value="entry">
    <td style="border: 1px solid #EEEEEE; padding: 3px">${entry.key}</td>
    <td style="border: 1px solid #EEEEEE; padding: 3px" t:type="Loop" t:source="${entry.value}" t:value="entry2"> 
        ${entry2}
    </td>
</tr>

Then I get the whole list rendered as a single string.

This means that tapestry is converting the List<Entry<String, Long>> into a String. I do not want that to happen as I want to loop through the list and access individual entries.

How to loop through these nested maps? And is there any way to retain the type of inner list and prevent tapestry from converting it into a string?

Update: I was able to solve this problem using Lance Java's suggestions. Following are the details.

code in tml file.

<tr t:type="Loop" t:source="summarizer.byEventTypeSorted.entrySet()" t:value="entry">
    <td style="border: 1px solid #EEEEEE; padding: 3px">${entry.key}</td>
    <td style="border: 1px solid #EEEEEE; padding: 3px" t:type="Loop" t:source="KeySetForEntryValue" t:value="entry2"> 
        ${entry2.key}
    </td>
</tr>

I have a getter method for "KeySetForEntryValue" and Map<String, Map<String, Long>> in corresponding java class.

public Set<Entry<String, Long>> getKeySetForEntryValue(){
    return entry.getValue().entrySet();
}

public Map<String, Map<String, Long>> getByEventTypeSorted() {
    return byEventType;
}

And following are the properties in the same java class.

@Property
private Entry<String, Map<String, Long>> entry;
@Property
private Entry<String, Long> entry2;
有帮助吗?

解决方案

Your problem is with t:source="${entry.value}"

Using ${...} in a template attribute causes the value to be coerced to a string

Try t:source="entry.value" instead.

Here's how I'd do it:

@Property
private Map<String, Map<String, Long>> byEventType;

@Property
private Entry<String, Map<String, Long>> entry;

@Property
private Entry<String, Long> entry2;

<tr t:type="Loop" t:source="byEventType.entrySet()" t:value="entry">
<td style="border: 1px solid #EEEEEE; padding: 3px">${entry.key}</td>
<td style="border: 1px solid #EEEEEE; padding: 3px" t:type="Loop" t:source="entry.value.entrySet()" t:value="entry2"> 
    ${entry2.key} = ${entry2.value}
</td>

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top