Skip to content

Commit 95ec23f

Browse files
author
zhangrongfan
committed
Refactor mybatisboost.json
1 parent 77031d9 commit 95ec23f

File tree

7 files changed

+75
-48
lines changed

7 files changed

+75
-48
lines changed

mybatis-boost-core/src/main/java/cn/mybatisboost/json/JsonResultSetsHandler.java

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,45 @@
11
package cn.mybatisboost.json;
22

3+
import cn.mybatisboost.util.ReflectionUtils;
4+
import cn.mybatisboost.util.function.UncheckedFunction;
35
import org.apache.ibatis.executor.resultset.ResultSetHandler;
46
import org.apache.ibatis.plugin.*;
57

68
import java.lang.reflect.Field;
7-
import java.lang.reflect.ParameterizedType;
89
import java.sql.Statement;
9-
import java.util.*;
10+
import java.util.List;
11+
import java.util.Properties;
1012
import java.util.concurrent.ConcurrentHashMap;
1113
import java.util.concurrent.ConcurrentMap;
12-
import java.util.stream.Collectors;
1314

1415
@Intercepts(@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = Statement.class))
1516
public class JsonResultSetsHandler implements Interceptor {
1617

17-
private ConcurrentMap<Class<?>, List<Field>> fieldCache = new ConcurrentHashMap<>();
18+
private ConcurrentMap<String, Field> fieldCache = new ConcurrentHashMap<>();
1819

1920
@Override
2021
public Object intercept(Invocation invocation) throws Throwable {
21-
List<?> proceed = (List<?>) invocation.proceed();
22-
if (proceed.isEmpty()) return proceed;
23-
24-
Class<?> type = proceed.get(0).getClass();
25-
List<Field> fields = fieldCache.computeIfAbsent(type,
26-
key -> Collections.unmodifiableList(Arrays.stream(type.getDeclaredFields())
27-
.filter(it -> it.getType() == Optional.class)
28-
.peek(it -> it.setAccessible(true)).collect(Collectors.toList())));
29-
if (fields.isEmpty()) return proceed;
30-
31-
for (Object object : proceed) {
32-
for (Field field : fields) {
33-
Object value = ((Optional<?>) field.get(object)).orElse(null);
34-
if (value instanceof String) {
35-
field.set(object, Optional.of(JsonTypeHandler.objectMapper.readValue((String) value,
36-
(Class<?>) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0])));
22+
try {
23+
List<?> proceed = (List<?>) invocation.proceed();
24+
List<String> properties = JsonTypeHandler.tlProperties.get();
25+
if (proceed.isEmpty() || properties.isEmpty()) return proceed;
26+
27+
Class<?> type = proceed.get(0).getClass();
28+
List<String> results = JsonTypeHandler.tlResults.get();
29+
for (int i = 0; i < results.size(); i++) {
30+
String content = results.get(i);
31+
if (content != null) {
32+
Field field = fieldCache.computeIfAbsent(properties.get(i % properties.size()),
33+
UncheckedFunction.of(key -> ReflectionUtils.makeAccessible(type.getDeclaredField(key))));
34+
field.set(proceed.get(i / properties.size()),
35+
JsonTypeHandler.objectMapper.readValue(content, field.getType()));
3736
}
3837
}
38+
return proceed;
39+
} finally {
40+
JsonTypeHandler.tlProperties.remove();
41+
JsonTypeHandler.tlResults.remove();
3942
}
40-
return proceed;
4143
}
4244

4345
@Override
Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,60 @@
11
package cn.mybatisboost.json;
22

3+
import cn.mybatisboost.support.Bean;
4+
import cn.mybatisboost.util.PropertyUtils;
35
import com.fasterxml.jackson.core.JsonProcessingException;
46
import com.fasterxml.jackson.databind.ObjectMapper;
57
import org.apache.ibatis.type.BaseTypeHandler;
68
import org.apache.ibatis.type.JdbcType;
79
import org.apache.ibatis.type.MappedTypes;
10+
import org.slf4j.Logger;
11+
import org.slf4j.LoggerFactory;
812

913
import java.sql.CallableStatement;
1014
import java.sql.PreparedStatement;
1115
import java.sql.ResultSet;
1216
import java.sql.SQLException;
13-
import java.util.Optional;
17+
import java.util.ArrayList;
18+
import java.util.List;
1419

15-
@MappedTypes(Optional.class)
16-
public class JsonTypeHandler extends BaseTypeHandler<Object> {
20+
@MappedTypes(Bean.class)
21+
public class JsonTypeHandler extends BaseTypeHandler<Bean> {
1722

23+
private static Logger logger = LoggerFactory.getLogger(JsonTypeHandler.class);
1824
static ObjectMapper objectMapper = new ObjectMapper().findAndRegisterModules();
25+
static ThreadLocal<List<String>> tlProperties = ThreadLocal.withInitial(ArrayList::new);
26+
static ThreadLocal<List<String>> tlResults = ThreadLocal.withInitial(ArrayList::new);
1927

2028
@Override
21-
public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType)
29+
public void setNonNullParameter(PreparedStatement ps, int i, Bean parameter, JdbcType jdbcType)
2230
throws SQLException {
2331
try {
24-
Optional<?> optional = (Optional<?>) parameter;
25-
if (optional.isPresent()) {
26-
ps.setString(i, objectMapper.writeValueAsString(optional.get()));
27-
} else {
28-
ps.setObject(i, null);
29-
}
32+
ps.setString(i, objectMapper.writeValueAsString(parameter));
3033
} catch (JsonProcessingException e) {
3134
throw new RuntimeException(e);
3235
}
3336
}
3437

3538
@Override
36-
public Object getNullableResult(ResultSet rs, String columnName) throws SQLException {
37-
return rs.getString(columnName);
39+
public Bean getNullableResult(ResultSet rs, String columnName) throws SQLException {
40+
List<String> resultNames = tlProperties.get();
41+
String property = PropertyUtils.normalizeProperty(columnName);
42+
if (!resultNames.contains(property)) {
43+
resultNames.add(property);
44+
}
45+
tlResults.get().add(rs.getString(columnName));
46+
return null;
3847
}
3948

4049
@Override
41-
public Object getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
42-
return rs.getString(columnIndex);
50+
public Bean getNullableResult(ResultSet rs, int columnIndex) {
51+
logger.warn("Json type is not supported when using CallableStatement");
52+
return null;
4353
}
4454

4555
@Override
46-
public Object getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
47-
return cs.getString(columnIndex);
56+
public Bean getNullableResult(CallableStatement cs, int columnIndex) {
57+
logger.warn("Json type is not supported when using CallableStatement");
58+
return null;
4859
}
4960
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package cn.mybatisboost.support;
2+
3+
public abstract class Bean {
4+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package cn.mybatisboost.util;
2+
3+
import java.lang.reflect.AccessibleObject;
4+
5+
public abstract class ReflectionUtils {
6+
7+
public static <T extends AccessibleObject> T makeAccessible(T accessibleObject) {
8+
accessibleObject.setAccessible(true);
9+
return accessibleObject;
10+
}
11+
}

mybatis-boost-test/src/main/java/cn/mybatisboost/test/Project.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package cn.mybatisboost.test;
22

3-
import java.util.Optional;
4-
53
public class Project {
64

75
private Integer id;
@@ -78,9 +76,8 @@ public Project setDeveloper(String developer) {
7876
return this;
7977
}
8078

81-
82-
public Optional<Website> getWebsite() {
83-
return Optional.ofNullable(website);
79+
public Website getWebsite() {
80+
return website;
8481
}
8582

8683
public void setWebsite(Website website) {

mybatis-boost-test/src/main/java/cn/mybatisboost/test/Website.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package cn.mybatisboost.test;
22

3-
public class Website {
3+
import cn.mybatisboost.support.Bean;
4+
5+
public class Website extends Bean {
46

57
private String protocol;
68
private String host;

mybatis-boost-test/src/test/java/cn/mybatisboost/test/JsonTest.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public class JsonTest {
2222
private ProjectMapper mapper;
2323
@Autowired
2424
private JdbcTemplate jdbcTemplate;
25-
private ObjectMapper objectMapper = new ObjectMapper().findAndRegisterModules();
25+
private ObjectMapper objectMapper = new ObjectMapper().findAndRegisterModules().enableDefaultTyping();
2626

2727
@After
2828
public void tearDown() {
@@ -37,7 +37,7 @@ public void testSave() {
3737
mapper.insert(project);
3838
jdbcTemplate.query("select * from project", resultSet -> {
3939
try {
40-
assertEquals(objectMapper.writeValueAsString(project.getWebsite().get()), resultSet.getString("website"));
40+
assertEquals(objectMapper.writeValueAsString(project.getWebsite()), resultSet.getString("website"));
4141
} catch (JsonProcessingException e) {
4242
fail();
4343
}
@@ -52,8 +52,8 @@ public void testQuery() throws Exception {
5252
jdbcTemplate.execute("insert into project (id, group_id, website) values (999, 'cn.mybatisboost', '" + objectMapper.writeValueAsString(project.getWebsite()) + "')");
5353
project = mapper.selectById(999);
5454
assertNotNull(project);
55-
assertEquals("HTTPS", project.getWebsite().get().getProtocol());
56-
assertEquals("mybatisboost.cn", project.getWebsite().get().getHost());
57-
assertEquals(80, project.getWebsite().get().getPort());
55+
assertEquals("HTTPS", project.getWebsite().getProtocol());
56+
assertEquals("mybatisboost.cn", project.getWebsite().getHost());
57+
assertEquals(80, project.getWebsite().getPort());
5858
}
5959
}

0 commit comments

Comments
 (0)