schan
schan

Reputation: 41

How do I use an XML ResultMap in an annotated mapper for MyBatis Dynamic SQL?

I am trying to use MyBatis Dynamic SQL for my application, and am running into some problems when following the guidelines on how to use the XML mapper together with the annotated mapper, as described in the "XML Mapper for Join Statements" on this page.

I am trying to get the following query to work:

SessionMapper mapper = sqlSession.getMapper(SessionMapper.class);
SessionTableSupport sessionMaster = new SessionTableSupport();

SelectStatementProvider stmt = select(
        sessionMaster.sessionId,
        sessionMaster.module,
        sessionMaster.startTime,
        sessionMaster.endTime,
        sessionMaster.eventId,
        sessionMaster.userId)
        .from(sessionMaster.sessionTable)
        .where(sessionMaster.module, isEqualTo("sample_module"))
        .build()
        .render(RenderingStrategy.MYBATIS3);

List<SessionResult> sampleSessions = mapper.selectMany(stmt);

For your reference, the config file looks something like this:

<configuration>
    <settings> ... </settings>
    <environments> ... </environments>
    <mappers>
        <mapper resource="./mappers/SessionResultMapper.xml"/>
        <package name="mappers"/>
    </mappers>
</configuration>

Then, here is my xml mapper SessionResultMapper.xml:

<mapper namespace="SessionResultMapper">
    <resultMap id="SimpleResults" type="results.SessionResult">
        <id column="session_id" jdbcType="VARCHAR" property="sessionId" />
        <result column="module" jdbcType="VARCHAR" property="module" />
        <result column="start_time" jdbcType="BIGINT" property="startTime" />
        <result column="end_time" jdbcType="BIGINT" property="endTime" />
        <result column="event_id" jdbcType="INTEGER" property="eventId" />
        <result column="user_id" jdbcType="VARCHAR" property="userId" />
        <result column="institute" jdbcType="VARCHAR" property="institute" />
    </resultMap>
</mapper>

Here's the annotated mapper interface SessionMapper.java:

@Mapper
public interface SessionMapper {
    @SelectProvider(type=SqlProviderAdapter.class, method="select")
    @ResultMap("SimpleResults")
    List<SessionResult> selectMany(SelectStatementProvider selectStatement);
}

And finally, here's SessionResult.java:

public class SessionResult {

    private String sessionId;
    private String module;
    private long startTime;
    private long endTime;
    private int eventId;
    private String userId;
    private String institute;

    public SessionResult(
            String sessionId,
            String module,
            long startTime, 
            long endTime,
            int eventId, 
            String userId, 
            String institute) {

        super();
        this.sessionId = sessionId;
        this.module = module;
        this.startTime = startTime;
        this.endTime = endTime;
        this.eventId = eventId;
        this.userId = userId;
        this.institute = institute;
    }

    public SessionResult() {}

    // Getters and Setters
    ...
}

When running the above using both xml and annotations, the following exception is thrown:

Exception in thread "main" org.apache.ibatis.builder.IncompleteElementException: Could not find result map mappers.SessionMapper.SimpleResults
    at org.apache.ibatis.builder.MapperBuilderAssistant.getStatementResultMaps(MapperBuilderAssistant.java:346)
    at org.apache.ibatis.builder.MapperBuilderAssistant.addMappedStatement(MapperBuilderAssistant.java:290)
    at org.apache.ibatis.builder.annotation.MapperAnnotationBuilder.parseStatement(MapperAnnotationBuilder.java:364)
    at org.apache.ibatis.builder.annotation.MethodResolver.resolve(MethodResolver.java:33)
    at org.apache.ibatis.session.Configuration.lambda$buildAllStatements$3(Configuration.java:795)
    at java.util.Collection.removeIf(Collection.java:414)
    at org.apache.ibatis.session.Configuration.buildAllStatements(Configuration.java:794)
    at org.apache.ibatis.session.Configuration.hasStatement(Configuration.java:763)
    at org.apache.ibatis.session.Configuration.hasStatement(Configuration.java:758)
    at org.apache.ibatis.binding.MapperMethod$SqlCommand.resolveMappedStatement(MapperMethod.java:254)
    at org.apache.ibatis.binding.MapperMethod$SqlCommand.<init>(MapperMethod.java:224)
    at org.apache.ibatis.binding.MapperMethod.<init>(MapperMethod.java:50)
    at org.apache.ibatis.binding.MapperProxy.lambda$cachedMapperMethod$0(MapperProxy.java:62)
    at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1660)
    at org.apache.ibatis.binding.MapperProxy.cachedMapperMethod(MapperProxy.java:62)
    at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:57)
    at com.sun.proxy.$Proxy5.selectMany(Unknown Source)
    at test.TestMyBatisDynamic.main(TestMyBatisDynamic.java:70)
Caused by: java.lang.IllegalArgumentException: Result Maps collection does not contain value for mappers.SessionMapper.SimpleResults
    at org.apache.ibatis.session.Configuration$StrictMap.get(Configuration.java:933)
    at org.apache.ibatis.session.Configuration.getResultMap(Configuration.java:645)
    at org.apache.ibatis.builder.MapperBuilderAssistant.getStatementResultMaps(MapperBuilderAssistant.java:344)
    ... 17 more

But when I use a purely annotated result map, everything works correctly. Unfortunately, I'm trying to build a more complicated result map with collections and associations, so using pure annotations does not seem to be an option.

I've tried my best to follow the examples in the documentation as closely as possible. I'm at a complete loss here... Does anyone have any idea how to fix this problem? Any help or tips will be greatly appreciated! Thank you for your time in advance!

Upvotes: 1

Views: 3102

Answers (1)

schan
schan

Reputation: 41

Thanks to a post in the comments, I've learned that there was a namespace conflict in my code. To fix it, I changed the xml and annotated mappers as follows:

SessionResultMapper.xml

<mapper namespace="SessionResultMapper">
    <resultMap id="SimpleResults" type="results.SessionResult">
        ...
    </resultMap>
</mapper>

and accordingly, in SessionMapper.java:

@ResultMap("SessionResultMapper.SimpleResults")

Basically, make sure the [namespace].[resultMap id] path is consistent between the xml and annotated mappers.

Upvotes: 1

Related Questions