Re: Does mybatis support mapper extend?

2,987 views
Skip to first unread message

Eduardo Macarron

unread,
Apr 27, 2013, 12:38:32 PM4/27/13
to mybatis-user
Hi Jerry,

Current version does not have that option.

Let me try to explain how inheritance works.

interface Parent {
@select()
annotatedParentMethod();
xmlParentMethod();
}

interface Child extends parent {
}

When loading the Child type MyBatis does two things:
- Creates a new mapped statement called "Child.annotatedParentMethod"
- Searches for Child.xml and loads the statemens of the Child namespace

When executing MyBatis gets the id of the statement by concatenating
the name of the mapper and the called method. So if you call
annotatedParentMethod on Child it will execute the statement name
"Child.annotatedParentMethod"

Note that when using annotations there is no need to load the Parent
to use the method annotatedParentMethod. In fact, if the parent is
loaded a new mapped statement called Parent.annotatedParentMethod will
be created. (with the same exact content than
Child.annotatedParentMethod())

Probably we could change the way MyBatis gets the id of the statement:
- try with self name and method name (Child.xmlParentMethod) (this is
already being done)
- If not found, then try with method.getDeclaringClass().getName()
(Parent.xmlParentMethod)

Unlike with annotated methods, with xml you have to load the Parent
type (or the Parent.xml) so that MyBatis creates the
Parent.xmlParentMethod statement.

Paul Krause

unread,
May 1, 2013, 5:34:41 PM5/1/13
to mybati...@googlegroups.com


On Saturday, April 27, 2013 12:38:32 PM UTC-4, Eduardo wrote:
Probably we could change the way MyBatis gets the id of the statement:
- try with self name and method name (Child.xmlParentMethod) (this is
already being done)
- If not found, then try with method.getDeclaringClass().getName()
(Parent.xmlParentMethod)


That would be very nice to have.  Adding methods to an interface generated by MyBatis Generator is problematic right now.  Either you have to edit the generated XML or add the methods to a super-interface using annotations. 

Eduardo Macarron

unread,
May 2, 2013, 12:35:57 AM5/2/13
to mybatis-user
It is already in the snapshot Paul. Could you give it a try?

Details are in https://github.com/mybatis/mybatis-3/issues/35

2013/5/1 Paul Krause <paulkr...@alum.mit.edu>:
> --
> 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.
>
>

Paul Krause

unread,
May 6, 2013, 6:29:05 PM5/6/13
to mybati...@googlegroups.com
I am having trouble resolving fragments.  I suspect the problem is that MySuperMapper.xml contains references to fragments defined in MyMapper.xml, but MySuperMapper.xml is parsed first, since the MyMapper interface extends MySuperMapper.

Exception in thread "main" org.apache.ibatis.builder.IncompleteElementException: Could not find SQL statement to include with refid 'mypackage.MySuperMapper.myFragment'
at org.apache.ibatis.builder.xml.XMLIncludeTransformer.findSqlFragment(XMLIncludeTransformer.java:62)
at org.apache.ibatis.builder.xml.XMLIncludeTransformer.applyIncludes(XMLIncludeTransformer.java:37)
at org.apache.ibatis.builder.xml.XMLIncludeTransformer.applyIncludes(XMLIncludeTransformer.java:50)
at org.apache.ibatis.builder.xml.XMLStatementBuilder.parseStatementNode(XMLStatementBuilder.java:83)
at org.apache.ibatis.session.Configuration.buildAllStatements(Configuration.java:697)
at org.apache.ibatis.session.Configuration.hasStatement(Configuration.java:667)
at org.apache.ibatis.session.Configuration.hasStatement(Configuration.java:662)
at org.apache.ibatis.binding.MapperMethod$SqlCommand.<init>(MapperMethod.java:175)
at org.apache.ibatis.binding.MapperMethod.<init>(MapperMethod.java:38)
at org.apache.ibatis.binding.MapperProxy.cachedMapperMethod(MapperProxy.java:49)
at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:42)
at com.sun.proxy.$Proxy31.selectAll(Unknown Source)
Caused by: java.lang.IllegalArgumentException: XML fragments parsed from previous mappers does not contain value for mypackage.MySuperMapper.myFragment
at org.apache.ibatis.session.Configuration$StrictMap.get(Configuration.java:790)
at org.apache.ibatis.builder.xml.XMLIncludeTransformer.findSqlFragment(XMLIncludeTransformer.java:58)
... 15 more

Apparently, "XML fragments parsed from previous mappers" is the name of the StrictMap.

Paul Krause

unread,
May 6, 2013, 7:01:45 PM5/6/13
to mybati...@googlegroups.com
There's a worse problem.  I moved the XML back into the generated file, and now the statement ids from the super interface are not found.

org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): mypackage.MyMapper.selectByMyCustomId
at org.apache.ibatis.binding.MapperMethod$SqlCommand.<init>(MapperMethod.java:184) ~[mybatis-3.2.3-SNAPSHOT.jar:3.2.3-SNAPSHOT]
at org.apache.ibatis.binding.MapperMethod.<init>(MapperMethod.java:38) ~[mybatis-3.2.3-SNAPSHOT.jar:3.2.3-SNAPSHOT]
at org.apache.ibatis.binding.MapperProxy.cachedMapperMethod(MapperProxy.java:49) ~[mybatis-3.2.3-SNAPSHOT.jar:3.2.3-SNAPSHOT]
at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:42) ~[mybatis-3.2.3-SNAPSHOT.jar:3.2.3-SNAPSHOT]
at com.sun.proxy.$Proxy29.selectBySourceId(Unknown Source) ~[na:na]

Eduardo Macarron

unread,
May 7, 2013, 11:40:12 AM5/7/13
to mybati...@googlegroups.com
Not sure why this happens. When you call a mapper for the first time
all xml includes should be resolved. It does not matter the order, the
xml parser supports definiting xml out of order.

Seems that "mypackage.MySuperMapper.myFragment" cannot be found.

How can I help? Can you preproduce it in a test?

Paul Krause

unread,
May 7, 2013, 12:29:01 PM5/7/13
to mybati...@googlegroups.com
I'll see if I can extend the test you made for this new feature.  Where is it?

Eduardo Macarron

unread,
May 7, 2013, 12:52:08 PM5/7/13
to mybati...@googlegroups.com
That would be great. You can find them at
src/test/java/org/apache/ibatis/submitted/mapper_extend/

2013/5/7 Paul Krause <paulkr...@alum.mit.edu>:

Paul Krause

unread,
May 9, 2013, 12:05:05 PM5/9/13
to mybati...@googlegroups.com
Weird.  I added 3 new tests and they all pass.

Eduardo Macarron

unread,
May 9, 2013, 1:25:03 PM5/9/13
to mybati...@googlegroups.com
Bad news...

Maybe you can set a breakpoint in MapperMethod and have a look at what
is in configuration (and why mypackage.MyMapper.selectByMyCustomId is
not there).

Maybe this lets you know how to reproduce the issue.

hengch...@gmail.com

unread,
Dec 4, 2014, 4:42:58 AM12/4/14
to mybati...@googlegroups.com
#Child Dao
-------------------------------------------------
package com.self.app.dao;

import com.self.app.dto.ContentDto;

public interface ContentDao extends ContentDtoMapper {
 
ContentDto getC();
}
-------------------------------------------------

#Child xml
-------------------------------------------------
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.self.app.dao.ContentDao">
<resultMap id="ResultMap" type="com.self.app.dto.ContentDto" extends="com.self.app.dao.ContentDtoMapper.BaseResultMap" />
 
<select id="getC" resultMap="ResultMap">
select * from content where id=1
</select>

</mapper>
-------------------------------------------------

On Thursday, April 25, 2013 11:48:34 AM UTC+8, Jerry Huang wrote:
For example, I write two mappers.

CommonDemoMapper.java

public interface CommonFooMapper {
  Foo find(String id);
  List<Foo> findAll();
}

CommonDemoMapper.xml

... (define find  select and findAll select)

ExtendDemoMapper.java

public interface ExtendDemoMapper extends CommonFooMapper {
  List<Foo> findByBar(String bar);
}

ExtendDemoMapper.xml

... (define findByBar select)

Now I can use all the methods by ExtendDemoMapper.java.
But, the mapper's xml can be extended too? Thanks!

Reply all
Reply to author
Forward
0 new messages