MapperScan with XML mappers

619 views
Skip to first unread message

Christopher Clark

unread,
Dec 24, 2013, 1:28:34 PM12/24/13
to mybati...@googlegroups.com
Has anyone successfully used the @MapperScan annotation with XML mappers?

I am able to use @MapperScan if I annotate my mapper interfaces with annotations like @Select to specify the SQL.  However, I'd like to move the SQL into XML files.

I asked this question on StackOverflow which yielded one answer, but I was not able to get it to work.  Has anyone here had any success with this?

Thank you all,

Chris

Eduardo Macarron

unread,
Dec 26, 2013, 12:16:41 PM12/26/13
to mybati...@googlegroups.com
Hi. It searches for interfaces, so it does not matter if the statements are annotated or in an xml, mybatis will load the mapper in either cases.


2013/12/24 Christopher Clark <ludach...@gmail.com>

--
You received this message because you are subscribed to the Google Groups "mybatis-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mybatis-user...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Christopher Clark

unread,
Dec 27, 2013, 12:39:28 PM12/27/13
to mybati...@googlegroups.com
Thanks for your reply Eduardo. I'm entirely new to MyBatis, so perhaps this is
newbie stuff.

Indeed the Java Mapper interfaces are registered when the correct package is
scanned with @MapperScan. I should specify further: my problem is in binding the
Java Mapper interfaces to a peer XML mapper.

I see in the MyBatis documentation: "MyBatis will automatically look for and
load a peer XML file if it exists" with the same name as the Java Mapper
interface and located in the same package.

Unfortunately I couldn't get that working, so:

Looking for examples of such behavior, I had a look at the tests in the MyBatis
framework. However in the MyBatis tests I found (e.g. SqlSessionManagerTest),
the XML mappers are not automagically loaded, they are specified in a
<configuration> element in MapperConfig.xml. This makes me suspect that there is
some extra work one must do when setting up the SqlSession if one wants the
XML mappers to be bound to the Java mapper interfaces.

Currently I set up my SqlSessionFactory like this:

    @Autowired
    DataSource dataSource;

    @Bean
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(dataSource);
        return sessionFactory.getObject();
    }

This is sufficient if the Java Mappers have methods annotated with @Select
statements. Is there anything else that needs to be done to get MyBatis to bind
a Java Mapper interface to a peer XML mapper?

Or, could someone point me to the location in the MyBatis code that attempts to
load this peer XML? There is likely some fundamental concept of MyBatis that I,
as a beginner, simply don't know.

Thanks again,
Chris

Jose María Zaragoza

unread,
Dec 28, 2013, 3:44:49 AM12/28/13
to mybati...@googlegroups.com
2013/12/27 Christopher Clark <ludach...@gmail.com>:
> Thanks for your reply Eduardo. I'm entirely new to MyBatis, so perhaps this
> is
> newbie stuff.
>
> Indeed the Java Mapper interfaces are registered when the correct package is
> scanned with @MapperScan. I should specify further: my problem is in binding
> the
> Java Mapper interfaces to a peer XML mapper.
>
> I see in the MyBatis documentation: "MyBatis will automatically look for and
> load a peer XML file if it exists" with the same name as the Java Mapper
> interface and located in the same package.
>
> Unfortunately I couldn't get that working


1)

If you want to use Spring + MyBatis , I recommend you to use Spring IOC
I paste the code that I use


<!-- Enable autowire -->
<context:annotation-config />

<context:property-placeholder location="/WEB-INF/database.properties" />


<bean id="dataSource1" class="org.apache.tomcat.jdbc.pool.DataSource"
destroy-method="close">
<property name="driverClassName"
value="${database.driver}" />
<property name="url" value="${database.url}" />
<property name="username" value="${database.username}" />
<property name="password" value="${database.password}" />
<property name="maxActive" value="${database.maxactive}" />
<property name="maxWait" value="${database.maxwait}" />
<property name="maxIdle" value="${database.maxidle}" />
<property name="minIdle" value="${database.minidle}" />
<property name="initialSize" value="${database.initialsize}" />
<property name="removeAbandoned"
value="${database.removeabandoned}" />
<property name="validationQuery"
value="${database.validationquery}" />
<property name="testOnBorrow" value="true"/>
</bean>



<!-- Define the SqlSessionFactory, Notice that configLocation
is not needed when you use MapperFactoryBean -->
<bean id="sqlSessionFactory1"
class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource1" />
<property name="configLocation"
value="WEB-INF/sqlmap-config.xml" />
</bean>

<!-- Scan for mappers and let them be @Autowired -->

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage"
value="com.myapp.persistence.mapper.*"/>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory1"/>
</bean>


Have a look like mapper interfaces are registered into Spring context
with MapperScannerConfigurer , scanning in a basePackage


Now, in your class, you can inject (only) your mappers, like:

@Autowired
MyAppMapper myappMapper;

This mapper is thread-safe ( if I'm not wrong )


2)

If your mapper interfaces have all theirs methods annotated with
@Select annotations, you don't need any XML file
But. if they don't, XML files and mapper interfaces must be in the
same directory


I hope this help you
Regards

Eduardo Macarron

unread,
Dec 28, 2013, 5:13:14 AM12/28/13
to mybati...@googlegroups.com
Hi Christopher,

As the manual says: "MyBatis will automatically look for and
load a peer XML file if it exists" with the same name as the Java Mapper
interface and located in the same package.

It also has to have the name of the interface as a domain. This is very important (I recall there is a paragraph about that in the manual).

That is all. XML files are the alternative to annotations, so you must not use the @Select annotation in that case.

You have some tests in the mybatis and spring github projects. Look for BaseTest in MyBatis or "sample" in spring.


2013/12/28 Jose María Zaragoza <demab...@gmail.com>

Frank Martínez

unread,
Dec 29, 2013, 4:21:36 PM12/29/13
to mybati...@googlegroups.com
Hi,

What about just CDI??


:D Just propaganda of our new project :D

--
Frank D. Martínez M.

Christopher Clark

unread,
Jan 11, 2014, 10:33:53 AM1/11/14
to mybati...@googlegroups.com
It also has to have the name of the interface as a domain

Eduardo, I don't understand this statement, could you elaborate?

That is all

That can't be!  Not when using fully Java config and @MapperScan.  I've created a minimal working example to showcase this problem.  Please see: https://github.com/Ludachrispeed/mybatis-spring-mwe

Steps to see this problem:

1. Run `PersonServiceTest`. It passes.

2. Comment out the annotations in `PersonMapper.java`, and add the following file called `PersonMapper.xml` to src/main/resources/example/persistence/PersonMapper.xml:

    <!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    <mapper namespace="com.ludachrispeed.persistence.PersonMapper">
        <select id="getByFirstName" parameterType="string" resultType="Person">
            select * from PEOPLE where PEOPLE.FIRSTNAME = #{firstname}
        </select>
    </mapper>

3. Rerun PersonServiceTest. It fails.

Thus, there MUST BE some configuration needed when using XML mappers that IS NOT needed when using annotations.  Whatever configuration that is, I'm having a really hard time finding it.  Does anybody know?

Christopher Clark

unread,
Jan 11, 2014, 12:07:52 PM1/11/14
to mybati...@googlegroups.com
There's a typo in that XML document above (incorrect package name), but the problem still stands.  The github repo README has correct directions.

Eduardo Macarron

unread,
Jan 11, 2014, 12:21:54 PM1/11/14
to mybati...@googlegroups.com
Hi Chris. With some code this is much more easier.

Have a look at your repo, I sent a pull request with the changes.



2014/1/11 Christopher Clark <ludach...@gmail.com>

Christopher Clark

unread,
Jan 11, 2014, 12:41:14 PM1/11/14
to mybati...@googlegroups.com
Well that solves it :)  Fully qualify the resultType in the XML.  Well I feel about as smart as a bag of apples.

Thank you very much Eduardo!

Eduardo Macarron

unread,
Jan 11, 2014, 1:20:49 PM1/11/14
to mybati...@googlegroups.com
XD

Spring does not fail if the scanner throws an exception (like not finding the Person class). Do not know the reason but we can do no more than failing. 

Any failure is printed out to console but Spring makes neverending stacktraces and finding the root cause is often not trivial.

Anyway, good to know it works.


2014/1/11 Christopher Clark <ludach...@gmail.com>
Reply all
Reply to author
Forward
0 new messages