I want to iterate a List nested in a Map, the data structure is like:
Map<Integer, List<Integer>> groups = new TreeMap<>()
// Some code else to put values into groups ...
Freemarker template:
<#list groups?keys as groupKey>
${groupKey} // It's OK here.
<#list groups[groupKey] as item> // Exception threw here, detail message is pasted below
${item}
</#list>
</#list>
Detail exception message:
FreeMarker template error:
For "...[...]" left-hand operand: Expected a sequence or string or something automatically convertible to string (number, date or boolean), but this evaluated to an extended_hash (wrapper: f.t.SimpleHash):
==> groups
So, what is the problem?
P.S.
I have tried groups.get(groupKey) instead of groups[groupKey], it throws a new Exception stack:
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
java.lang.String.compareTo(String.java:108)
java.util.TreeMap.getEntry(TreeMap.java:346)
java.util.TreeMap.get(TreeMap.java:273)
freemarker.template.SimpleHash.get(SimpleHash.java:160)
freemarker.core.Dot._eval(Dot.java:40)
freemarker.core.Expression.eval(Expression.java:76)
The problem in the original question is that FTL's hash type is not like Map. It's a collection of "variables", that is, the keys must be String-s. (Even that ?keys works is a glitch in BeansWrapper... though now it comes handy.) Since the key is a number, FTL assumes that you want to get an item from a sequence (a List or array), or that you want to get a character from a string, hence the original error message.
The solution is using the Java API-s, like get in Dev-an's answer. (On the long term FTL meant to introduce the map type, so all this problems with non-string keys will end, but who knows when that will be...)
Update: Since 2.3.22 there's ?api to access the Java API of objects, like myMap?api.get(nonStringKey). However, it's by default not allowed (see the api_builtin_enabled configuration setting and more in the Manual: http://freemarker.org/docs/ref_builtins_expert.html#ref_buitin_api_and_has_api). Also note that as Java maps are particular about the numerical type, if the key is not an Integer coming from a Java, you have to use myMap?api.get(myNumericalKey?int).
Try the following:
<#list groups?keys as groupKey>
${groupKey}
<#list groups.get(groupKey) as item>
${item}
</#list>
</#list>
Related
I want to access any index of a HashMap to retrieve an Id through this code:
th:text="'Network Id: ' + ${poolHashrates[0].key.networkHashrate.id}"
poolHashrates is a HashMap,
networkHashrate is a separate variable in key variable
Basically, all the networkHashrates in key have the same Id, so I could actually access any element, no matter what the index is.
I've also tried:
th:text="'Network Id: ' + ${poolHashrates.get(key).networkHashrate.id}"
th:text="'Network Id: ' + ${poolHashrates['key'].networkHashrate.id}"
None of these works. I keep getting
Exception evaluating SpringEL expression: "poolHashrates['key'].networkHashrate.id"
or
SpelEvaluationException: EL1007E: Property or field 'networkHashrate' cannot be found on null
I was able to print the Id in Intellij console, so it apparently exsists.
So you want to get an element out of the HashMap without knowing any of the keys? I think that's kind of silly... but it is possible. Here is one such way:
<span th:text="${poolHashrates.get(poolHashrates.keySet().toArray()[0])}" />
That will get you an element of the poolHashrates HashMap. I'm still unclear why you keep talking about key, but never really define what you mean. Is key really a property (with a getKey() and setKey()) on whatever you are storing in your HashMap? If so, then your final expression would look like this:
<span th:text="${poolHashrates.get(poolHashrates.keySet().toArray()[0]).key.networkHashrate.id}" />
or maybe
<span th:text="${poolHashrates.get(poolHashrates.keySet().toArray()[0]).networkHashrate.id}" />
(Are you confusing .key with a variable you get when you iterate over a HashMap with th:each in Thymeleaf?)
How do I iterate over a hashmap in Freemarker. I am using the 2.3.23 version and I am unable to get the value from the hashmap. I am using the following:
<#list hashMap?keys as key>
${key} = ${hashMap.get(key)}
<#list>
I have even tried the following:
<#list hashMap?keys as key>
${key} = ${hashMap[key]}
<#list>
It says that the value is null. However, I checked the data and there is a value for every key. I cannot upgrade the freemarker version to 2.3.25
Could someone help me with this.
Usually, the problem is that your keys aren't String-s, but some Java objects other than mere numbers/dates/booleans. Such "miscellaneous" objects are usable as FTL strings, so that you can print them directly (and internally that calls obj.toString()). Thus hashMap[key] won't complain that key is not a FTL string (because it is), instead it basically does hashMap.get(key.toString()), and there you have your null.
Since you can't update to 2.3.25, where you could use <#list hashMap as key, value>, you have to use ?api (and I hope you can enable calling ?api in the configuration):
<#list hashMap?api.entrySet() as ent>
${ent.key} = ${ent.value}
</#list>
I want to loop over the MultiMap in Freemarker template and access(display) the key and its distinct values(which are objects in this case):
Here TaskType is a String (dont misunderstand)
multiMap.put(TaskType.DHOLDING_TASK,Obj1);
multiMap.put(TaskType.BTRADE_TASK,Obj2);
multiMap.put(TaskType.ANONE,Obj3);
multiMap.put(TaskType.DHOLDING_TASK,Obj4);
multiMap.put(TaskType.CPRICE_TASK,Obj5);
multiMap.put(TaskType.BTRADE_TASK,Obj6);
multiMap.put(TaskType.ANONE,Obj7);
multiMap.put(TaskType.CPRICE_TASK,Obj8);
The output will look like this of teh MultiMap:
{CPRICE_TASK=[Obj5, Obj8], ANONE=[Obj3, Obj7], BTRADE_TASK=[Obj2, Obj6], DHOLDING_TASK=[Obj1, Obj4]}
My freeMarker code :
<#assign taskKeys = multiMap?keys >
<#list taskKeys as key>
${key} --It works fine till here :-)
`taskList[key] or taskList[key_values]---XXX both gives exception
How to display the multivalues associated with the key here in list???
I need to access the value part o fthe pair here(i.e. the RHS) : CPRICE_TASK=[Obj5, Obj8]
A help is much appreciated :)
Thanks ddekany for the reply.. :)
However, I could find the answer, It was mistake in freemarker code..I iterate over the keys as
<#list taskList?keys as taskType>
which is fine ..After that I should be iterating over the list associated with the key (i.e the multiple values)as it is a google multimap.Like:
<#assign values = taskList?values>
<#list values[taskType_index] as task>
I guess I was missing the assign tag in my code..while accessing the values of the keys.
Hope this will help some one.
I'm trying to convert a large Map> to some JavaBean. The key of map corresponds to some property of JavaBean, and the value somehow is decoded to property value. So I decided to use some util for that, but don't know what will work. There are some requirements I have to this util (or framework):
all configuration must be in separate files
should be a possibility to map dynamic quantity of keys:
there is a map:
key | value
quan | n
key_1| value_1
key_2| value_2
........ | .............
key_n| value_n
where n - is any number
and the JavaBean has a List of some beans. They have a property. value_1, value_2, ... must be mapped in this property, and in the end there must be so much beans in list, as these keys and values in map.
3.. should be a possibility to set up custom decoder for property mapping, because in most cases the value in map is a List with 1 value, so I need to get the first item of list (if it's not empty).
4.. should be a possibility run some script to execute extraordinary mappings, for example:
there is a map, that is described in 2d point.
and the JavaBean has a property of type HashMap, where value_1 is mapped to Bean1 and some analogous value from input map is mapped to Bean2.
I've tried to use smooks, but when I've started, all these requirements were not clear yet and the smooks was something new, I haven't worked with it until now. So the smooks config doesn't contain the whole business-logic (because of second req.) and looks ugly, I don't like that. I can show the most ugliest fragment for 2d point:
<jb:bean beanId="javaBean" class="com.example.JavaBean" createOnElement="map">
<jb:wiring property="someBeans" beanIdRef="someBeanItems"/>
</jb:bean>
<jb:bean beanId="someBeanItems" class="java.util.ArrayList" createOnElement="map/entry">
<jb:wiring beanIdRef="someBeanItem"/>
</jb:bean>
<jb:bean beanId="someBeanItem" class="com.example.someBeanItem" createOnElement="map/entry">
<condition>map.quan[0]>0</condition>
<jb:expression property="property1">
index = map.quan[0]-1;
value = additionalProperties.property1_List[index];
map.quan[0] = map.quan[0] - 1;
return value;
</jb:expression>
</jb:bean>
Here "property1_List" is builded before executing smooks.
Now I look for something more nice and need your help: maybe you know how to make that better using smooks? Or what another frameworks for mapping can you recommend for my issue?
I have a XML file with many copies of table node structure as below:
<databasetable TblID=”123” TblName=”Department1_mailbox”>
<SelectColumns>
<Slno>dept1_slno</Slno>
<To>dept1_to</To>
<From>dept1_from</From>
<Subject>dept1_sub</Subject>
<Body>dept1_body</Body>
<BCC>dept1_BCC</BCC>
<CC>dept1_CC</CC>
</SelectColumns>
<WhereCondition>MailSentStatus=’New’</WhereCondition>
<UpdateSuccess>
<MailSentStatus>’Yes’</MailSentStatus>
<MailSentFailedReason>’Mail Sent Successfully’</MailSentFailedReason>
</UpdateSuccess>
<UpdateFailure>
<MailSentStatus>’No’</MailSentStatus>
<MailSentFailedReason>’Mail Sending Failed ’</MailSentFailedReason>
</ UpdateFailure>
</databasetable>
As it is not an efficient manner to traverse the file for each time to fetch the details of each node for the queries in the program, I used the nested hashmap concept to store the details while traversing the XML file for the first time. The structure I used is as below:
MapMaster
Key Value
123 MapDetails
Key Value
TblName Department1_mailbox
SelectColumns mapSelect
Key Value
Slno dept1_slno
To dept1_to
From dept1_from
Subject dept1_sub
Body dept1_body
BCC dept1_BCC
CC dept1_CC
WhereCondition MailSentStatus=’New’
UpdateSuccess mapUS
MailSentStatus ’Yes’
MailSentFailedReason ’Mail Sent Successfully’
UpdateFailure mapUF
MailSentStatus ’No’
MailSentFailedReason ’Mail Sending Failed’
But the problem I’m facing now is regarding retrieving the Value part using the nested Keys. For example,
If I need the value of Slno Key, I have to specify TblID, SelectColumns, Slno in nested form like:
Stirng Slno = ((HashMap)((HashMap)mapMaster.get(“123”))mapDetails.get(“SelectColumns”))mapSelect.get(“Slno”);
This is unconvinent to use in a program. Please suggest a solution but don’t tell that iterators are available. As I’ve to fetch the individual value from the map according to the need of my program.
EDIT:my program has to fetch the IDs of the department for which there is privilege to send mails and then these IDs are compared with the IDs in XML file. Only information of those IDs are fetched from XML which returned true in comparison. This is all my program. Please help.
Thanks in advance,
Vishu
Never cast to specific Map implementation. Better use casting to Map interface, i.e.
((Map)one.get("foo")).get("bar")
Do not use casting in your case. You can define collection using generics, so compiler will do work for you:
Map<String, Map> one = new HashMap<String, Map>();
Map<String, Integer> two = new HashMap<String, Integer>();
Now your can say:
int n = one.get("foo").get("bar");
No casting, no problems.
But the better solution is not to use nested tables at all. Create your custom classes like SelectColumns, WhereCondition etc. Each class should have appropriate private fields, getters and setters. Now parse your XML creating instance of these classes. And then use getters to traverse the data structure.
BTW if you wish to use JAXB you do not have to do almost anything! Something like the following:
Unmarshaller u = JAXBContext.newInstance(SelectColumns.class, WhereCondition.class).createUnmarshaller();
SelectColumns[] columns = (SelectColumns[])u.unmarshal(in);
One approach to take would be to generate fully qualified keys that contain the XML path to the element or attribute. These keys would be unique, stored in a single hashmap and get you to the element quickly.
Your code would simply have to generate a unique textual representation of the path and store and retrieve the xml element based on the key.