Im use myBatis for work with myMysql. I have several identical tables (actors, producers, composers end etc..) that contain only two fields - id and name.
I have to write a lot of almost identical code to work with this. For example mapper
<?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="ru.common.mapper.NamedEntityMapper">
<resultMap id="actor" type="Actor">
<id property="id" column="id"/>
<result property="name" column="name"/>
</resultMap>
<select id="getActorByName" parameterType="String" resultMap="actor">
SELECT * FROM actors WHERE name = #{name}
</select>
<select id="getActorById" parameterType="String" resultMap="actor">
SELECT * FROM actors WHERE id = #{id}
</select>
<insert id="saveActor" useGeneratedKeys="true" parameterType="Actor" keyProperty="id">
INSERT INTO actors (name) VALUES (#{name})
</insert>
<resultMap id="writer" type="Writer">
<id property="id" column="id"/>
<result property="name" column="name"/>
</resultMap>
<select id="getWriterByName" parameterType="String" resultMap="writer">
SELECT * FROM writers WHERE name = #{name}
</select>
<select id="getWriterById" parameterType="String" resultMap="writer">
SELECT * FROM writers WHERE id = #{id}
</select>
<insert id="saveWriter" useGeneratedKeys="true" parameterType="Writer" keyProperty="id">
INSERT INTO writers (name) VALUES (#{name})
</insert>
</mapper>
As can be seen in the mapper, very similar methods and queries that differ only in the name of the table and the type being returned. In reality, there are more such methods and it looks awful.
And it is a interface
public interface NamedEntityMapper {
Actor getActorById(long id);
Actor getActorByName(String name);
void saveActor(Actor actor);
Writer getWriterById(long id);
Writer getWriterByName(String name);
void saveWriter(Writer writer);
}
I tried to do it like this, I made a common interface for each similar model. (BaseModel)
public interface BaseModel {
int getId();
void setId(int id);
String getName();
void setName(String name);
}
And implemented this interface in all models used like Actor...
But this led to failure because it is not clear how to explain to the mapper to create an instance of the desired class. How to transfer type which needs to be created in a xml mapper?
Something like that
public interface NamedEntityMapper<T extends BaseModel> {
T getEntityById(long id, String tableName, Class clazz);
}
and xml mapper
<mapper namespace="ru.common.mapper.NamedEntityMapper">
<resultMap id="entity" type="${clazz}">
<id property="id" column="id"/>
<result property="name" column="name"/>
</resultMap>
<select id="getEntityById" parameterType="String" resultMap="entity">
SELECT * FROM ${tableName} WHERE id = #{id}
</select>
</mapper>
But I could not pass the return type as a parameter to the mapper. This can be done ? This will allow to remove a lot of duplicate code in my case.