001package springdao; 002 003import java.lang.reflect.Field; 004import java.lang.reflect.InvocationTargetException; 005import java.lang.reflect.Method; 006import java.lang.reflect.ParameterizedType; 007import java.lang.reflect.Type; 008import java.util.concurrent.atomic.AtomicInteger; 009import org.apache.logging.log4j.Logger; 010import org.apache.logging.log4j.LogManager; 011import org.springframework.beans.BeansException; 012import org.springframework.beans.factory.BeanNotOfRequiredTypeException; 013import org.springframework.beans.factory.NoSuchBeanDefinitionException; 014import org.springframework.beans.factory.config.BeanDefinition; 015import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter; 016import org.springframework.beans.factory.support.BeanDefinitionRegistry; 017import org.springframework.beans.factory.support.GenericBeanDefinition; 018import org.springframework.context.ApplicationContext; 019import org.springframework.context.ApplicationContextAware; 020import org.springframework.context.ConfigurableApplicationContext; 021import org.springframework.core.Ordered; 022import org.springframework.util.ClassUtils; 023import org.springframework.util.ReflectionUtils; 024import org.springframework.util.StringUtils; 025import springdao.support.AbstractSpringDao; 026import springdao.support.SimpleSpringDao; 027 028/** 029 * 030 * @author Kent Yeh 031 */ 032public class DaoAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter implements Ordered, 033 ApplicationContextAware { 034 035 private static final Logger log = LogManager.getLogger(DaoAnnotationBeanPostProcessor.class); 036 private ApplicationContext context; 037 private ConfigurableApplicationContext regContext; 038 private static final AtomicInteger defcnt = new AtomicInteger(0); 039 040 @Override 041 public int getOrder() { 042 return Ordered.HIGHEST_PRECEDENCE; 043 } 044 045 @Override 046 public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 047 this.context = applicationContext; 048 if (applicationContext instanceof ConfigurableApplicationContext) { 049 regContext = (ConfigurableApplicationContext) applicationContext; 050 } 051 } 052 053 public <T> T getBean(String name, Class<T> requiredType) { 054 try { 055 return context.getBean(name, requiredType); 056 } catch (NoSuchBeanDefinitionException ex) { 057 log.warn("Bean name '{}' with {} not exists.", name, requiredType.getSimpleName()); 058 return null; 059 } catch (BeansException ex) { 060 log.warn(String.format("Can't get %s[%s] bean.", requiredType.getSimpleName(), name), ex); 061 return null; 062 } 063 } 064 065 /*private void registerBean(String name, Object bean) { 066 if (regContext != null) { 067 regContext.getBeanFactory().registerSingleton(name, bean); 068 logger.debug("register {} with {}->{}", new Object[]{name, bean.getClass(), bean}); 069 } 070 }*/ 071 private String convertName(String orgName) { 072 String[] names = orgName.split("\\."); 073 StringBuilder sb = new StringBuilder(); 074 for (int i = 0; i < names.length; i++) { 075 if (i == 0) { 076 sb.append(String.valueOf(names[i].charAt(0)).toLowerCase()).append(names[i].substring(1)); 077 } else { 078 sb.append(String.valueOf(names[i].charAt(0)).toUpperCase()).append(names[i].substring(1)); 079 } 080 } 081 return sb.toString(); 082 } 083 084 @Override 085 public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException { 086 087 ReflectionUtils.doWithFields(bean.getClass(), new ReflectionUtils.FieldCallback() { 088 089 @Override 090 public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException { 091 final Dao dao = field.getAnnotation(Dao.class); 092 093 if (dao != null) { 094 Class<?> genericType = dao.value().equals(Object.class) ? null : dao.value(); 095 if (genericType == null) { 096 if (field.getGenericType() instanceof ParameterizedType) { 097 ParameterizedType pt = (ParameterizedType) field.getGenericType(); 098 Type[] typeArguments = pt.getActualTypeArguments(); 099 if (typeArguments != null & typeArguments.length > 0) { 100 genericType = (Class<?>) typeArguments[0]; 101 } 102 } 103 } 104 if (genericType == null) { 105 throw new IllegalArgumentException("@Dao field should assoicate a Generic ParameterizedType like DaoManager<Type> " 106 + field.getName() + " or annotated with @Dao(assocationType.class)"); 107 } 108 final Class<?> assoicateType = genericType; 109 String daoName = StringUtils.hasText(dao.name()) ? dao.name() : dao.autoRegister() 110 ? String.format("%sDao", convertName(DaoRepository.class.equals(field.getType()) ? assoicateType.getSimpleName() : field.getType().getName())) 111 : String.format("%sDao_%d", convertName(assoicateType.getSimpleName()), defcnt.getAndAdd(1)); 112 DaoRepository<?> resultDao = daoName != null && !daoName.isEmpty() ? getBean(daoName, DaoRepository.class) : null; 113 if (resultDao == null) { 114 if (ClassUtils.isAssignable(field.getType(), AbstractSpringDao.class)) { 115 BeanDefinitionRegistry registry = (BeanDefinitionRegistry) regContext.getBeanFactory(); 116 GenericBeanDefinition beanDefinition = new GenericBeanDefinition(); 117 beanDefinition.setBeanClass(SimpleSpringDao.class); 118 beanDefinition.setLazyInit(false); 119 beanDefinition.setAbstract(false); 120 beanDefinition.setAutowireCandidate(true); 121 beanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON); 122 beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, assoicateType); 123 registry.registerBeanDefinition(daoName, beanDefinition); 124 resultDao = (DaoRepository<?>) context.getBean(daoName); 125 } else if (ClassUtils.isAssignable(DaoRepository.class, field.getType())) { 126 BeanDefinitionRegistry registry = (BeanDefinitionRegistry) regContext.getBeanFactory(); 127 GenericBeanDefinition beanDefinition = new GenericBeanDefinition(); 128 beanDefinition.setBeanClass(field.getType()); 129 beanDefinition.setLazyInit(false); 130 beanDefinition.setAbstract(false); 131 beanDefinition.setAutowireCandidate(true); 132 beanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON); 133 registry.registerBeanDefinition(daoName, beanDefinition); 134 resultDao = (DaoRepository<?>) context.getBean(daoName); 135 } else { 136 throw new BeanNotOfRequiredTypeException(field.getName(), DaoRepository.class, field.getType()); 137 } 138 log.debug("Build, and inject field with bean {}@{}<{}>", daoName, resultDao.getClass().getSimpleName(), assoicateType.getSimpleName()); 139 } 140 ReflectionUtils.makeAccessible(field); 141 field.set(bean, resultDao); 142 } 143 final DaoManager ormm = field.getAnnotation(DaoManager.class); 144 if (ormm != null) { 145 Class<?> genericType = ormm.value().equals(Object.class) ? null : ormm.value(); 146 if (genericType == null) { 147 if (field.getGenericType() instanceof ParameterizedType) { 148 ParameterizedType pt = (ParameterizedType) field.getGenericType(); 149 Type[] typeArguments = pt.getActualTypeArguments(); 150 if (typeArguments != null & typeArguments.length > 0) { 151 genericType = (Class<?>) typeArguments[0]; 152 } 153 } 154 } 155 if (genericType == null) { 156 throw new IllegalArgumentException("@DaoManager field should assoicate a Generic ParameterizedType like RepositoryManager<Type> " 157 + field.getName() + " or annotated with @DaoManager(assocationType.class)"); 158 } 159 final Class<?> assoicateType = genericType; 160 String mgrName = StringUtils.hasText(ormm.name()) ? ormm.name() : ormm.autoRegister() 161 ? String.format("%sManager", convertName(RepositoryManager.class.equals(field.getType()) ? assoicateType.getSimpleName() : field.getType().getName())) 162 : String.format("%sManager_%d", convertName(assoicateType.getSimpleName()), defcnt.getAndAdd(1)); 163 RepositoryManager resultManager = mgrName != null && !mgrName.isEmpty() ? getBean(mgrName, RepositoryManager.class) : null; 164 Class<?> fc = field.getType(); 165 if (resultManager == null) { 166 //target's type equals or extends from ormm.baseManagerType(); 167 if (ClassUtils.isAssignable(ormm.baseManagerType(), fc)) { 168 BeanDefinitionRegistry registry = (BeanDefinitionRegistry) regContext.getBeanFactory(); 169 GenericBeanDefinition beanDefinition = new GenericBeanDefinition(); 170 beanDefinition.setBeanClass(fc); 171 beanDefinition.setLazyInit(false); 172 beanDefinition.setAbstract(false); 173 beanDefinition.setAutowireCandidate(true); 174 beanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON); 175 registry.registerBeanDefinition(mgrName, beanDefinition); 176 resultManager = (RepositoryManager) context.getBean(mgrName); 177 } else if (ClassUtils.isAssignable(fc, ormm.baseManagerType())) { 178 BeanDefinitionRegistry registry = (BeanDefinitionRegistry) regContext.getBeanFactory(); 179 GenericBeanDefinition beanDefinition = new GenericBeanDefinition(); 180 beanDefinition.setBeanClass(ormm.baseManagerType()); 181 beanDefinition.setLazyInit(false); 182 beanDefinition.setAbstract(false); 183 beanDefinition.setAutowireCandidate(true); 184 beanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON); 185 registry.registerBeanDefinition(mgrName, beanDefinition); 186 resultManager = (RepositoryManager) context.getBean(mgrName); 187 } 188 } 189 if (resultManager.getDao() == null) { 190 String daoName = StringUtils.hasText(ormm.daoName()) ? ormm.daoName() : ormm.autoRegister() 191 ? String.format("%sDao", convertName(assoicateType.getSimpleName())) 192 : String.format("%sDao_%d", convertName(assoicateType.getSimpleName()), defcnt.getAndAdd(1)); 193 DaoRepository<?> resultDao = StringUtils.hasText(daoName) ? getBean(daoName, DaoRepository.class) : null; 194 if (resultDao == null) { 195 BeanDefinitionRegistry registry = (BeanDefinitionRegistry) regContext.getBeanFactory(); 196 GenericBeanDefinition beanDefinition = new GenericBeanDefinition(); 197 beanDefinition.setBeanClass(SimpleSpringDao.class); 198 beanDefinition.setLazyInit(false); 199 beanDefinition.setAbstract(false); 200 beanDefinition.setAutowireCandidate(true); 201 beanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON); 202 beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, assoicateType); 203 registry.registerBeanDefinition(daoName, beanDefinition); 204 resultDao = (DaoRepository<?>) context.getBean(daoName); 205 } 206 resultManager.setDao(resultDao); 207 } 208 ReflectionUtils.makeAccessible(field); 209 log.debug("Inject {} with {}", field.getName(), resultManager.getClass()); 210 field.set(bean, resultManager); 211 } 212 } 213 }); 214 ReflectionUtils.doWithMethods(bean.getClass(), new ReflectionUtils.MethodCallback() { 215 216 @Override 217 public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException { 218 219 Class<?> parmatypes[] = method.getParameterTypes(); 220 Class<?> fc = parmatypes.length > 0 ? parmatypes[0] : null; 221 222 final Dao dao = method.getAnnotation(Dao.class); 223 if (dao != null && fc != null && void.class.equals(method.getReturnType()) 224 && ClassUtils.isAssignable(DaoRepository.class, fc)) { 225 Class<?> genericType = dao.value().equals(Object.class) ? null : dao.value(); 226 if (genericType == null) { 227 Type[] genericParameterTypes = method.getGenericParameterTypes(); 228 if (genericParameterTypes[0] instanceof ParameterizedType) { 229 ParameterizedType aType = (ParameterizedType) genericParameterTypes[0]; 230 Type[] parameterArgTypes = aType.getActualTypeArguments(); 231 if (parameterArgTypes.length == 1) { 232 genericType = (Class<?>) parameterArgTypes[0]; 233 } 234 } 235 } 236 if (genericType == null) { 237 throw new IllegalArgumentException("@Dao Method should assoicate a Generic ParameterizedType like " + 238 method.getName() + "(DaoRepository<Type>) or annotated with @Dao(assocationType.class) "); 239 } 240 final Class<?> assoicateType = genericType; 241 String daoName = StringUtils.hasText(dao.name()) ? dao.name() : dao.autoRegister() 242 ? String.format("%sDao", convertName(DaoRepository.class.equals(fc) ? assoicateType.getSimpleName() : fc.getName())) 243 : String.format("%sDao_%d", convertName(assoicateType.getSimpleName()), defcnt.getAndAdd(1)); 244 DaoRepository<?> resultDao = daoName != null && !daoName.isEmpty() ? getBean(daoName, DaoRepository.class) : null; 245 if (resultDao == null) { 246 if (ClassUtils.isAssignable(fc, AbstractSpringDao.class)) { 247 BeanDefinitionRegistry registry = (BeanDefinitionRegistry) regContext.getBeanFactory(); 248 GenericBeanDefinition beanDefinition = new GenericBeanDefinition(); 249 beanDefinition.setBeanClass(SimpleSpringDao.class); 250 beanDefinition.setLazyInit(false); 251 beanDefinition.setAbstract(false); 252 beanDefinition.setAutowireCandidate(true); 253 beanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON); 254 beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, assoicateType); 255 registry.registerBeanDefinition(daoName, beanDefinition); 256 resultDao = (DaoRepository<?>) context.getBean(daoName); 257 } else { 258 BeanDefinitionRegistry registry = (BeanDefinitionRegistry) regContext.getBeanFactory(); 259 GenericBeanDefinition beanDefinition = new GenericBeanDefinition(); 260 beanDefinition.setBeanClass(fc); 261 beanDefinition.setLazyInit(false); 262 beanDefinition.setAbstract(false); 263 beanDefinition.setAutowireCandidate(true); 264 beanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON); 265 registry.registerBeanDefinition(daoName, beanDefinition); 266 resultDao = (DaoRepository<?>) context.getBean(daoName); 267 } 268 } 269 ReflectionUtils.makeAccessible(method); 270 try { 271 log.debug("Inject {}({}) with {}", new Object[]{method.getName(), fc.getSimpleName(), resultDao.getClass()}); 272 method.invoke(bean, resultDao); 273 } catch (InvocationTargetException ex) { 274 log.error(ex.getMessage(), ex); 275 } 276 } 277 final DaoManager ormm = method.getAnnotation(DaoManager.class); 278 if (ormm != null && fc != null && void.class.equals(method.getReturnType()) 279 && (ClassUtils.isAssignable(fc, ormm.baseManagerType()) || ClassUtils.isAssignable(ormm.baseManagerType(), fc))) { 280 Class<?> genericType = ormm.value().equals(Object.class) ? null : ormm.value(); 281 if (genericType == null) { 282 Type[] genericParameterTypes = method.getGenericParameterTypes(); 283 if (genericParameterTypes[0] instanceof ParameterizedType) { 284 ParameterizedType aType = (ParameterizedType) genericParameterTypes[0]; 285 Type[] parameterArgTypes = aType.getActualTypeArguments(); 286 if (parameterArgTypes.length == 1) { 287 genericType = (Class<?>) parameterArgTypes[0]; 288 } 289 } 290 } 291 if (genericType == null) { 292 throw new IllegalArgumentException("@DaoMethod Method should assoicate a Generic ParameterizedType like " 293 + method.getName() + "(RepositoryManager<Type>) or annotated with @DaoManager(assocationType.class)"); 294 } 295 final Class<?> assoicateType = genericType; 296 String mgrName = StringUtils.hasText(ormm.name()) ? ormm.name() : ormm.autoRegister() 297 ? String.format("%sManager", convertName(RepositoryManager.class.equals(method.getReturnType()) ? assoicateType.getSimpleName() : fc.getName())) 298 : String.format("%sManager_%d", convertName(assoicateType.getSimpleName()), defcnt.getAndAdd(1)); 299 RepositoryManager resultManager = StringUtils.hasText(mgrName) ? getBean(mgrName, RepositoryManager.class) : null; 300 if (resultManager == null) { 301 if (ClassUtils.isAssignable(ormm.baseManagerType(), fc)) { 302 BeanDefinitionRegistry registry = (BeanDefinitionRegistry) regContext.getBeanFactory(); 303 GenericBeanDefinition beanDefinition = new GenericBeanDefinition(); 304 beanDefinition.setBeanClass(fc); 305 beanDefinition.setLazyInit(false); 306 beanDefinition.setAbstract(false); 307 beanDefinition.setAutowireCandidate(true); 308 beanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON); 309 registry.registerBeanDefinition(mgrName, beanDefinition); 310 resultManager = (RepositoryManager) context.getBean(mgrName); 311 } else if (ClassUtils.isAssignable(fc, ormm.baseManagerType())) { 312 BeanDefinitionRegistry registry = (BeanDefinitionRegistry) regContext.getBeanFactory(); 313 GenericBeanDefinition beanDefinition = new GenericBeanDefinition(); 314 beanDefinition.setBeanClass(ormm.baseManagerType()); 315 beanDefinition.setLazyInit(false); 316 beanDefinition.setAbstract(false); 317 beanDefinition.setAutowireCandidate(true); 318 beanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON); 319 registry.registerBeanDefinition(mgrName, beanDefinition); 320 resultManager = (RepositoryManager) context.getBean(mgrName); 321 } 322 } 323 if (resultManager.getDao() == null) { 324 String daoName = StringUtils.hasText(ormm.daoName()) ? ormm.daoName() : ormm.autoRegister() 325 ? String.format("%sDao", convertName(assoicateType.getSimpleName())) 326 : String.format("%sDao_%d", convertName(assoicateType.getSimpleName()), defcnt.getAndAdd(1)); 327 DaoRepository<?> resultDao = StringUtils.hasText(daoName) ? getBean(daoName, DaoRepository.class) : null; 328 if (resultDao == null) { 329 BeanDefinitionRegistry registry = (BeanDefinitionRegistry) regContext.getBeanFactory(); 330 GenericBeanDefinition beanDefinition = new GenericBeanDefinition(); 331 beanDefinition.setBeanClass(SimpleSpringDao.class); 332 beanDefinition.setLazyInit(false); 333 beanDefinition.setAbstract(false); 334 beanDefinition.setAutowireCandidate(true); 335 beanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON); 336 beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, assoicateType); 337 registry.registerBeanDefinition(daoName, beanDefinition); 338 resultDao = (DaoRepository<?>) context.getBean(daoName); 339 } 340 resultManager.setDao(resultDao); 341 } 342 ReflectionUtils.makeAccessible(method); 343 try { 344 log.debug("Inject {}({}) with {}", new Object[]{method.getName(), fc.getSimpleName(), resultManager.getClass()}); 345 method.invoke(bean, resultManager); 346 } catch (InvocationTargetException ex) { 347 log.error(ex.getMessage(), ex); 348 } 349 } 350 } 351 }); 352 return bean; 353 } 354}