What are supported types for keys of hash in freemarker? - freemarker

Can we use any type for keys of hash in Freemarker ?
For instance:
In Java we have:
Hash<User, Boolean> mapUserToSelected = new HashMap<>()
And in Freemarker we have:
<#list mapUserToSelected as user, selected>
<p>${user.name}</p>
<p>${selected?c}</p>
</#list>
However, we got "The following has evaluated to null or missing" for the <p>${selected?c}</p> and I am sure that it exists in the map.
If I use String for keys of hash Hash<String, Boolean> mapUserToSelected = new HashMap<>() it will work.
Is the key of hash needed to be String only?

The object mapUserToSelected can contain any Object as key, the built in ?c will convert a string to numeric. Not sure why you're applying it to Boolean.
Also, not to confuse ourselves: When we want to send the object mapUserToSelected from Logic (controller) to UI then tha's when the key must be String based on the definition of TemplateHashModel.
Example:
ModelAndView mainView = new ModelAndView();
mainView.getModel().put("usersMap", mapUserToSelected );
But the object itself can contain anything, you can get the keys list using mapUserToSelected?keys then access each the list of the keys using ?index if you are interested in the value of every key.

Related

Pass comparator into map with collectors [duplicate]

Let's say I have a list of Brand objects. The POJO contains a getName() that returns a string. I want to build a
Map<String, Brand>
out of this with the String being the name... but I want the key to be case insensitive.
How do I make this work using Java streams? Trying:
brands.stream().collect(Collectors.groupingBy(brand -> brand.getName().toLowerCase()));
doesn't work, which I think is because I'm not using groupBy correctly.
Collect the results into a case insensitive map
Map<String, Brand> map = brands
.stream()
.collect(
Collectors.toMap(
Brand::getName, // the key
Function.identity(), // the value
(first, second) -> first, // how to handle duplicates
() -> new TreeMap<String, Brand>(String.CASE_INSENSITIVE_ORDER))); // supply the map implementation
Collectors#groupBy won't work here because it returns a Map<KeyType, List<ValueType>>, but you don't want a List as a value, you just want a Brand, from what I've understood.

How to convert list of map list<map<string, object>> to list of value of map map<string,list<string>> using steam api java 8

I have a list of map. The map contains string as key & object as value. Most likely values also string. I want to group by one value so that I will get a set of value as key and another group of unique values as a list. Actually, list of map is couchbase select data.
e.g:
[{"id":"1", "status":"pending"},{"id":"2", "status":"download"},{"id":"3", "status":"pending"},{"id":"4", "status":"pending"}, {"id":"5", "status":"ready"},{"id":"6", "status":"download"}] => {"pending":["1","3","4"], "download":["2","6"], "ready":["5"]}
Try this out. Notice that my values are Strings NOT Objects as yours. In your case you need to cast it explicitly to String like so,
s -> (String) s.get("status")
s -> (String) s.get("id")
Map<String, List<String>> idsByStatus = listOfMap.stream().collect(
Collectors.groupingBy(s -> s.get("status"), Collectors.mapping(s -> s.get("id"), Collectors.toList())));

RedisTemplate get hash key by value

I'm very new both on Spring and Redis. I would like to know if there is a way to get the KEY by value?
My KEY is patterned like this: "{typeOfFile}:{id}:{filename}"
typeOfFile could either be "image", "html", or "pdf".
For instance, I want to get the get the KEY of an image type of file with a given fileHash and content. I'm doing it with this kind of idea:
private String getKeyByVal(final String givenFileHash, final String content) {
// get all keys that starts with "image"
Set<String> keys = redisTemplate.keys("image*");
if (keys != null) {
for (String key : keys) {
Map<Object, Object> val = redisTemplate.opsForHash().entries(key);
// check if the value of KEY is equal to the given fileHash
if (val.get("fileHash").equals(givenFileHash) && val.get("content").equals(content)) {
return key;
}
}
}
}
However, I was told that this is quite costly since I'm getting all the keys that starts with "image", and manually check all of them.
Now I'm thinking, maybe it would be much better if I can get the KEY by value. So that it would be easier to get all of its properties. Is that possible in Redis?
No, this is not possible in Redis. You can however store a reverse map in simultaneous as below:
fileHash -> "{typeOfFile}:{id}:{filename}"
This solution assumes that the file hash is unique. If the hash is not unique then you can store a set of ids with the same hash, retrieve the content for each of them and compare. Still a lot faster than the original solution.

Whats the key value in the Cache populated via #Cachable

I have a cache thats populated via #Cacheable as follows
#Cacheable(value = "accountGroupCache")
public List<Acc> getAccInfo(int groupId, String user)
I would like to know what will be the key value pair for this cache? I am using ehcahe to do the caching.
The key will be based on the parameters to your getAccInfo() method. The value is going to be the List<Acc> returned by your method.
According to the docs:
28.3.1.1 Default Key Generation
Since caches are essentially key-value stores, each invocation of a
cached method needs to be translated into a suitable key for cache
access. Out of the box, the caching abstraction uses a simple
KeyGenerator based on the following algorithm:
If no params are given, return 0.
If only one param is given, return that instance.
If more the one param is given, return a key computed from the hashes of all parameters.
Looking at the source code for DefaultKeyGenerator, this is how it computes "a key computed from the hashes of all parameters":
int hashCode = 17;
for (Object object : params) {
hashCode = 31 * hashCode +
(object == null ? NULL_PARAM_KEY : object.hashCode());
}

DataSource containing a null value makes ComboBox fail

I've thrown myself headfirst into C# and .Net 2.0 using Linq, and I'm having a few problems debugging some of the problems, namely the following:
I have a ComboBox control (cmbObjects) I want to populate with a set of objects retrieved using Linq. I've written a helper method to populate a List<T> generic:
class ObjectProvider
{
public static List<T> Get<T>(bool includeNull) where T : class, new()
{
List<T> list = new List<T>();
LutkeDataClassesDataContext db = ConnectionManager.GetConnection();
IQueryable<T> objects = db.GetTable<T>().AsQueryable();
if (includeNull) list.Add(null);
foreach (T o in objects) list.Add(o);
return list;
}
public static List<T> Get<T>() where T : class, new()
{
return Get<T>(false);
}
}
I verified the results when calling the function with true or false - the List does contain the right values, when passing true, it contains null as the first value, followed by the other objects.
When I assign the DataSource to the ComboBox however, the control simply refuses to display any items, including the null value (not selectable):
cmbObjects.DataSource = ObjectProvider.Get<Car>(true);
Passing in false (or no parameter) does work - it displays all of the objects.
Is there a way for me to specify a "null" value for the first object without resorting to magic number objects (like having a bogus entry in the DB just to designate a N/A value)? Something along the lines of a nullable would be ideal, but I'm kind of lost.
Also, I've tried adding new T() instead of null to the list, but that only resulted in an OutOfMemoryException.
The combo box control has an option to append data bound items to the hard-coded items in the list. So you hard-code your n/a value, and data bind the real values.
Okay, it seems the DataSource becomes invalid if you try to add a null value. The solution was to just add the items via a simple foreach loop with an empty string at the start instead of assigning the List<>.

Resources