Home > database >  Retrieve individual values from Map<Long,String> by key in Thymeleaf without iteration
Retrieve individual values from Map<Long,String> by key in Thymeleaf without iteration

Time:10-04

I tried all the different variations of myMap.get(key), myMap[key], etc. to get this line of code working where myMap is a Map<Long,String> and thing has a property called state:

<span th:text="${myMap.get(__${thing.state}__)}"></span>

Any syntactically valid variation I could come up with would only result in empty text.

The only thing that ultimately worked was using a Map<Integer,String> instead. I'm still passing a long into myMap.get(). Thankfully my value range for the particular use case is within the range of Integer.

How do I write this line of code to be able to use a Map<Long,String> when I need to?

CodePudding user response:

I tried the following:

Map<Long, String> foodMap = new HashMap<>();
foodMap.put(1L, "Ham & Eggs");
context.setVariable("food", foodMap);
context.setVariable("keyer", new Keyer(1));

With this for my key:

static class Keyer {

  public Keyer(long key) {
    this.key = key;
  }

  private long key;

  public long getKey() {
    return key;
  }

  public void setKey(long key) {
    this.key = key;
  }
}

And each of these worked:

<span th:text="${food[keyer.key]}" />
<span th:text="${food.get(keyer.key)}" />
<span th:text="${food.get(1L)}" />

Output:

<span >Ham &amp; Eggs</span>
<span >Ham &amp; Eggs</span>
<span >Ham &amp; Eggs</span>

CodePudding user response:

The reason your example does not work as expected is a combination of these two facts:

  • By coding __${...}__ you trigger preprocessing the contained expression. Preprocessing adds back the result of the expression as text to the surrounding expression and is processed again in a second round. Thymeleaf/SPEL does not have a good hint to interpret the result as java.lang.Long and hence the next best attempt is to parse it into java.lang.Integer.
  • java.lang.Integer and java.lang.Long do not compare (and maps rely on the result of equals).
Integer i = 42;
Long l = 42L;
System.out.println(l.equals(i)); // the output is 'false'

The solution depends on wether you actually need preprocessing and how thing.state is declared:

  1. If it is a long or java.lang.Long and there is no good argument for preprocessing it you can simply write:
${myMap.get(thing.state)}
  1. If it has a different type (e.g. String) or you definitely need it to be preprocessed you can explicitly convert it to long by adding an 'L' suffix:
${myMap.get(__${thing.state   'L'}__)}
  1. Similar to option 2 you could adapt your code to make thing.state resolve to a string ending with 'L'.

(tested with Thymeleaf 3.0.15.RELEASE)

Hints:

  • Option 1 is expected to be slightly faster.
  • Option 2 and 3 only will raise an exception if the resulting expression is not numeric (as the original expression would as well).
  • Related