001/* 002 * Copyright 2009-2023 the original author or authors. 003 * 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 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 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.binding; 017 018import com.mybatisflex.core.mybatis.FlexConfiguration; 019import org.apache.ibatis.binding.BindingException; 020import org.apache.ibatis.binding.MapperRegistry; 021import org.apache.ibatis.builder.annotation.MapperAnnotationBuilder; 022import org.apache.ibatis.io.ResolverUtil; 023import org.apache.ibatis.session.SqlSession; 024 025import java.util.Collection; 026import java.util.Collections; 027import java.util.Map; 028import java.util.Set; 029import java.util.concurrent.ConcurrentHashMap; 030 031public class FlexMapperRegistry extends MapperRegistry { 032 private final FlexConfiguration config; 033 private final Map<Class<?>, FlexMapperProxyFactory<?>> knownMappers = new ConcurrentHashMap<>(); 034 035 public FlexMapperRegistry(FlexConfiguration config) { 036 super(config); 037 this.config = config; 038 } 039 040 @SuppressWarnings("unchecked") 041 public <T> T getMapper(Class<T> type, SqlSession sqlSession) { 042 final FlexMapperProxyFactory<T> mapperProxyFactory = (FlexMapperProxyFactory<T>) knownMappers.get(type); 043 if (mapperProxyFactory == null) { 044 throw new BindingException("Type " + type + " is not known to the MapperRegistry."); 045 } 046 try { 047 return mapperProxyFactory.newInstance(sqlSession, config); 048 } catch (Exception e) { 049 throw new BindingException("Error getting mapper instance. Cause: " + e, e); 050 } 051 } 052 053 public <T> boolean hasMapper(Class<T> type) { 054 return knownMappers.containsKey(type); 055 } 056 057 public <T> void addMapper(Class<T> type) { 058 if (type.isInterface()) { 059 if (hasMapper(type)) { 060 throw new BindingException("Type " + type + " is already known to the MapperRegistry."); 061 } 062 boolean loadCompleted = false; 063 try { 064 knownMappers.put(type, new FlexMapperProxyFactory<>(type)); 065 // It's important that the type is added before the parser is run 066 // otherwise the binding may automatically be attempted by the 067 // mapper parser. If the type is already known, it won't try. 068 MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type); 069 parser.parse(); 070 loadCompleted = true; 071 } finally { 072 if (!loadCompleted) { 073 knownMappers.remove(type); 074 } 075 } 076 } 077 } 078 079 /** 080 * Gets the mappers. 081 * 082 * @return the mappers 083 * @since 3.2.2 084 */ 085 public Collection<Class<?>> getMappers() { 086 return Collections.unmodifiableCollection(knownMappers.keySet()); 087 } 088 089 /** 090 * Adds the mappers. 091 * 092 * @param packageName the package name 093 * @param superType the super type 094 * @since 3.2.2 095 */ 096 public void addMappers(String packageName, Class<?> superType) { 097 ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<>(); 098 resolverUtil.find(new ResolverUtil.IsA(superType), packageName); 099 Set<Class<? extends Class<?>>> mapperSet = resolverUtil.getClasses(); 100 for (Class<?> mapperClass : mapperSet) { 101 addMapper(mapperClass); 102 } 103 } 104 105 /** 106 * Adds the mappers. 107 * 108 * @param packageName the package name 109 * @since 3.2.2 110 */ 111 public void addMappers(String packageName) { 112 addMappers(packageName, Object.class); 113 } 114}