0

I tried to follow Return HashMap in mybatis and use it as ModelAttribute in spring MVC (Option 1) and Mybatis ResultMap is HashMap<String,Object>. I have

@Select("select sources.host as 'key', count(*) total ... group by host")
@MapKey("key")
Map<String, Integer> getSourcesById(@Param("id")String id, @Param("hitDate")Date hitDate);

It returns an error

Error attempting to get column 'key' from result set. Cause: java.sql.SQLException: Invalid value for getInt() - 'NONE' ; SQL []; Invalid value for getInt() - 'NONE'; nested exception is java.sql.SQLException: Invalid value for getInt() - 'NONE'

The query works fine in MySQL and returns

| key         | total |
+-------------+-------+
| NONE        |    33 |
| twitter.com |     1 |

It's as if it is not using the @MapKey annotation.


I tried

List<AbstractMap.SimpleEntry<String, Integer>> getSourcesById(...)

But it gave

nested exception is org.apache.ibatis.executor.ExecutorException: No constructor found in java.util.AbstractMap$SimpleEntry matching [java.lang.String, java.lang.Long]

Also tried this with the same error.

List<AbstractMap.SimpleEntry<String, Long>> 

https://docs.oracle.com/javase/7/docs/api/java/util/AbstractMap.SimpleEntry.html#constructor_summary

MyBatis 3.4.6, MyBatis-Spring 1.3.2

Chloe
  • 25,162
  • 40
  • 190
  • 357

2 Answers2

0

I had to build my own class, but I don't like it. It's dumb that I have to add so much code for getting a simple key/value pair from the DB.

Pair.java
public class Pair<T1, T2> {
    public T1 key;
    public T2 value;

    public Pair(T1 k, T2 v) {
        key = k;
        value = v;
    }
    
    public Pair(String k, Long v) {
        key = (T1) k;
        value = (T2) v;
    }

    public T1 getKey() {
        return key;
    }

    public T2 getValue() {
        return value;
    }

}
Mapper.java
List<Pair<String, Long>> getSourcesById(@Param("id")String id, @Param("hitDate")Date hitDate);
Page.jsp
<c:forEach items="${sources}" var="s">${s.value},</c:forEach>
Community
  • 1
  • 1
Chloe
  • 25,162
  • 40
  • 190
  • 357
0

You should write the following,

@Select("select sources.host as 'key', count(*) total ... group by host")
@MapKey("key")
Map<String, Map<String, Object>> getSourcesById(@Param("id")String id, @Param("hitDate")Date hitDate);

It's the option-1's way.

Bing Zhao
  • 568
  • 6
  • 19
  • That is a Map of Maps. Why would that be useful? And how would you specify the 2 keys? There are only 2 values, but that requires 3. Presumably you would use the same key for the outer Map as the inner Map, but then what's the point? Might as well just use a List of Maps at that point. – Chloe Dec 13 '18 at 23:11
  • @Chloe It's the way that option 1 works, for key "NONE" of the outter map, inner map is "key" -> "NONE", "total" -> 33. You can transform Map> to Map by `Map anotherMap = map.entrySet().stream() .collect(Collectors.toMap(Map.Entry::getKey, it -> (int)it.getValue().get("total")));` – Bing Zhao Dec 14 '18 at 01:51