All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.onetwo.dbm.mapping.DbmMappedEntryBuilder Maven / Gradle / Ivy

The newest version!
package org.onetwo.dbm.mapping;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;

import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;

import org.onetwo.common.annotation.AnnotationInfo;
import org.onetwo.common.log.JFishLoggerFactory;
import org.onetwo.common.reflect.ReflectUtils;
import org.onetwo.common.spring.SpringUtils;
import org.onetwo.common.utils.Assert;
import org.onetwo.common.utils.JFishFieldInfoImpl;
import org.onetwo.common.utils.JFishProperty;
import org.onetwo.common.utils.JFishPropertyInfoImpl;
import org.onetwo.common.utils.LangUtils;
import org.onetwo.common.utils.RegisterManager;
import org.onetwo.common.utils.StringUtils;
import org.onetwo.dbm.annotation.DbmColumn;
import org.onetwo.dbm.annotation.DbmEntity;
import org.onetwo.dbm.annotation.DbmGeneratedValue;
import org.onetwo.dbm.annotation.DbmQueryable;
import org.onetwo.dbm.core.spi.DbmInnerServiceRegistry;
import org.onetwo.dbm.dialet.DBDialect;
import org.onetwo.dbm.exception.DbmException;
import org.onetwo.dbm.id.StrategyType;
import org.onetwo.dbm.jpa.GeneratedValueIAttrs;
import org.onetwo.dbm.query.DbmQueryableMappedEntryImpl;
import org.onetwo.dbm.utils.DBUtils;
import org.onetwo.dbm.utils.SpringAnnotationFinder;
import org.slf4j.Logger;
import org.springframework.core.Ordered;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.MetadataReader;

@SuppressWarnings("rawtypes")
public class DbmMappedEntryBuilder implements MappedEntryBuilder, RegisterManager {

	protected final Logger logger = JFishLoggerFactory.getLogger(this.getClass());
	
//	private Map entryCache = new HashMap();
	private boolean byProperty = true;
	private DBDialect dialect;
	
	private int order = Ordered.LOWEST_PRECEDENCE;
	
	private MappedEntryBuilderListenerManager listenerManager;
	
	final private Map builderListeners = new LinkedHashMap<>();
	protected final DbmInnerServiceRegistry serviceRegistry;

	public Map getRegister() {
		return builderListeners;
	}

	public DbmMappedEntryBuilder(DbmInnerServiceRegistry serviceRegistry){
		this.serviceRegistry = serviceRegistry;
		this.dialect = this.serviceRegistry.getDialect();
	}
	
	@Override
	public void initialize() {
		Assert.notNull(dialect);
		listenerManager = new MappedEntryBuilderListenerManager(builderListeners.values());
	}

	protected DBDialect getDialect() {
		return dialect;
	}


	public boolean isSupported(Object entity){
		if(MetadataReader.class.isInstance(entity)){
			MetadataReader metadataReader = (MetadataReader) entity;
			AnnotationMetadata am = metadataReader.getAnnotationMetadata();
			return am.hasAnnotation(DbmEntity.class.getName()) || am.hasAnnotation(DbmQueryable.class.getName());
		}else{
			Class entityClass = ReflectUtils.getObjectClass(entity);
			return entityClass.getAnnotation(DbmEntity.class)!=null || entityClass.getAnnotation(DbmQueryable.class)!=null;
		}
	}
	
//	@Override
//	public JFishMappedEntry findEntry(Object object) {
//		try {
//			return getEntry(object);
//		} catch (Exception e) {
//			logger.error("can find the entry : " + object);
//		}
//		return null;
//	}

	/* (non-Javadoc)
	 * @see org.onetwo.common.db.wheel.MappedEntityManager#getEntry(java.lang.Object)
	 */
	public DbmMappedEntry getEntry(Object objects){
		Assert.notNull(objects, "entity can not be null");
		DbmMappedEntry entry = null;
		
		Object object = LangUtils.getFirst(objects);
		if(!isSupported(object)){
			LangUtils.throwBaseException("don't support this object : " + object);
//			return null;
		}
		
		if(object instanceof Map){
			Map mapEntity = (Map)object;
//			boolean removeMeta = true;
			/*if(mapEntity.containsKey(TMeta.entity_meta)){
				mapEntity = (Map)mapEntity.get(TMeta.entity_meta);
//				removeMeta = false;
			}*/
			
			entry = buildMappedEntry(mapEntity);
		}else if(object instanceof Class){
			Class entityClass = (Class)object;
			
			/*key = entityClass.getName();
			entry = getFromCache(key);
			if(entry!=null)
				return entry;*/
			
			entry = buildMappedEntry(entityClass, byProperty);
		}else{
			Class entityClass = object.getClass();
			
			/*key = entityClass.getName();
			entry = getFromCache(key);
			if(entry!=null)
				return entry;*/
			
			entry = buildMappedEntry(entityClass, byProperty);
		}
		
		if(entry==null)
			LangUtils.throwBaseException("no entry created : "+object);
		
//		putInCache(key, entry);
		
		return entry;
	}
	

	@Override
	public DbmMappedEntry buildMappedEntry(Object object) {
		Object entity = LangUtils.getFirst(object);
		Class entityClass = ReflectUtils.getObjectClass(entity);
		return buildMappedEntry(entityClass, byProperty);
	}
	
	protected void afterBuildMappedEntry(DBDialect dbDialect, DbmMappedEntry entry){
		this.checkIdStrategy(dbDialect, entry); 
	}
	
	/********
	 * 自动检查更正id策略
	 * @param dbDialect
	 * @param entry
	 */
	protected void checkIdStrategy(DBDialect dbDialect, DbmMappedEntry entry){
		entry.getIdentifyFields().forEach(identifyField -> {
			checkIdStrategy(dbDialect, identifyField);
		});
	}
	protected void checkIdStrategy(DBDialect dbDialect, DbmMappedField identifyField){
		if(identifyField==null)
			return ;
		if(identifyField.getStrategyType()!=null && !dbDialect.isSupportedIdStrategy(identifyField.getStrategyType())){
			if(!dbDialect.isAutoDetectIdStrategy()){
				throw new DbmException("database["+dbDialect.getDbmeta().getDbName()+"] do not support this strategy : " + identifyField.getStrategyType());
			}else{
				identifyField.setStrategyType(dbDialect.getIdStrategy().get(0));
			}
		}
	}
	
	/*********
	 * 1. 创建一个实体映射对象
	 * 2. 把所有实体的注解添加到对象
	 * @param entityClass
	 * @return
	 */
	@SuppressWarnings("deprecation")
	protected DbmMappedEntry createDbmMappedEntry(AnnotationInfo annotationInfo){
		AbstractDbmMappedEntryImpl entry = null;
		Class entityClass = annotationInfo.getSourceClass();
		DbmEntity jentity = entityClass.getAnnotation(DbmEntity.class);
		DbmQueryable jqueryable = entityClass.getAnnotation(DbmQueryable.class);

		if(jentity==null && jqueryable==null)
			throw new DbmException("it's not a valid entity : " + entityClass);

		TableInfo tableInfo = newTableInfo(annotationInfo);
		if(jqueryable!=null){
			entry = new DbmQueryableMappedEntryImpl(jentity.name(), annotationInfo, tableInfo, serviceRegistry);
		}else{
			if(jentity.type()==MappedType.QUERYABLE_ONLY){
				entry = new DbmQueryableMappedEntryImpl(jentity.name(), annotationInfo, tableInfo, serviceRegistry);
			}/*else if(jentity.type()==MappedType.JOINED){
				entry = new JFishJoinedMappedEntryImpl(annotationInfo, tableInfo);
			}*/else{
				entry = new DbmMappedEntryImpl(jentity.name(), annotationInfo, tableInfo, serviceRegistry);
			}
		}
		entry.setSqlBuilderFactory(this.dialect.getSqlBuilderFactory());
		return entry;
	}
	
	protected void buildIdGeneratorsOnClass(DbmMappedEntry entry){
		AnnotationInfo annotationInfo = entry.getAnnotationInfo();
		IdGeneratorFactory.createDbmIdGenerator(annotationInfo)
							.ifPresent(idGenerator->entry.addIdGenerator(idGenerator));
	}

	/*********
	 * build entity mapped info and put it into cache
	 * @param entityClass
	 * @param byProperty
	 * @return
	 */
	public DbmMappedEntry buildMappedEntry(Class entityClass, boolean byProperty) {
//		AnnotationInfo annotationInfo = new AnnotationInfo(entityClass);
		AnnotationInfo annotationInfo = SpringUtils.createAnnotationInfo(entityClass);
		DbmMappedEntry entry = createDbmMappedEntry(annotationInfo);
		this.listenerManager.notifyAfterCreatedMappedEntry(entry);

		this.buildIdGeneratorsOnClass(entry);
		if(byProperty){
			entry = buildMappedEntryByProperty(entry);
		}else{
			entry = buildMappedEntryByField(entry);
		}
//		buildMappedEntryProperties(entry, byProperty);
		
//		TableInfo tableInfo = entry.getTableInfo();
//		entry.build(tableInfo);
		afterBuildMappedEntry(dialect, entry);
		this.listenerManager.notifyAfterBuildMappedEntry(entry);
		
		return entry;
	}
	
	@Override
	public DbmMappedEntry buildMappedFields(DbmMappedEntry entry) {
		return buildMappedEntryByField(entry);
	}

	protected DbmMappedEntry buildMappedEntryByProperty(DbmMappedEntry entry) {
		Class entityClass = entry.getEntityClass();
		PropertyDescriptor[] props = ReflectUtils.desribProperties(entityClass);
		
		AbstractMappedField mfield = null;
//		List mfieldList = new ArrayList(props.length);
		for(PropertyDescriptor prop : props){
			mfield = createAndBuildMappedField(entry, new JFishPropertyInfoImpl(entityClass, prop));
			if(mfield==null)
				continue;
			this.listenerManager.notifyAfterBuildMappedField(entry, mfield);
			entry.addMappedField(mfield);
		}
		return entry;
	}

	protected DbmMappedEntry buildMappedEntryByField(DbmMappedEntry entry) {
		Class entityClass = entry.getEntityClass();
		Collection fields = ReflectUtils.findFieldsFilterStatic(entityClass);
		
		AbstractMappedField mfield = null;
		for(Field field : fields){
			mfield = createAndBuildMappedField(entry, new JFishFieldInfoImpl(entityClass, field));
			if(mfield==null)
				continue;
			entry.addMappedField(mfield);
		}

		return entry;
	}
	
	protected boolean ignoreMappedField(DbmMappedEntry entry, JFishProperty field){
		return Modifier.isTransient(field.getModifiers()) || Modifier.isStatic(field.getModifiers());
	}

	protected TableInfo newTableInfo(AnnotationInfo entry){
		TableInfo tableInfo = new TableInfo(buildTableName(entry));
		tableInfo.setSeqName(buildSeqName(entry, tableInfo));
		return tableInfo;
	}
	
	protected String buildSeqName(AnnotationInfo entry, TableInfo tableInfo){
//		String sname = entry.getEntityClass().getSimpleName();
		String sname = "SEQ_" + tableInfo.getName().toUpperCase();
		return sname;
	}
	
	protected String buildTableName(AnnotationInfo entry){
		String tname = null;
		if(entry.getAnnotation(DbmQueryable.class)!=null){
			DbmQueryable queryable = entry.getAnnotation(DbmQueryable.class);
			tname = queryable.table();
		}
		
		//JFishEntity's table name will be override JFishQueryable
		if(entry.getAnnotation(DbmEntity.class)!=null){
			DbmEntity jfishEntity = entry.getAnnotation(DbmEntity.class);
			tname = jfishEntity.table();
		}
		if(StringUtils.isBlank(tname))
			tname = StringUtils.convert2UnderLineName(entry.getSourceClass().getSimpleName());
		/*if(StringUtils.isBlank(tname)){
			LangUtils.throwBaseException("table can not be empty: " + entry.getEntityClass());
		}*/
		return tname;
	}

	protected BaseColumnInfo buildColumnInfo(TableInfo tableInfo, DbmMappedField field){
//		Method method = ReflectUtils.getReadMethod(entityClass, field.getProperty());
		
		String colName = null;
		DbmColumn jc = field.getPropertyInfo().getAnnotation(DbmColumn.class);
		int sqlType = DBUtils.TYPE_UNKNOW;
		if (jc!=null) {
			colName = jc.name();
			sqlType = jc.sqlType();
		}
		
		colName = convertColumnName(field, colName);

		if (sqlType==DBUtils.TYPE_UNKNOW) {
			sqlType = dialect.getTypeMapping().getType(field.getPropertyInfo().getType());
		}
		ColumnInfo col = new ColumnInfo(tableInfo, colName, sqlType);
		col.setJavaType(field.getPropertyInfo().getType());
		col.setPrimaryKey(field.isIdentify());
		if (field.isIdentify()) {
			col.setInsertable(!field.isIdentityStrategy());
			col.setUpdatable(!field.isIdentityStrategy());
		}
		
		return col;
	}
	
	protected String convertColumnName(DbmMappedField field, String colName) {
		if (StringUtils.isBlank(colName)) {
			colName = field.getName();
			colName = StringUtils.convert2UnderLineName(colName);
		} 
		return colName;
	}
	
	/*protected void buildPKColumnInfo(AbstractMappedField field, ColumnInfo col){
		col.setPrimaryKey(true);
	}*/

	protected DbmMappedEntry buildMappedEntry(Map entity){
		throw new IllegalArgumentException("unsupported map entity : " + entity);
		/*JFishMappedEntry entry = new JFishMappedEntryImpl(entity.getClass());
		//TODO
		return entry;*/
	}

	protected Object getValueFromMapEntity(Map entity, String key, boolean remove){
		if(!entity.containsKey(key))
			return null;
		Object val = entity.get(key);
		if(remove)
			entity.remove(key);
		return val;
	}
	
	/*******
	 * 通过类的属性
	 * 1. 创建字段映射对象
	 * 2. 添加字段的所有注解到对象
	 * 3. 设置对象是否为identify
	 * @param entry
	 * @param prop
	 * @return
	 */

	protected AbstractMappedField createAndBuildMappedField(DbmMappedEntry entry, JFishProperty prop){
		/*if(ignoreMappedField(prop)) {
			return null;
		}*/
		// 替换注解查找策略
		prop.getAnnotationInfo().setAnnotationFinder(SpringAnnotationFinder.INSTANCE);
		
		AbstractMappedField mfield = newMappedField(entry, prop);
		this.buildMappedField(mfield);
		
		// transient
		if (!ignoreMappedField(entry, prop)) {
			BaseColumnInfo col = this.buildColumnInfo(entry.getTableInfo(), mfield);
			
			//设置关系
			if(col!=null){
				mfield.setColumn(col);
				if(entry.getTableInfo()!=null){
					entry.getTableInfo().addColumn(col);
				}
			}
		}
		return mfield;
	}
	
	protected AbstractMappedField newMappedField(DbmMappedEntry entry, JFishProperty prop){
		DbmMappedProperty mfield = new DbmMappedProperty(entry, prop);
		return mfield;
	}

	protected void buildMappedField(DbmMappedField mfield){
		if("id".equals(mfield.getName()))
			mfield.setIdentify(true);
		if(this.getDialect().getDbmeta().isMySQL()){
			mfield.setStrategyType(StrategyType.IDENTITY);
		}else if(this.getDialect().getDbmeta().isOracle()){
			mfield.setStrategyType(StrategyType.SEQ);
		}
		
//		this.buildMappedFieldByAnnotations(mfield);
	}
	

	protected void buildIdGeneratorsOnField(DbmMappedField mfield){
		GeneratedValueIAttrs generatedValueIAttrs = null;

		AnnotationInfo annotationInfo = mfield.getPropertyInfo().getAnnotationInfo();
		
		GeneratedValue g = annotationInfo.getAnnotation(GeneratedValue.class);
		DbmGeneratedValue dg = annotationInfo.getAnnotation(DbmGeneratedValue.class);
		if (dg!=null) {
			GenerationType type = dg.strategy();
			generatedValueIAttrs = new GeneratedValueIAttrs(type, dg.generator());
		} else if (g!=null) {
			GenerationType type = g.strategy();
			generatedValueIAttrs = new GeneratedValueIAttrs(type, g.generator());
		}
		
		mfield.setGeneratedValueIAttrs(generatedValueIAttrs);
		IdGeneratorFactory.createDbmIdGenerator(annotationInfo)
							.ifPresent(idGenerator->mfield.addIdGenerator(idGenerator));
	}
	
	/*private void buildMappedFieldByAnnotations(AbstractMappedField mfield){
		//TODO
		JFishMeta jfishColumn = mfield.getPropertyInfo().getAnnotation(JFishMeta.class);
		if(mfield.getPropertyInfo().hasAnnotation(JFishMeta.class)){
			this.buildJFishGen(mfield, jfishColumn);
		}
	}
	
	private void buildJFishGen(AbstractMappedField mfield, JFishMeta gen){
		//TODO
	}*/

	public void setDialect(DBDialect dialect) {
		this.dialect = dialect;
	}


	public int getOrder() {
		return order;
	}


	public void setOrder(int order) {
		this.order = order;
	}

	public void setListenerManager(MappedEntryBuilderListenerManager listenerManager) {
		this.listenerManager = listenerManager;
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy