com.github.nomou.mybatis.builder.AnnotatedMapperSupport Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mybatis-smart Show documentation
Show all versions of mybatis-smart Show documentation
Mybatis-smart - a light mybatis mapper method implementation proxy
package com.github.nomou.mybatis.builder;
import com.github.nomou.mybatis.util.Collections2;
import org.apache.ibatis.annotations.Arg;
import org.apache.ibatis.annotations.CacheNamespace;
import org.apache.ibatis.annotations.CacheNamespaceRef;
import org.apache.ibatis.annotations.Case;
import org.apache.ibatis.annotations.ConstructorArgs;
import org.apache.ibatis.annotations.Many;
import org.apache.ibatis.annotations.One;
import org.apache.ibatis.annotations.Property;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.TypeDiscriminator;
import org.apache.ibatis.builder.BuilderException;
import org.apache.ibatis.builder.MapperBuilderAssistant;
import org.apache.ibatis.mapping.Discriminator;
import org.apache.ibatis.mapping.FetchType;
import org.apache.ibatis.mapping.ResultFlag;
import org.apache.ibatis.mapping.ResultMapping;
import org.apache.ibatis.parsing.PropertyParser;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;
import org.apache.ibatis.type.UnknownTypeHandler;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Properties;
/**
* TODO DOC ME!.
*
* @author changhe.yang
* @since 20191031
*/
public abstract class AnnotatedMapperSupport {
protected final MapperBuilderAssistant assistant;
/**
* @param assistant
*/
protected AnnotatedMapperSupport(final MapperBuilderAssistant assistant) {
this.assistant = assistant;
}
/**
* 配置给定的annotation缓存命名空间.
*
* @param cacheNs 缓存命名空间配置
* @see org.apache.ibatis.builder.annotation.MapperAnnotationBuilder#parseCache()
*/
protected void useCache(final CacheNamespace cacheNs) {
if (null != cacheNs) {
final Integer size = 0 != cacheNs.size() ? cacheNs.size() : null;
final Long flushInterval = 0 != cacheNs.flushInterval() ? cacheNs.flushInterval() : null;
final Properties props = toProperties(cacheNs.properties(), assistant.getConfiguration());
assistant.useNewCache(cacheNs.implementation(), cacheNs.eviction(), flushInterval, size, cacheNs.readWrite(), cacheNs.blocking(), props);
}
}
/**
* 配置给定的annotation缓存命名空间引用.
*
* @param cacheNsRef 缓存命名空间引用配置
* @see org.apache.ibatis.builder.annotation.MapperAnnotationBuilder#parseCacheRef()
*/
protected void useCacheRef(final CacheNamespaceRef cacheNsRef) {
if (null != cacheNsRef) {
final String refName = cacheNsRef.name();
final Class> refType = cacheNsRef.value();
if (void.class.equals(refType) && refName.isEmpty()) {
throw new BuilderException("Should be specified either value() or name() attribute in the @CacheNamespaceRef");
}
if (!void.class.equals(refType) && !refName.isEmpty()) {
throw new BuilderException("Cannot use both value() and name() attribute in the @CacheNamespaceRef");
}
final String namespace = !void.class.equals(refType) ? refType.getName() : refName;
assistant.useCacheRef(namespace);
}
}
/**
* 转换给定{@link Property} 转换为 properties.
*
* @param props 属性配置
* @param configuration 配置对象
* @return properties
* @see org.apache.ibatis.builder.annotation.MapperAnnotationBuilder#convertToProperties(Property[])
*/
protected Properties toProperties(final Property[] props, final Configuration configuration) {
if (0 < props.length) {
final Properties propsObj = new Properties();
for (final Property prop : props) {
propsObj.setProperty(prop.name(), PropertyParser.parse(prop.value(), configuration.getVariables()));
}
return propsObj;
} else {
return null;
}
}
protected String createResultMap(final String resultMapId, final Class> returnType,
final Results results, final ConstructorArgs args, final TypeDiscriminator discriminator) {
this.doCreateResultMap(
resultMapId, returnType,
null != args ? args.value() : new Arg[0],
null != results ? results.value() : new Result[0],
discriminator
);
return resultMapId;
}
private void doCreateResultMap(final String resultMapId, final Class> returnType,
final Arg[] args, final Result[] results, final TypeDiscriminator typeDiscriminator) {
final List mappings = new ArrayList();
Collections.addAll(mappings, createMappings(args, returnType));
Collections.addAll(mappings, createMappings(results, returnType));
final Discriminator discriminator = createDiscriminator(resultMapId, typeDiscriminator, returnType);
assistant.addResultMap(resultMapId, returnType, null, discriminator, mappings, null);
if (null != discriminator) {
for (final Case c : typeDiscriminator.cases()) {
final String caseResultMapId = resultMapId + "-" + c.value();
final List innerMappings = new ArrayList();
Collections.addAll(innerMappings, createMappings(args, returnType));
Collections.addAll(innerMappings, createMappings(results, returnType));
assistant.addResultMap(caseResultMapId, c.type(), resultMapId, null, innerMappings, null);
}
}
}
private ResultMapping[] createMappings(final Arg[] args, final Class> resultType) {
final ResultMapping[] mappings = new ResultMapping[args.length];
for (int i = 0; i < args.length; i++) {
mappings[i] = createMapping(args[i], resultType);
}
return mappings;
}
private ResultMapping[] createMappings(final Result[] results, final Class> resultType) {
final ResultMapping[] mappings = new ResultMapping[results.length];
for (int i = 0; i < results.length; i++) {
mappings[i] = createMapping(results[i], resultType);
}
return mappings;
}
private Discriminator createDiscriminator(final String resultMapId, final TypeDiscriminator discriminator, final Class> resultType) {
if (null != discriminator) {
final String column = discriminator.column();
final Class> javaType = determineJavaType(discriminator.javaType(), String.class);
final JdbcType jdbcType = determineJdbcType(discriminator.jdbcType(), null);
final Class extends TypeHandler>> typeHandler = determineTypeHandler(discriminator.typeHandler(), null);
final Map discriminatorMap = Collections2.newHashMap(16);
for (final Case c : discriminator.cases()) {
final String caseResultMapId = resultMapId + "-" + c.value();
discriminatorMap.put(c.value(), caseResultMapId);
}
return assistant.buildDiscriminator(resultType, column, javaType, jdbcType, typeHandler, discriminatorMap);
}
return null;
}
@SuppressWarnings("unchecked")
private ResultMapping createMapping(final Arg arg, final Class> resultType) {
final List flags = arg.id() ? Arrays.asList(ResultFlag.CONSTRUCTOR, ResultFlag.ID) : Collections.singletonList(ResultFlag.CONSTRUCTOR);
final Class extends TypeHandler>> typeHandler = determineTypeHandler(arg.typeHandler(), null);
final Class> javaType = determineJavaType(arg.javaType(), null);
final JdbcType jdbcType = !JdbcType.UNDEFINED.equals(arg.jdbcType()) ? arg.jdbcType() : null;
final String property = nullOrEmpty(arg.name());
final String column = nullOrEmpty(arg.column());
final String nestedSelect = nullOrEmpty(arg.select());
final String nestedResultMapId = nullOrEmpty(arg.resultMap());
return assistant.buildResultMapping(
resultType, property, column, javaType, jdbcType,
nestedSelect, nestedResultMapId, null, null,
typeHandler, flags, null, null, false
);
}
private ResultMapping createMapping(final Result result, final Class> resultType) {
final List flags = result.id() ? Collections.singletonList(ResultFlag.ID) : Collections.emptyList();
final Class extends TypeHandler>> typeHandler = determineTypeHandler(result.typeHandler(), null);
final Class> javaType = determineJavaType(result.javaType(), null);
final JdbcType jdbcType = determineJdbcType(result.jdbcType(), null);
final String property = nullOrEmpty(result.property());
final String column = nullOrEmpty(result.column());
final String nestedSelect = hasNestedSelect(result) ? nestedSelectId(result) : null;
final String nestedResultMapId = null;
final boolean isLazy = isLazy(result);
return assistant.buildResultMapping(
resultType, property, column, javaType, jdbcType,
nestedSelect, nestedResultMapId, null, null,
typeHandler, flags, null, null, isLazy
);
}
private boolean hasNestedSelect(final Result result) {
final One one = result.one();
final Many many = result.many();
if (0 < one.select().length() && 0 < many.select().length()) {
throw new BuilderException("Cannot use both @One and @Many annotations in the same @Result");
}
return 0 < one.select().length() || 0 < many.select().length();
}
private String nestedSelectId(final Result result) {
String nestedSelect = result.one().select();
if (1 > nestedSelect.length()) {
nestedSelect = result.many().select();
}
if (!nestedSelect.contains(".")) {
final String namespace = assistant.getCurrentNamespace();
if (null == namespace || namespace.isEmpty()) {
throw new IllegalStateException("assistant namespace is not set");
}
nestedSelect = namespace + "." + nestedSelect;
}
return nestedSelect;
}
/**
* 给定Result是否是延迟加载.
*
* @param result 配置的Result
* @return 是否延迟加载
* @see org.apache.ibatis.builder.annotation.MapperAnnotationBuilder#isLazy(Result)
*/
private boolean isLazy(final Result result) {
final One one = result.one();
final Many many = result.many();
boolean isLazy = assistant.getConfiguration().isLazyLoadingEnabled();
if (0 < one.select().length() && !FetchType.DEFAULT.equals(one.fetchType())) {
isLazy = FetchType.LAZY.equals(one.fetchType());
} else if (0 < many.select().length() && !FetchType.DEFAULT.equals(many.fetchType())) {
isLazy = FetchType.LAZY.equals(many.fetchType());
}
return isLazy;
}
private String nullOrEmpty(final String value) {
return null == value || value.trim().isEmpty() ? null : value;
}
private JdbcType determineJdbcType(final JdbcType jdbcType, final JdbcType def) {
return !JdbcType.UNDEFINED.equals(jdbcType) ? jdbcType : def;
}
private Class> determineJavaType(final Class> javaType, final Class> def) {
return !void.class.equals(javaType) ? javaType : def;
}
@SuppressWarnings("unchecked")
private Class extends TypeHandler>> determineTypeHandler(final Class extends TypeHandler> typeHandler,
final Class extends TypeHandler> defaultHandler) {
return (Class extends TypeHandler>>) (!UnknownTypeHandler.class.equals(typeHandler) ? typeHandler : defaultHandler);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy