Skip to content

Commit 6916377

Browse files
committed
Fn增加方法,当通过基类或基类泛型的字段引用时,可以指定所属的实体类 fixed#50
1 parent e2fc0e1 commit 6916377

File tree

6 files changed

+91
-27
lines changed

6 files changed

+91
-27
lines changed

README.md

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
项目文档: https://mapper.mybatis.io
99

10+
[加入QQ群: 277256950](https://qm.qq.com/cgi-bin/qm/qr?k=ks1Y2WVNI1xjsqMlBzAkWmBMuYqDhVqZ&jump_from=webapi&authKey=U0CL8SDMS4wsJ8H9njVcNMbOW6Gb9AsxLfFB4jbxSKa0w0ChBX3wCms0+Cjzhekw)
11+
1012
## 1. 快速入门
1113

1214
这是一个不需要任何配置就可以直接使用的通用 Mapper,通过简单的学习就可以直接在项目中使用。
@@ -61,11 +63,11 @@ MyBatis Mapper 要求 MyBatis 最低版本为
6163

6264
```groovy
6365
dependencies {
64-
compile("io.mybatis:mybatis-mapper:1.2.2")
65-
// 使用 Service 层封装时
66-
compile("io.mybatis:mybatis-service:1.2.2")
67-
// 使用 ActiveRecord 模式时
68-
compile("io.mybatis:mybatis-activerecord:1.2.2")
66+
compile("io.mybatis:mybatis-mapper:1.2.2")
67+
// 使用 Service 层封装时
68+
compile("io.mybatis:mybatis-service:1.2.2")
69+
// 使用 ActiveRecord 模式时
70+
compile("io.mybatis:mybatis-activerecord:1.2.2")
6971
}
7072
```
7173

@@ -83,9 +85,9 @@ MyBatis Mapper 的基本原理是将实体类映射为数据库中的表和字
8385
```sql
8486
create table user
8587
(
86-
id INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 1) PRIMARY KEY,
87-
name VARCHAR(32) DEFAULT 'DEFAULT',
88-
sex VARCHAR(2)
88+
id INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 1) PRIMARY KEY,
89+
name VARCHAR(32) DEFAULT 'DEFAULT',
90+
sex VARCHAR(2)
8991
);
9092
```
9193

@@ -160,11 +162,11 @@ public interface UserMapper extends Mapper<User, Long> {
160162
> @MapperScan(basePackages = "com.example.mapper")
161163
> @SpringBootApplication
162164
> public class SpringBootDemoApplication {
163-
>
165+
>
164166
> public static void main(String[] args) {
165167
> SpringApplication.run(SpringBootDemoApplication.class, args);
166168
> }
167-
>
169+
>
168170
> }
169171
> ```
170172
> Spring Boot 中,还可以直接给接口添加 `@org.apache.ibatis.annotations.Mapper` 注解,增加注解后可以省略 `@MapperScan` 配置。
@@ -222,4 +224,4 @@ WHERE (sex = ? AND ((id > ?) OR (id < ?)))
222224
- baseid 简单封装,所有表都使用名为 id,类型为 bigint 的自增主键
223225
- shardingsphere 分库分表,支持分库分表的代码生成,每个表有不同的id
224226

225-
通过示例项目可以结合代码生成器自动生成大部分代码,可以用于测试和学习 mybatis-mapper 中的功能。
227+
通过示例项目可以结合代码生成器自动生成大部分代码,可以用于测试和学习 mybatis-mapper 中的功能。

mapper/src/main/java/io/mybatis/mapper/BaseMapper.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ default ExampleWrapper<T, I> wrapper() {
7474
*/
7575
default <F> List<T> selectByFieldList(Fn<T, F> field, Collection<F> fieldValueList) {
7676
Example<T> example = new Example<>();
77-
example.createCriteria().andIn((Fn<T, Object>) field, fieldValueList);
77+
example.createCriteria().andIn((Fn<T, Object>) field.in(entityClass()), fieldValueList);
7878
return selectByExample(example);
7979
}
8080

@@ -90,7 +90,7 @@ default <F> List<T> selectByFieldList(Fn<T, F> field, Collection<F> fieldValueLi
9090
*/
9191
default <F> int deleteByFieldList(Fn<T, F> field, Collection<F> fieldValueList) {
9292
Example<T> example = new Example<>();
93-
example.createCriteria().andIn((Fn<T, Object>) field, fieldValueList);
93+
example.createCriteria().andIn((Fn<T, Object>) field.in(entityClass()), fieldValueList);
9494
return deleteByExample(example);
9595
}
9696

mapper/src/main/java/io/mybatis/mapper/fn/Fn.java

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,25 @@ public interface Fn<T, R> extends Function<T, R>, Serializable {
4141
*/
4242
Map<Fn, Reflections.ClassField> FN_CLASS_FIELD_MAP = new HashMap<>();
4343

44+
/**
45+
* 指定字段集合的虚拟表,当通过基类或者泛型基类获取字段时,需要设置字段所属的实体类
46+
*
47+
* @param entityClass 当使用基类获取泛型时,需要指定实体类类型
48+
* @param fns 指定字段
49+
* @return 虚拟表
50+
*/
51+
static <E> Fns<E> of(Class<E> entityClass, Fn<E, Object>... fns) {
52+
return new Fns<>(entityClass, fns);
53+
}
54+
4455
/**
4556
* 指定字段集合的虚拟表
4657
*
4758
* @param fns 指定字段
4859
* @return 虚拟表
4960
*/
5061
static <E> Fns<E> of(Fn<E, Object>... fns) {
51-
return new Fns<>(fns);
62+
return of(null, fns);
5263
}
5364

5465
/**
@@ -66,6 +77,17 @@ static <E> Fns<E> of(Class<E> entityClass, String... columnNames) {
6677
return new Fns<>(entityClass, entityTable.tableName(), columns);
6778
}
6879

80+
/**
81+
* 当前字段所属的实体类,当实体存在继承关系时
82+
* 父类的方法引用无法获取字段所属的实体类,需要通过该方法指定
83+
*
84+
* @param entityClass 指定实体类
85+
* @return 带有指定实体类的 Fn
86+
*/
87+
default Fn<T, R> in(Class<?> entityClass) {
88+
return new FnImpl<>(this, entityClass);
89+
}
90+
6991
/**
7092
* 转换为字段:获取方法引用对应的字段信息
7193
*
@@ -125,6 +147,26 @@ default EntityColumn toEntityColumn() {
125147
return FN_COLUMN_MAP.get(this);
126148
}
127149

150+
/**
151+
* 带有指定类型的方法引用
152+
*/
153+
class FnImpl<T, R> implements Fn<T, R> {
154+
155+
final Fn<T, R> fn;
156+
final Class<?> entityClass;
157+
158+
public FnImpl(Fn<T, R> fn, Class<?> entityClass) {
159+
this.fn = fn;
160+
this.entityClass = entityClass;
161+
}
162+
163+
@Override
164+
public R apply(T t) {
165+
return fn.apply(t);
166+
}
167+
168+
}
169+
128170
/**
129171
* 字段数组,用于获取字段对应的所有字段名和列名,当前对象相当于一个部分字段的虚拟表
130172
*
@@ -150,14 +192,19 @@ private Fns(Class<E> entityClass, String table, List<EntityColumn> columns) {
150192
*
151193
* @param fns 字段数组
152194
*/
153-
private Fns(Fn<E, Object>... fns) {
154-
super(null);
195+
private Fns(Class<E> entityClass, Fn<E, Object>... fns) {
196+
super(entityClass);
155197
this.columns = new ArrayList<>(fns.length);
156198
for (int i = 0; i < fns.length; i++) {
157-
this.columns.add(fns[i].toEntityColumn());
199+
if (entityClass != null) {
200+
this.columns.add(fns[i].in(entityClass).toEntityColumn());
201+
} else {
202+
this.columns.add(fns[i].toEntityColumn());
203+
}
158204
if (i == 0) {
159205
EntityTable entityTable = this.columns.get(i).entityTable();
160206
this.table = entityTable.tableName();
207+
this.style = entityTable.style();
161208
this.entityClass = entityTable.entityClass();
162209
this.resultMap = entityTable.resultMap();
163210
this.autoResultMap = entityTable.autoResultMap();

mapper/src/main/java/io/mybatis/mapper/fn/Reflections.java

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,15 @@ private Reflections() {
3838

3939
public static ClassField fnToFieldName(Fn fn) {
4040
try {
41+
Class<?> clazz = null;
42+
if (fn instanceof Fn.FnImpl) {
43+
clazz = ((Fn.FnImpl<?, ?>) fn).entityClass;
44+
fn = ((Fn.FnImpl<?, ?>) fn).fn;
45+
//避免嵌套多次的情况
46+
while (fn instanceof Fn.FnImpl) {
47+
fn = ((Fn.FnImpl<?, ?>) fn).fn;
48+
}
49+
}
4150
Method method = fn.getClass().getDeclaredMethod("writeReplace");
4251
method.setAccessible(Boolean.TRUE);
4352
SerializedLambda serializedLambda = (SerializedLambda) method.invoke(fn);
@@ -48,15 +57,17 @@ public static ClassField fnToFieldName(Fn fn) {
4857
getter = getter.substring(2);
4958
}
5059
String field = Introspector.decapitalize(getter);
51-
//主要是这里 serializedLambda.getInstantiatedMethodType()
52-
Matcher matcher = INSTANTIATED_CLASS_PATTERN.matcher(serializedLambda.getInstantiatedMethodType());
53-
String implClass;
54-
if (matcher.find()) {
55-
implClass = matcher.group("cls").replaceAll("/", "\\.");
56-
} else {
57-
implClass = serializedLambda.getImplClass().replaceAll("/", "\\.");
60+
if (clazz == null) {
61+
//主要是这里 serializedLambda.getInstantiatedMethodType()
62+
Matcher matcher = INSTANTIATED_CLASS_PATTERN.matcher(serializedLambda.getInstantiatedMethodType());
63+
String implClass;
64+
if (matcher.find()) {
65+
implClass = matcher.group("cls").replaceAll("/", "\\.");
66+
} else {
67+
implClass = serializedLambda.getImplClass().replaceAll("/", "\\.");
68+
}
69+
clazz = Class.forName(implClass);
5870
}
59-
Class<?> clazz = Class.forName(implClass);
6071
return new ClassField(clazz, field);
6172
} catch (ReflectiveOperationException e) {
6273
throw new RuntimeException(e);

service/src/test/java/io/mybatis/service/ServiceTest.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,9 +180,14 @@ public void testUserService() {
180180
Assert.assertEquals(3, userService.findList(user).size());
181181
user.setName("admin");
182182
Assert.assertTrue(userService.findOne(user) != null);
183+
}
184+
185+
@Test
186+
public void testIssues50() {
187+
UserService userService = context.getBean(UserService.class);
183188

184189
List<Integer> ids = new ArrayList<>();
185-
user = new User();
190+
User user = new User();
186191
userService.save(user);
187192
ids.add(user.getId());
188193
user = new User();

service/src/test/java/io/mybatis/service/model/BaseId.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818

1919
import io.mybatis.provider.Entity;
2020

21-
@Entity.Table
2221
public class BaseId<T extends BaseId> {
2322
@Entity.Column(id = true, insertable = false)
2423
private Integer id;

0 commit comments

Comments
 (0)