こうなってくると永続化層のMyBatisにもインターフェイスを返して欲しくなります。
しかし、MyBatisは初期状態ではデフォルトコンストラクタがないクラスには対応していません。
ObjectFactoryの実装とバインド
この問題を解決するには、ObjectFactoryを実装し、MyBatisModule#bindObjectFactoryTypeメソッドでバインドします。
ObjectFactoryへProviderを注入
せっかくGuiceを採用しているのですから、ObjectFactoryへProviderを注入し、オブジェクトの生成を委譲しましょう。
実装したものが次のクラスです。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package myamamoto.sample.mapper; | |
import myamamoto.sample.bean.Person; | |
import org.apache.ibatis.reflection.factory.DefaultObjectFactory; | |
import com.google.inject.Inject; | |
import com.google.inject.Provider; | |
class BeanObjectFactory extends DefaultObjectFactory { | |
private static final long serialVersionUID = 1L; | |
private Provider<Person> personProvider; | |
@Inject | |
BeanObjectFactory(Provider<Person> personProvider) { | |
this.personProvider = personProvider; | |
} | |
@Override | |
public Object create(@SuppressWarnings("rawtypes") Class type) { | |
if(Person.class == type){ | |
return this.personProvider.get(); | |
} | |
return super.create(type); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package myamamoto.sample; | |
import java.util.List; | |
import myamamoto.sample.bean.BeanModule; | |
import myamamoto.sample.bean.Person; | |
import myamamoto.sample.mapper.MapperModule; | |
import myamamoto.sample.mapper.PersonMapper; | |
import com.google.inject.Guice; | |
import com.google.inject.Injector; | |
import com.google.inject.Provider; | |
public class App | |
{ | |
public static void main( String[] args ) | |
{ | |
Injector injector = Guice.createInjector(new MapperModule(), new BeanModule()); | |
Provider<Person> personProvider = injector.getProvider(Person.class); | |
PersonMapper personMapper = injector.getInstance(PersonMapper.class); | |
try{ | |
personMapper.create(); | |
Person person = personProvider.get(); | |
person.setName("myamamoto0417"); | |
person.setAge(29); | |
personMapper.insert(person); | |
List<Person> persons = personMapper.select(); | |
for(Person p: persons){ | |
System.out.println("name: " + p.getName()); | |
System.out.println("age: " + p.getAge()); | |
} | |
}catch(Exception e){ | |
e.printStackTrace(); | |
}finally{ | |
personMapper.drop(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package myamamoto.sample.bean; | |
import java.io.Serializable; | |
import java.lang.reflect.InvocationHandler; | |
import java.lang.reflect.Method; | |
import java.lang.reflect.Proxy; | |
import java.util.HashMap; | |
import java.util.Map; | |
class BeanInvocationHandler implements InvocationHandler, Serializable { | |
private static final long serialVersionUID = 1L; | |
private final Map<String, Object> map = new HashMap<String, Object>(); | |
public Object invoke(Object proxy, Method method, Object[] args) | |
throws Throwable { | |
if(this.isCopyTo(method)){ | |
this.invokeCopyTo(method, args); | |
return null; | |
} | |
if(this.isGetter(method)){ | |
return this.invokeGetter(method); | |
} | |
if(this.isSetter(method)){ | |
this.invokeSetter(method, args); | |
return null; | |
} | |
return null; | |
} | |
private void invokeCopyTo(Method method, Object[] args) { | |
InvocationHandler h = Proxy.getInvocationHandler(args[0]); | |
if(!(h instanceof BeanInvocationHandler)){ | |
throw new IllegalArgumentException(); | |
} | |
BeanInvocationHandler handler = (BeanInvocationHandler) h; | |
handler.map.putAll(this.map); | |
} | |
private Object invokeGetter(Method method) { | |
String property = this.getPropertyName(method); | |
return this.map.get(property); | |
} | |
private void invokeSetter(Method method, Object[] args) { | |
String property = this.getPropertyName(method); | |
this.map.put(property, args[0]); | |
} | |
private boolean isCopyTo(Method method) { | |
return "copyTo".equals(method.getName()); | |
} | |
private boolean isGetter(Method method) { | |
return method.getName().startsWith("get"); | |
} | |
private boolean isSetter(Method method) { | |
return method.getName().startsWith("set"); | |
} | |
private String getPropertyName(Method method){ | |
String methodName = method.getName(); | |
return methodName.replaceAll("^get", "").replaceAll("^set", "").toLowerCase(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package myamamoto.sample.bean; | |
import com.google.inject.AbstractModule; | |
public class BeanModule extends AbstractModule { | |
@Override | |
protected void configure() { | |
bind(Person.class).toProvider(PersonProvider.class); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package myamamoto.sample.mapper; | |
import myamamoto.sample.bean.Person; | |
import org.apache.ibatis.reflection.factory.DefaultObjectFactory; | |
import com.google.inject.Inject; | |
import com.google.inject.Provider; | |
class BeanObjectFactory extends DefaultObjectFactory { | |
private static final long serialVersionUID = 1L; | |
private Provider<Person> personProvider; | |
@Inject | |
BeanObjectFactory(Provider<Person> personProvider) { | |
this.personProvider = personProvider; | |
} | |
@Override | |
public Object create(@SuppressWarnings("rawtypes") Class type) { | |
if(Person.class == type){ | |
return this.personProvider.get(); | |
} | |
return super.create(type); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package myamamoto.sample.mapper; | |
import java.util.Properties; | |
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory; | |
import org.mybatis.guice.MyBatisModule; | |
import org.mybatis.guice.datasource.builtin.UnpooledDataSourceProvider; | |
import org.mybatis.guice.datasource.helper.JdbcHelper; | |
import com.google.inject.name.Names; | |
public class MapperModule extends MyBatisModule { | |
@Override | |
protected void initialize() { | |
install(JdbcHelper.H2_IN_MEMORY_PRIVATE); | |
bindTransactionFactoryType(JdbcTransactionFactory.class); | |
bindDataSourceProviderType(UnpooledDataSourceProvider.class); | |
bindObjectFactoryType(BeanObjectFactory.class); | |
Properties properties = new Properties(); | |
properties.setProperty("mybatis.environment.id", "sample"); | |
properties.setProperty("JDBC.username", ""); | |
properties.setProperty("JDBC.password", ""); | |
Names.bindProperties(binder(), properties); | |
addMapperClass(PersonMapper.class); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package myamamoto.sample.bean; | |
public interface Person { | |
String getName(); | |
void setName(String name); | |
Integer getAge(); | |
void setAge(Integer age); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package myamamoto.sample.mapper; | |
import java.util.List; | |
import myamamoto.sample.bean.Person; | |
import org.apache.ibatis.annotations.Select; | |
import org.apache.ibatis.annotations.Update; | |
public interface PersonMapper { | |
static final String CREATE_SQL = | |
"CREATE TABLE person(name VARCHAR, age INTEGER)"; | |
@Update(CREATE_SQL) | |
void create(); | |
static final String INSERT_SQL = | |
"INSERT INTO person VALUES(#{name}, #{age})"; | |
@Update(INSERT_SQL) | |
int insert(Person person); | |
static final String SELECT_SQL = | |
"SELECT name, age FROM person"; | |
@Select(SELECT_SQL) | |
List<Person> select(); | |
static final String DROP_SQL = | |
"DROP TABLE person"; | |
@Update(DROP_SQL) | |
void drop(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package myamamoto.sample.bean; | |
import java.lang.reflect.Proxy; | |
import com.google.inject.Provider; | |
class PersonProvider implements Provider<Person> { | |
public Person get() { | |
return (Person) Proxy.newProxyInstance( | |
Person.class.getClassLoader(), | |
new Class[]{Person.class}, | |
new BeanInvocationHandler()); | |
} | |
} |
0 件のコメント:
コメントを投稿