Skip to content

Instantly share code, notes, and snippets.

@criminy
Created October 5, 2011 01:01
Show Gist options
  • Star 13 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save criminy/1263330 to your computer and use it in GitHub Desktop.
Save criminy/1263330 to your computer and use it in GitHub Desktop.
Initial MyBatis support for Spring-Data (specifically a sample repository and Pagination).
import java.util.Collection;
import java.util.List;
import java.util.ListIterator;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
/**
* Extension class between spring data commons and java.util.List that is
* required to get MyBatis to use it as a return value.
*
* The list section is all undefined.
*
* @author sheenobu
*
* @param <T> The Type of the contained entity.
*/
public class PageI<T> extends PageImpl<T> implements List<T> {
public PageI(List<T> content) {
super(content);
}
public PageI(List<T> content,Pageable pageable, int total) {
super(content,pageable,total);
}
private static final long serialVersionUID = 1L;
@Override
public boolean add(T e) {
throw new UnsupportedOperationException();
}
@Override
public void add(int index, T element) {
throw new UnsupportedOperationException();
}
@Override
public boolean addAll(Collection<? extends T> c) {
throw new UnsupportedOperationException();
}
@Override
public boolean addAll(int index, Collection<? extends T> c) {
throw new UnsupportedOperationException();
}
@Override
public void clear() {
throw new UnsupportedOperationException();
}
@Override
public boolean contains(Object o) {
throw new UnsupportedOperationException();
}
@Override
public boolean containsAll(Collection<?> c) {
throw new UnsupportedOperationException();
}
@Override
public T get(int index) {
throw new UnsupportedOperationException();
}
@Override
public int indexOf(Object o) {
throw new UnsupportedOperationException();
}
@Override
public boolean isEmpty() {
throw new UnsupportedOperationException();
}
@Override
public int lastIndexOf(Object o) {
throw new UnsupportedOperationException();
}
@Override
public ListIterator<T> listIterator() {
throw new UnsupportedOperationException();
}
@Override
public ListIterator<T> listIterator(int index) {
throw new UnsupportedOperationException();
}
@Override
public boolean remove(Object o) {
throw new UnsupportedOperationException();
}
@Override
public T remove(int index) {
throw new UnsupportedOperationException();
}
@Override
public boolean removeAll(Collection<?> c) {
throw new UnsupportedOperationException();
}
@Override
public boolean retainAll(Collection<?> c) {
throw new UnsupportedOperationException();
}
@Override
public T set(int index, T element) {
throw new UnsupportedOperationException();
}
@Override
public int size() {
throw new UnsupportedOperationException();
}
@Override
public List<T> subList(int fromIndex, int toIndex) {
throw new UnsupportedOperationException();
}
@Override
public Object[] toArray() {
throw new UnsupportedOperationException();
}
@Override
public <T> T[] toArray(T[] a) {
throw new UnsupportedOperationException();
}
}
import java.io.Serializable;
public class Person implements Serializable{
private static final long serialVersionUID = 1L;
private String firstName;
private String lastName;
private String id;
private String username;
private String password;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
import java.util.List;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.CrudRepository;
public interface PersonRepository extends CrudRepository<Person,String> {
//all listed are implemented YaY.
@Override
public long count();
@Override
public List<Person> findAll();
@Override
public Person findOne(String id);
public PageI<Person> findAll(Pageable page);
}
<?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="PersonRepository">
<select id="findAll" resultType="Person" parameterType="org.springframework.data.domain.Pageable" >
SELECT
uuid,
firstName,
lastName,
userID as username,
password
from person
<!-- TODO: USE if and foreach for sorting and pagination -->
</select>
<select id="findOne" resultType="Person" parameterType="String">
SELECT
uuid,
firstName,
lastName,
userID as username,
password
from person
where
uuid = #{id}
</select>
<select id="count" resultType="int">
SELECT
count(*)
from person
</select>
</mapper>
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.List;
import java.util.Properties;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.springframework.data.domain.Pageable;
/**
* MyBatis plugin which allows functions of the form
*
* : {@link PageI}<T> someFunction(...,{@link Pageable} pageable,...)
*
* to work properly using spring-datas {@link Pageable} and {@link Page} interfaces.
*
* @author sheenobu
*
*/
//ISSUE 1: bad query transformation.
//ISSUE 2: The function must use PageI instead of Page, otherwise mybatis will choke.
@Intercepts({ @Signature(type = Executor.class, method = "query", args =
{ MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class } )})
public class SpringDataMyBatisPlugin implements Interceptor {
@Override
public Object intercept(Invocation arg0) throws Throwable {
boolean pageable = false;
Pageable pageableObject = null;
MappedStatement stmt = null;
for(Object o : arg0.getArgs())
{
if(o != null)
{
if(Pageable.class.isAssignableFrom(o.getClass())) {
pageable = true;
pageableObject = (Pageable) o;
}
if(o instanceof MappedStatement)
{
stmt = (MappedStatement)o;
}
}
}
Object ret = arg0.proceed();
if(pageable && pageableObject != null && stmt != null) {
int total = -1;
Executor exec = (Executor) arg0.getTarget();
Statement sqlstmt = exec.getTransaction().getConnection().createStatement();
// This is a bit shady. I might want to replace it by finding a similar function on the same
// mapper. For example: FunctionA => countOfFunctionA
//Convert the select ... from ... statement to a count statement.
//TODO: remove paginating LIMITS and such.
ResultSet s = sqlstmt.executeQuery(stmt.getSqlSource().getBoundSql(null).getSql().replace('\n', ' ')
.replaceFirst("[S|s][E|e][L|l][E|e][C|c][T\t]\\s+.*[F|f][R|r][O|o][M|m]","SELECT count(*) from "));
s.next();
total = s.getShort(1);
PageI<?> pi = new PageI<Object>((List)ret, pageableObject,total);
return pi;
}
return ret;
}
@Override
public Object plugin(Object arg0) {
return Plugin.wrap(arg0,(Interceptor) this);
}
@Override
public void setProperties(Properties arg0) {
}
}
@kopax
Copy link

kopax commented Oct 31, 2016

Is this still working with spring boot 1.4 and mybatis 3.4.1 ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment