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

2 Answers 2

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>
Sign up to request clarification or add additional context in comments.

Comments

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.

2 Comments

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 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<String, Map<String, Object>> to Map<String, Integer> by Map<String, Integer> anotherMap = map.entrySet().stream() .collect(Collectors.toMap(Map.Entry::getKey, it -> (int)it.getValue().get("total")));

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.