Freemarker InvalidReferenceException - java

I am trying to pass a collection to Freemarker:
My Recipient inner class:
#Data
private class Recipient {
private String phone;
private String languageValue;
}
My template:
<#list recipients as recipient>
{
"address": "${recipient.phone}",
"language": "en"
}
</#list>
My Java code:
List <Recipient> recipientList = new ArrayList <> ();
Recipient r = new Recipient();
r.setPhone("123");
recipientList.add(r);
Template template = new Template("name", new StringReader(myTemplate), new Configuration());
Writer out = new StringWriter();
Map<String, Object> dataModel = new HashMap<>();
dataModel.put("recipients", recipientList);
template.process(dataModel, out);
But I am getting this error:
[pool-1-thread-7] freemarker.runtime: Error executing FreeMarker template freemarker.core.InvalidReferenceException: The following has evaluated to null or missing:==> recipient.phone [in template "name" at line 1, column 220]
What's wrong? Please help. Thanks.

Related

Java Jackson how to parse large REST API JSON?

Api I'm trying to get info from https://prices.runescape.wiki/api/v1/osrs/latest
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.GET()
.uri(URI.create("https://prices.runescape.wiki/api/v1/osrs/latest"))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
ObjectMapper mapper = new ObjectMapper();
JsonNode json = mapper.readTree(response.body());
JsonNode data = json.get("data");
List<Data> items = new ArrayList<>();
data.forEach(item -> {
Data d = new Data(
item.get("high").asInt(),
item.get("highTime").asInt(),
item.get("low").asInt(),
item.get("lowTime").asInt()
);
items.add(d);
});
Problem is the object is the itemID. So if I want the item id 6. I can't do it since it's not an attribute of the object.
"2":{"high":164,"highTime":1672078170,"low":160,"lowTime":1672078164} ``
2 is the itemID and the object.
Below is when I loop through the arraylist and print it out
Data{high=157, highTime=1672071161, low=150, lowTime=1672071151}
Data{high=187987, highTime=1672071066, low=182005, lowTime=1672070881}
Data{high=189903, highTime=1672071052, low=186820, lowTime=1672070884}
Data{high=190000, highTime=1672070957, low=184882, lowTime=1672070984}
Your JSON has the following structure:
{
"data":{
"2":{ ... },
"6":{ ... },
"8":{ ... },
"10":{ ... },
"12":{ ... }
...
}
}
And property "data" is associated not with an object, or a List<Data>, but with a Map<Integer,Data> (or Map<String,Data>.
There are several ways how you can parse:
You can define an object with a single property Map<Integer,Data> data.
public static class DataWrapper {
private Map<Integer, Data1> data;
// getters, setters
}
Usage example:
String json = """
{
"data":{ ... }
}
""";
ObjectMapper mapper12 = new ObjectMapper();
DataWrapper dataWrapper = mapper12.readValue(json12, DataWrapper.class);
Map<Integer, Data1> dataMap = dataWrapper.getData();
System.out.println("item 6: " + dataMap.get(6));
Another approach would be to create a JsonNode by parsing the given JSON, access the node mapped to the property "data" and parse it as a Map using ObjectReader and its method ObjectReader.readValue(). To generate ObjectReader we can make use of the method ObjectMapper.readerFor() which expects a TypeReference.
That's how the second approach might be implemented:
String json = """
{
"data":{ ... }
}
""";
ObjectMapper mapper = new ObjectMapper();
JsonNode tree = mapper.readTree(json);
ObjectReader reader = mapper.readerFor(new TypeReference<Map<Integer, Data>>() {});
Map<Integer, Data> itemsMap = reader.readValue(tree.get("data"));
System.out.println("item 6: " + itemsMap.get(6));
Output:
item 6: Data{high=195500, highTime=1672079035, low=182009, lowTime=1672078518}

How to create a nested json using collections in java

I am creating a Json format for my nav bar menu and menu items.. i have put some effort and have done some work for one loop but what i want is to be nested json
My database has Data like This
What i want is to create a Json format from this table like this
var data = {
"India":
[
{ "Submenu": "delhi", "link" : "https://www.google.com" },
{ "Submenu": "mumbai", "link" : "https://www.google.com" }
],
"USA":
[
{ "Submenu": "NY", "link" : "https://www.google.com" },
{ "Submenu": "california", "link" : "https://www.google.com" }
],
"England":
[
{ "Submenu": "London", "link" : "https://www.google.com" },
{ "Submenu": "Menchester", "link" : "https://www.google.com" }
],
"logout":
[]
};
Till now i have tried this
LinkedHashMap<Object, Object> lhm = null;
List<Map<Object, Object>> list = new ArrayList<Map<Object, Object>>();
String sql="select menu,submenu and link from table_name";
String name,link;
String str = null;
Gson gson = new Gson();
try {
resultSet = statement.executeQuery(sql);
while(resultSet.next()){
lhm= new LinkedHashMap<Object, Object>();
name= resultSet.getString("submenu");
link= resultSet.getString("link");
lhm.put("submenu", name);
lhm.put("link", link);
list.add(lhm);
str = gson.toJson(list);
}
System.out.println(str);
from this i am getting result like this
[{"submenu":"Delhi","link":"https://www.google.com"},{"submenu":"mumbai","link":"https://www.google.com"},{"submenu":"NY","link":"https://www.google.com"},{"submenu":"California","link":"https://www.google.com"},{"submenu":"London","link":"https://www.google.com"},{"submenu":"Mencherter","link":"https://www.google.com"}]
now i have got the sub menus and there link .. i am facing trouble on linking the submenus to there respective menus .. i am facing issue in looping the data acc to my requirement if anyone of you have any suggestion and idea please help me out
First retrieve required dat from DB:
select menu, sub-menu, link from table_name;
Then create a Map to hold a menu content:
Map<String, List<Map<String, String>> map = new LinkedHashMap<>();
Then read result sets and fill a map, using menu name as a key:
while(rs.next()) {
map.compute(rs.getString("menu"), (menu, subMenus) -> {
Map<String, String> mapSubMenu = new LinkedHashMap<>();
mapSubMenu.put("Submenu", rs.getString("sub-menu"));
mapSubMenu.put("link", rs.getString("link"));
subMenus = subMenus != null ? subMenus : new ArrayList<>();
subMenus.add(mapSubMenu);
return subMenus;
});
}
Try Using Map<String,List<Map<Object, Object>>> instead of List<Map<Object, Object>> so that you can give menu name to your main menu.
LinkedHashMap<Object, Object> lhm; //initiaze
Map<String,List<Map<Object, Object>>> map;
List<Map<Object, Object>> list;
while(rs.next())
{
String menu = rs.getString("menu");
String subMenu = rs.getString("sub-menu");
String link = rs.getString("link");
lhm.put("submenu", name);
lhm.put("link", link);
if (map.containsKey(menu)) //check if mainmenu already present
{
map.get(menu).add(lhm);
}
else
{
//initialize list here
list.add(lhm);
map.put(menu,list);
}
}
str = gson.toJson(list);
Follow idea only and customize code as your need

how to declare a java bean for the below json structire

I have below json response as part of a webservice response ,where inner object name is value which is dynamic.Not able to understand how to declare a equivalent java bean...
{
"error": [
{
"fea09b93175b626e4bb3d248ccb890bc": {
"name": "80_5595_10.zip (5.0)",
"error": [
"Location path does not exist"
]
}
},
{
"5a8745c1967adabe9d492d3595f37ce1": {
"name": "80_7208_01.zip (5.0)",
"error": [
"Location path does not exist"
]
}
}
]
You could do it that way (example using Jackson).
I declared a bean as follow:
class Error {
String id;
String name;
List<String> error;
// Getters / Setters
#Override
public String toString() {
return "id="+id+", name="+name+", error="+error;
}
}
Your JSON structure is Map<String, List<Map<String, Error>>>
// Parse your JSON into a Map<String, List<Map<String, Error>>>
ObjectMapper mapper = new ObjectMapper();
Map<String, List<Map<String, Error>>> map =
mapper.readValue(json, new TypeReference<Map<String, List<Map<String, Error>>>>() {});
You now have this Map structure
{ error = [
{ fea09b93175b626e4bb3d248ccb890bc = Error#36d64342 },
{ 5a8745c1967adabe9d492d3595f37ce1 = Error#39ba5a14 }
]
}
Then take each error element of the Map and set their id to be the same as their key. And add them into a List
List<Map<String, Error>> errorsMap = map.get("error");
List<Error> errors = new ArrayList<>();
for(Map<String, Error> errorMap : errorsMap) {
String key = new ArrayList<>(errorMap.keySet()).get(0);
Error error = errorMap.get(key);
error.setId(key);
errors.add(error);
}
errors.forEach(System.out::println);
Outputs:
id=fea09b93175b626e4bb3d248ccb890bc, name=80_5595_10.zip (5.0), error=[Location path does not exist]
id=5a8745c1967adabe9d492d3595f37ce1, name=80_7208_01.zip (5.0), error=[Location path does not exist]

Iterate hashmap's mongodb result in Freemarker

I am new at java and mongodb, and i dont see how to solve this, i have a collection:
{
"_id" : "20minutos",
"active" : true,
"group" : "20 Minutos",
"domains" : [
"20minutos.com",
"20minutos.es",
"20minutos.tv"
]
}
java code:
get("/pages/:page", (request, response) -> {
String page = request.params(":page");
if(page.equals("forms")){
UserDAO userDao = new UserDAO(Connection.getInstance().getDataStore());
HashMap<String,Object> map = new HashMap<String,Object>();
map.put("users", userDao.AllUsers());
return new ModelAndView(map, page+".ftl");
}else{
return new ModelAndView(null, page+".ftl");
}
}, new FreeMarkerEngine());
my AllUsers() function
public List<User> AllUsers() throws Exception{
return this.find().asList();
}
the pojo clas, the domains
public List<String> getDomains() {
return domains;
}
and the freemarker code
<#list users as data>
<tr class="odd gradeX">
<td>${data._id}</td>
<td>${data.active?string('yes', 'no')}</td>
<td>${data.group}</td>
<#assign x = ''>
<#assign keys = data?keys>
<#list keys as key>
<#assign x = x+','+key>
</#list>
<td>${x}</td>
</tr>
the problem is that i cant acces the values of Domains
i hope u someone can help me
thank you in advance
If you want to list user domains you can use join:
<td>${data.domains?join(",")}</td>

Using EXT-GWT ComboBox

I extend ComboBox and in constructor have such code:
ModelType type = new ModelType();
type.setRoot("data");
type.addField("id", "id");
type.addField("name", "name");
JsonLoadResultReader<ListLoadResult<ModelData>> reader = new JsonLoadResultReader<ListLoadResult<ModelData>>(type);
RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, "/category/getall");
HttpProxy<String> proxy = new HttpProxy<String>(builder);
BaseListLoader<ListLoadResult<ModelData>> loader = new BaseListLoader<ListLoadResult<ModelData>>(proxy, reader);
ListStore<ModelData> store = new ListStore<ModelData>(loader);
setStore(store);
loader.load();
setValueField("id");
setDisplayField("name");
setName("categoty");
Result: ajax query send to server but no results see in combobox but when click on it it loads data again and then display it, and how to set value to combobox?
I've created a simple store factory method that should solve your issue.
Copy in your class and create the store:
setStore(_createListStore("/category/getall", "data", "id", "name"));
loader.load();
setValueField("id");
setDisplayField("name");
setName("categoty");
the error in your code is that you add two fields to the ModelType, instead you should add just one field with "id" as value and "name" as display
protected ListStore<ModelData> _createListStore(String url, String root, String fieldValue, String displayValue){
ModelType mt = new ModelType();
mt.setRoot(root);
mt.addField(displayValue, fieldValue);
RequestBuilder rb = new RequestBuilder(RequestBuilder.GET, url);
HttpProxy<String> proxy = new HttpProxy<String>(rb);
JsonLoadResultReader<ListLoadResult<ModelData>> reader = new JsonLoadResultReader<ListLoadResult<ModelData>>(mt);
final BaseListLoader<ListLoadResult<ModelData>> loader = new BaseListLoader<ListLoadResult<ModelData>>(proxy, reader);
ListStore<ModelData> store = new ListStore<ModelData>(loader);
return store;
}

Categories

Resources