/*
* Copyright 2008-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.geequery.springdata.repository.support;
import java.io.Serializable;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import jef.tools.reflect.ClassEx;
import jef.tools.reflect.FieldEx;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.RepositoryDefinition;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.data.repository.core.support.TransactionalRepositoryFactoryBeanSupport;
import org.springframework.util.Assert;
/**
* Special adapter for Springs
* {@link org.springframework.beans.factory.FactoryBean} interface to allow easy
* setup of repository factories via Spring configuration.
*
* @param <T>
* the type of the repository
*/
public class GqRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extends Serializable> extends TransactionalRepositoryFactoryBeanSupport<T, S, ID> implements ApplicationContextAware {
protected GqRepositoryFactoryBean(Class<? extends T> repositoryInterface) {
super(repositoryInterface);
this.repositoryInterface = repositoryInterface;
}
private EntityManager em;
private ConfigurableApplicationContext context;
private Class<?> repositoryInterface;
private static Logger log = LoggerFactory.getLogger(GqRepositoryFactoryBean.class);
/**
* The {@link EntityManager} to be used.
*
* @param entityManager
* the entityManager to set
*/
@PersistenceContext
public void setEntityManager(EntityManager entityManager) {
this.em = entityManager;
}
/*
* (non-Javadoc)
*
* @see
* org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport
* #
* setMappingContext(org.springframework.data.mapping.context.MappingContext
* )
*/
@Override
public void setMappingContext(MappingContext<?, ?> mappingContext) {
super.setMappingContext(mappingContext);
}
/*
* (non-Javadoc)
*
* @see org.springframework.data.repository.support.
* TransactionalRepositoryFactoryBeanSupport#doCreateRepositoryFactory()
*/
@Override
protected RepositoryFactorySupport doCreateRepositoryFactory() {
return createRepositoryFactory(em);
}
/**
* Returns a {@link RepositoryFactorySupport}.
*
* @param entityManager
* @return
*/
protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
return new GqRepositoryFactory(entityManager);
}
/*
* (non-Javadoc)
*
* @see
* org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
@Override
public void afterPropertiesSet() {
Assert.notNull(em, "EntityManager must not be null!");
Object custom = generateCustomImplementation();
if (custom != null)
this.setCustomImplementation(custom);
super.afterPropertiesSet();
}
/*
* FIXME
* 土法炼钢:看spring-data源码,由于使用太多容器注入特性,没法发现CustomImplementation对象是从哪里创建出来的。
* (虽然说做个案例 DEBUG一下应该能跟出来,但最近实在没时间……)
* 所以这里简单粗暴的将自定义的扩展Repository构造出来用了再说。以后有时间还是要修改得更优雅一点。
*/
private Object generateCustomImplementation() {
for (Class<?> clz : repositoryInterface.getInterfaces()) {
if (Repository.class.isAssignableFrom(clz)) {
continue;
} else if (clz.getAnnotation(RepositoryDefinition.class) != null) {
continue;
}
ClassEx implClz = ClassEx.forName(clz.getName() + "Impl");
if (implClz == null) {
log.error("Lack of implementation of class: " + clz.getName());
}
try {
Object obj = implClz.newInstance();
for (FieldEx field : implClz.getDeclaredFields()) {
if (field.getAnnotation(PersistenceContext.class) != null) {
field.set(obj, em);
}
}
if (obj instanceof ApplicationContextAware) {
((ApplicationContextAware) obj).setApplicationContext(context);
}
if (obj instanceof InitializingBean) {
((InitializingBean) obj).afterPropertiesSet();
}
return obj;
} catch (Exception ex) {
log.error("", ex);
return null;
}
}
return null;
}
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
this.context = (ConfigurableApplicationContext) context;
}
}