001/*
002 *  Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
003 *  <p>
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *  <p>
008 *  http://www.apache.org/licenses/LICENSE-2.0
009 *  <p>
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package com.mybatisflex.core.mybatis;
017
018import com.mybatisflex.core.BaseMapper;
019import com.mybatisflex.core.FlexGlobalConfig;
020import com.mybatisflex.core.exception.FlexExceptions;
021import com.mybatisflex.core.util.StringUtil;
022import org.apache.ibatis.reflection.ExceptionUtil;
023import org.apache.ibatis.session.ExecutorType;
024import org.apache.ibatis.session.SqlSession;
025import org.apache.ibatis.session.SqlSessionFactory;
026import com.mybatisflex.core.util.MapUtil;
027
028import java.lang.reflect.InvocationHandler;
029import java.lang.reflect.Method;
030import java.lang.reflect.Proxy;
031import java.util.Map;
032import java.util.concurrent.ConcurrentHashMap;
033
034/**
035 * 获取 {@link BaseMapper} 对象。
036 *
037 * @author michael
038 * @author 王帅
039 */
040@SuppressWarnings("unchecked")
041public class Mappers {
042
043    private Mappers() {
044    }
045
046    private static final Map<String, Map<Class<?>, Object>> MAPPER_OBJECTS_OF_ENV = new ConcurrentHashMap<>();
047
048    private static final Map<Class<?>, Class<?>> ENTITY_MAPPER_MAP = new ConcurrentHashMap<>();
049
050    /**
051     * 添加 实体类 与 {@link BaseMapper} 接口实现接口 对应,两者皆为非动态代理类。
052     *
053     * @param entityClass 实体类
054     * @param mapperClass {@link BaseMapper} 实现接口
055     */
056    static void addMapping(Class<?> entityClass, Class<?> mapperClass) {
057        ENTITY_MAPPER_MAP.put(entityClass, mapperClass);
058    }
059
060    /**
061     * 通过 实体类 获取对应 {@link BaseMapper} 对象。
062     *
063     * @param entityClass 实体类
064     * @param <E>         实体类类型
065     * @return {@link BaseMapper} 对象
066     */
067    public static <E> BaseMapper<E> ofEntityClass(Class<E> entityClass) {
068        Class<?> mapperClass = ENTITY_MAPPER_MAP.get(entityClass);
069        if (mapperClass == null) {
070            throw FlexExceptions.wrap("Can not find MapperClass by entity: " + entityClass.getName());
071        }
072        return (BaseMapper<E>) ofMapperClass(mapperClass);
073    }
074
075    /**
076     * 通过 {@link BaseMapper} 接口实现的 Class 引用直接获取 {@link BaseMapper} 代理对象。
077     *
078     * @param mapperClass {@link BaseMapper} 接口实现
079     * @return {@link BaseMapper} 对象
080     */
081    public static <M> M ofMapperClass(Class<M> mapperClass) {
082        Map<Class<?>, Object> mapperObjects = MapUtil.computeIfAbsent(MAPPER_OBJECTS_OF_ENV, "default", envId -> new ConcurrentHashMap<>());
083        Object mapperObject = MapUtil.computeIfAbsent(mapperObjects, mapperClass, clazz ->
084            Proxy.newProxyInstance(mapperClass.getClassLoader()
085                , new Class[]{mapperClass}
086                , new MapperHandler(mapperClass)));
087        return (M) mapperObject;
088    }
089    public static <M> M ofMapperClass(String environmentId, Class<M> mapperClass) {
090        Map<Class<?>, Object> mapperObjects = MapUtil.computeIfAbsent(MAPPER_OBJECTS_OF_ENV, environmentId, envId -> new ConcurrentHashMap<>());
091        Object mapperObject = MapUtil.computeIfAbsent(mapperObjects, mapperClass, clazz ->
092            Proxy.newProxyInstance(mapperClass.getClassLoader()
093                , new Class[]{mapperClass}
094                , new MapperHandler(environmentId, mapperClass)));
095        return (M) mapperObject;
096    }
097
098    private static class MapperHandler implements InvocationHandler {
099
100        private final Class<?> mapperClass;
101        private final ExecutorType executorType;
102        private final SqlSessionFactory sqlSessionFactory;
103
104        public MapperHandler(Class<?> mapperClass) {
105            this(null, mapperClass);
106        }
107
108        public MapperHandler(String environmentId, Class<?> mapperClass) {
109            this.mapperClass = mapperClass;
110            if(StringUtil.noText(environmentId)) {
111                this.executorType = FlexGlobalConfig.getDefaultConfig()
112                    .getConfiguration()
113                    .getDefaultExecutorType();
114                this.sqlSessionFactory = FlexGlobalConfig.getDefaultConfig()
115                    .getSqlSessionFactory();
116            } else {
117                this.executorType = FlexGlobalConfig.getConfig(environmentId)
118                    .getConfiguration()
119                    .getDefaultExecutorType();
120                this.sqlSessionFactory = FlexGlobalConfig.getConfig(environmentId)
121                    .getSqlSessionFactory();
122            }
123        }
124
125        private SqlSession openSession() {
126            return sqlSessionFactory.openSession(executorType, true);
127        }
128
129        @Override
130        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
131            try (SqlSession sqlSession = openSession()) {
132                Object mapper = sqlSession.getMapper(mapperClass);
133                return method.invoke(mapper, args);
134            } catch (Throwable throwable) {
135                throw ExceptionUtil.unwrapThrowable(throwable);
136            }
137        }
138
139    }
140
141}