/* * JEF - Copyright 2009-2010 Jiyi (mr.jiyi@gmail.com) * * 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 jef.database.meta; import java.io.IOException; import java.lang.reflect.Modifier; import java.net.URL; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import javax.persistence.Column; import javax.persistence.JoinColumn; import javax.persistence.JoinColumns; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; import javax.persistence.ManyToOne; import javax.persistence.NoResultException; import javax.persistence.OneToMany; import javax.persistence.OneToOne; import javax.persistence.OrderBy; import javax.persistence.PersistenceException; import javax.persistence.Transient; import jef.accelerator.asm.Attribute; import jef.accelerator.asm.ClassReader; import jef.accelerator.asm.ClassVisitor; import jef.accelerator.asm.Opcodes; import jef.common.log.LogUtil; import jef.common.wrapper.Holder; import jef.database.Condition.Operator; import jef.database.DbCfg; import jef.database.DbMetaData; import jef.database.DbUtils; import jef.database.EntityExtensionSupport; import jef.database.Field; import jef.database.IQueryableEntity; import jef.database.JefClassLoader; import jef.database.MetadataContainer; import jef.database.ORMConfig; import jef.database.PojoWrapper; import jef.database.Session; import jef.database.VarObject; import jef.database.annotation.Cascade; import jef.database.annotation.DynamicKeyValueExtension; import jef.database.annotation.DynamicTable; import jef.database.annotation.EasyEntity; import jef.database.annotation.FieldOfTargetEntity; import jef.database.annotation.Indexed; import jef.database.annotation.JoinDescription; import jef.database.annotation.JoinType; import jef.database.annotation.NoForceEnhance; import jef.database.dialect.ColumnType; import jef.database.dialect.ColumnType.AutoIncrement; import jef.database.dialect.ColumnType.GUID; import jef.database.dialect.type.ColumnMapping; import jef.database.dialect.type.ColumnMappings; import jef.database.jsqlparser.expression.BinaryExpression; import jef.database.jsqlparser.parser.ParseException; import jef.database.jsqlparser.visitor.Expression; import jef.database.jsqlparser.visitor.ExpressionType; import jef.database.meta.AnnotationProvider.ClassAnnotationProvider; import jef.database.meta.AnnotationProvider.FieldAnnotationProvider; import jef.database.meta.def.IndexDef; import jef.database.meta.extension.EfPropertiesExtensionProvider; import jef.database.query.JpqlExpression; import jef.database.query.ReadOnlyQuery; import jef.database.support.EntityNotEnhancedException; import jef.database.support.QuerableEntityScanner; import jef.tools.ArrayUtils; import jef.tools.Assert; import jef.tools.IOUtils; import jef.tools.JefConfiguration; import jef.tools.StringUtils; import jef.tools.collection.CollectionUtils; import jef.tools.reflect.BeanUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.collect.ArrayListMultimap; /** * 静态存放所有数据表元模型的存放类。 * * 各个数据表模型都可以从这个类的方法中得到。 * * @author jiyi * */ @SuppressWarnings("deprecation") public final class MetaHolder { private MetaHolder() { } // 分表分库策略加载器 static private PartitionStrategyLoader partitionLoader; // 元数据加载器 static MetadataConfiguration config; // Schema映射 static Map<String, String> SCHEMA_MAPPING; // 站点映射 static Map<String, String> SITE_MAPPING; // 元数据池(包含标准Entity的元数据和POJO的元数据) static final Map<Class<?>, AbstractMetadata> pool = new java.util.IdentityHashMap<Class<?>, AbstractMetadata>(32); // 动态表元数据池 static final Map<String, TupleMetadata> dynPool = new java.util.HashMap<String, TupleMetadata>(32); // 反向查找表 private static final Map<String, AbstractMetadata> inverseMapping = new HashMap<String, AbstractMetadata>(); private static Logger log = LoggerFactory.getLogger(MetaHolder.class); // 初始化分表规则加载器 static { try { String clz = JefConfiguration.get(DbCfg.PARTITION_STRATEGY_LOADER); if (StringUtils.isNotEmpty(clz)) { partitionLoader = (PartitionStrategyLoader) BeanUtils.newInstance(clz); } if (partitionLoader == null) { partitionLoader = new DefaultPartitionStrategyLoader(); } } catch (Exception e) { log.error("PARTITION_STRATEGY_LOADER error", e); } try { String clz = JefConfiguration.get(DbCfg.CUSTOM_METADATA_LOADER); if (StringUtils.isNotEmpty(clz)) { config = (MetadataConfiguration) BeanUtils.newInstance(clz); } if (config == null) { config = new DefaultMetaLoader(); } } catch (Exception e) { log.error("CUSTOM_METADATA_LOADER error", e); } try { SCHEMA_MAPPING = StringUtils.toMap(JefConfiguration.get(DbCfg.SCHEMA_MAPPING), ",", ":", 1); String configStr = JefConfiguration.get(DbCfg.DB_DATASOURCE_MAPPING); SITE_MAPPING = StringUtils.toMap(configStr, ",", ":", -1); if (!SITE_MAPPING.isEmpty()) { LogUtil.info("Database mapping: " + SITE_MAPPING); } } catch (Exception e) { log.error("SCHEMA_MAPPING error", e); } } /** * 获得重定向后的Schema * * @param key * @return 如果返回"",表示无schema 如果返回入参本身,表示不作改动 其他情况,返回重定向的schema */ public static String getMappingSchema(String key) { if (key == null) return null; String result = SCHEMA_MAPPING.get(key.toUpperCase()); if (result == null) return key; return result.length() == 0 ? null : result; } /** * 获得重定向后的Site * * @param key * @return 如果返回"",表示无Site 如果返回入参本身,表示不作改动 其他情况,返回重定向的Site */ public static String getMappingSite(String key) { if (key == null) return null; String result = SITE_MAPPING.get(key.toLowerCase()); if (result == null) return key; return result.length() == 0 ? null : result; } /** * 根据数据库的表情况,初始化动态表的模型 初始化完成后会缓存起来,下次获取可以直接用{@link #getMeta(String)}得到 * * @param session * 数据库访问句柄 Session. * @param tableName * 表名 * @return */ public static TupleMetadata initMetadata(Session session, String tableName) throws SQLException { return initMetadata(session, tableName, true); } /** * 根据数据库的表情况,初始化动态表的模型 初始化完成后会缓存起来,下次获取可以直接用{@link #getMeta(String)}得到 * * @param session * 数据库访问句柄 Session. * @param tableName * 表名 * @param convertColumnNames * 是否将数据库的列名转换为 java 习惯。 <br/> * eg. CREATE_TIME -> createTime * @return */ public static TupleMetadata initMetadata(Session session, String tableName, boolean convertColumnNames) throws SQLException { DbMetaData meta = session.getNoTransactionSession().getMetaData(null); List<TableInfo> table = meta.getTable(tableName); if (table.isEmpty()) { throw new SQLException("The table " + tableName + " does not exit in database " + session.getNoTransactionSession().toString()); } PrimaryKey pks = meta.getPrimaryKey(tableName); List<jef.database.meta.Column> columns = meta.getColumns(tableName, false); TupleMetadata m = new TupleMetadata(tableName); for (jef.database.meta.Column c : columns) { boolean isPk = (pks == null) ? false : pks.hasColumn(c.getColumnName()); // m.addColumn(c.getColumnName(), c.getColumnName(), // c.toColumnType(meta.getProfile()), isPk); m.addColumn(DbUtils.underlineToUpper(c.getColumnName(), false), c.getColumnName(), c.toColumnType(meta.getProfile()), isPk); } putDynamicMeta(m); return m; } /** * 放置动态表的模型 * * @param meta */ public static void putDynamicMeta(TupleMetadata meta) { String name = meta.getTableName(true).toUpperCase(); TupleMetadata old = dynPool.put(name, meta); if (old != null) { LogUtil.warn("replace tuple metadata:{}", name); } } /** * 返回动态表的模型 * * @param name * @return */ public static TupleMetadata getDynamicMeta(String name) { if (name == null) return null; return dynPool.get(name.toUpperCase()); } /** * 初始化数据,可以指定schema和tablename * * @param clz * 实体类 * @param schema * 传入null表示不修改默认的schema,传""表示修改为当前数据库schema,传入其他则为指定的schema * @param tablename * 传入null表示不修正 * @return */ public static ITableMetadata initMetadata(Class<? extends IQueryableEntity> clz, String schema, String tablename) { Assert.notNull(clz); ITableMetadata me = (TableMetadata) pool.get(clz); // initData方法会处理关于缓存的问题 me = initData(clz); if (me instanceof TableMetadata) { TableMetadata m = (TableMetadata) me; if (schema != null) m.setSchema(getMappingSchema(schema)); if (StringUtils.isNotEmpty(tablename)) m.setTableName(tablename); } return me; } /** * 将一个对象名(数据表、索引等)转换为schemaMapping后的名称 * * @param objectName */ public static String toSchemaAdjustedName(String objectName) { if (objectName == null) { return null; } int n = objectName.indexOf('.'); if (n < 0) return objectName; String schema = objectName.substring(0, n); String schema1 = MetaHolder.getMappingSchema(schema); if (schema == schema1) { return objectName; } return schema1 == null ? objectName.substring(n + 1) : schema1.concat(objectName.substring(n)); } /** * 获取所有已经缓存的动态表模型 * * @return */ public static Collection<TupleMetadata> getCachedDynamicModels() { return dynPool.values(); } /** * 获取所有已经缓存的静态表模型 */ public static Collection<AbstractMetadata> getCachedModels() { return pool.values(); } /** * 得到指定类的元数据。该类可以是一个标准的GeeQueryEntity,也可以是一个POJO。 * * @param clz * @return */ public static final AbstractMetadata getMetaOrTemplate(Class<?> clz) { Assert.notNull(clz); if (clz == VarObject.class) { throw new IllegalArgumentException("A VarObject class does not indicted to any table metadata."); } AbstractMetadata m = pool.get(clz); if (m == null) { m = initData(clz); } return m; } /** * 根据类获取表模型 * * @param clz * @return */ public static final AbstractMetadata getMeta(Class<?> clz) { Assert.notNull(clz); if (clz == VarObject.class) { throw new IllegalArgumentException("A VarObject class does not indicted to any table metadata."); } AbstractMetadata m = pool.get(clz); if (m == null) { m = initData(clz); } if (m.getType() == EntityType.TEMPLATE) { throw new IllegalArgumentException("A Template class does not indicted to any table metadata."); } return m; } /** * 获取metadata * * @param d * @return */ public final static AbstractMetadata getMeta(Object d) { if (d instanceof MetadataContainer) { return (AbstractMetadata) ((MetadataContainer) d).getMeta(); } AbstractMetadata metadata = getMeta(d.getClass()); if (metadata.getType() == EntityType.TEMPLATE) { return metadata.getExtension((IQueryableEntity) d).getMeta(); } return metadata; } private static boolean isFirstInterfaceClzEntity(Class<?> sc) { Class<?>[] interfaces = sc.getInterfaces(); if (interfaces == null || interfaces.length == 0) return false; return ArrayUtils.contains(interfaces, IQueryableEntity.class); } /** * 在获取类时,需要有一个标记快速判断该类是否经过增强(无论是动态增强还是静态增强)一旦发现没增强的类,就抛出异常�? * * @param clz * @return */ private synchronized static AbstractMetadata initData(Class<?> clz) { { AbstractMetadata m1 = pool.get(clz); if (m1 != null) return m1; // 双重检查锁定 } if (IQueryableEntity.class.isAssignableFrom(clz)) { // 计算动态扩展字段 DynamicTable dt = clz.getAnnotation(DynamicTable.class); DynamicKeyValueExtension dkv = clz.getAnnotation(DynamicKeyValueExtension.class); if (dt == null && dkv == null) {// 两种扩展方式只能出现一种 return initEntity(clz.asSubclass(IQueryableEntity.class)); } else if (dt != null) { return initVarTemplate(clz.asSubclass(EntityExtensionSupport.class), dt); } else if (dkv != null) { return initVarEntity(clz.asSubclass(EntityExtensionSupport.class), dkv); } else { throw new UnsupportedOperationException("Not support @DynamicTable and @DynamicKeyValueExtension simultaneously."); } } else { return initPojo(clz); } } private static AbstractMetadata initVarTemplate(Class<? extends EntityExtensionSupport> clz, DynamicTable dt) { ClassAnnotationProvider annos = config.getAnnotations(clz); List<java.lang.reflect.Field> unprocessedField = new ArrayList<java.lang.reflect.Field>(); TableMetadata meta = internalProcess(clz, unprocessedField, annos); // 加载分表策略 Assert.notNull(partitionLoader, "the Partition loader is null!"); if (partitionLoader.get(clz) != null) { throw new UnsupportedOperationException("Not support a dynamic template with partition."); } ExtensionTemplate ef = new ExtensionTemplate(dt, clz, meta); EfPropertiesExtensionProvider.getInstance().register(clz, ef); TemplateMetadata result = new TemplateMetadata(ef); result.setUnprocessedFields(unprocessedField, annos); pool.put(clz, result); return result; } private static AbstractMetadata initVarEntity(Class<? extends EntityExtensionSupport> clz, DynamicKeyValueExtension dkv) { ClassAnnotationProvider annos = config.getAnnotations(clz); List<java.lang.reflect.Field> unprocessedField = new ArrayList<java.lang.reflect.Field>(); TableMetadata raw = internalProcess(clz, unprocessedField, annos); // 加载分表策略 Assert.notNull(partitionLoader, "the Partition loader is null!"); raw.setPartition(partitionLoader.get(clz)); KvExtensionImpl ef = new KvExtensionImpl(dkv, clz, raw); EfPropertiesExtensionProvider.getInstance().register(clz, ef); AbstractMetadata meta = ef.getDefault().getMeta(); // 此时就将基本字段计算完成的元数据加入缓存,以免在多表关系处理时遭遇死循环 pool.put(clz, meta); ef.initMeta(); // 针对未处理的字段,当做外部引用关系处理 for (java.lang.reflect.Field f : unprocessedField) { // 将这个字段作为外部引用处理 processReference(meta, annos.forField(f)); } return meta; } private static AbstractMetadata initPojo(Class<?> clz) { ClassAnnotationProvider annos = config.getAnnotations(clz); TableMetadata meta = new TableMetadata(PojoWrapper.class, clz, annos); List<java.lang.reflect.Field> unprocessedField = new ArrayList<java.lang.reflect.Field>(); MeteModelFields metaFields = new MeteModelFields(clz, meta); Class<?> processingClz = clz; while (processingClz != Object.class) { processMetaForClz(processingClz, unprocessedField, meta, annos, metaFields); processingClz = processingClz.getSuperclass(); if (isFirstInterfaceClzEntity(processingClz)) { break; } } metaFields.check(); return meta; } private static AbstractMetadata initEntity(Class<? extends IQueryableEntity> clz) { ClassAnnotationProvider annos = config.getAnnotations(clz); List<java.lang.reflect.Field> unprocessedField = new ArrayList<java.lang.reflect.Field>(); TableMetadata meta = internalProcess(clz, unprocessedField, annos); // 加载分表策略 Assert.notNull(partitionLoader, "the Partition loader is null!"); meta.setPartition(partitionLoader.get(clz)); // 此时就将基本字段计算完成的元数据加入缓存,以免在多表关系处理时遭遇死循环 pool.put(clz, meta); // 针对未处理的字段,当做外部引用关系处理 for (java.lang.reflect.Field f : unprocessedField) { // 将这个字段作为外部引用处理 processReference(meta, annos.forField(f)); // 还有一种情况,即定义了Column注解,但不属于元模型的一个字段,用于辅助映射的。当结果拼装时有用 processColumnHelper(meta, annos.forField(f)); } return meta; } private static TableMetadata internalProcess(Class<? extends IQueryableEntity> clz, List<java.lang.reflect.Field> unprocessedField, ClassAnnotationProvider annos) { { EasyEntity ee = annos.getAnnotation(EasyEntity.class); if (ORMConfig.getInstance().isCheckEnhancement()) { assertEnhanced(clz, ee, annos); } } TableMetadata meta = new TableMetadata(clz, annos); MeteModelFields metaFields = new MeteModelFields(clz, meta); Class<?> processingClz = clz; while (processingClz != Object.class) { processMetaForClz(processingClz, unprocessedField, meta, annos, metaFields); if (processingClz != clz) { meta.addParent(processingClz); } processingClz = processingClz.getSuperclass();// 父类:下一个要解析的类 if (isFirstInterfaceClzEntity(processingClz)) { break; } } metaFields.check(); return meta; } // 处理非元模型的Column描述字段 private static void processColumnHelper(TableMetadata meta, FieldAnnotationProvider field) { Column column = field.getAnnotation(Column.class); if (column != null) { meta.addNonMetaModelFieldMapping(field.getName(), column); } } /** * 检查是否执行了增强 * * @param type */ private static void assertEnhanced(Class<? extends IQueryableEntity> type, EasyEntity ee, AnnotationProvider annos) { if (annos.getAnnotation(NoForceEnhance.class) != null) { return; } if (ee != null && ee.checkEnhanced() == false) { return; } // 如果实体扫描时作了动态增强的话 if (QuerableEntityScanner.dynamicEnhanced.contains(type.getName())) { return; } // 仅需对非JefClassLoader加载的类做check. if (type.getClassLoader().getClass().getName().equals(JefClassLoader.class.getName())) { return; } String resourceName = type.getName().replace('.', '/') + ".class"; URL url = type.getClassLoader().getResource(resourceName); if (url == null) { LogUtil.warn("The source of class " + type + " not found, skip enhanced-check."); return; } byte[] data; try { data = IOUtils.toByteArray(url); } catch (IOException e) { throw new IllegalStateException(e); } ClassReader cr = new ClassReader(data); final Holder<Boolean> checkd = new Holder<Boolean>(false); cr.accept(new ClassVisitor(Opcodes.ASM5) { public void visitAttribute(Attribute attr) { if ("jefd".equals(attr.type)) { checkd.set(true); } super.visitAttribute(attr); } }, ClassReader.SKIP_CODE); if (!checkd.get()) { throw new EntityNotEnhancedException(type.getName()); } } static class MeteModelFields { private boolean isTuple; ArrayListMultimap<String, Field> enumFields; private ITableMetadata parent; MeteModelFields(Class<?> clz, ITableMetadata meta) { isTuple = !IQueryableEntity.class.isAssignableFrom(clz); parent = meta; if (isTuple) return; enumFields = com.google.common.collect.ArrayListMultimap.create(); Class<?> looping = clz; while (looping != Object.class) { for (Class<?> c : looping.getDeclaredClasses()) { if (c.isEnum() && ArrayUtils.contains(c.getInterfaces(), jef.database.Field.class)) { @SuppressWarnings("rawtypes") Class<? extends Enum> sub = c.asSubclass(Enum.class); for (Enum<?> fieldDef : sub.getEnumConstants()) { Field field = (Field) fieldDef; enumFields.put(field.name(), field);// 父类的放在后面,子类的放在前面。 } break; } } looping = looping.getSuperclass(); } } public void check() { if (hasMappingFailure()) { throw new IllegalArgumentException("These meta model field is not exist in [" + parent.getName() + "]:" + enumFields.keySet()); } } /** * 由于用户可能在父子类中反复定义同一个Field的元模型,因此此处返回的是列表 * @param name * @return */ List<jef.database.Field> remove(String name) { if (isTuple) { return Collections.<Field> singletonList(new TupleField(parent, name)); } return enumFields.removeAll(name); } boolean hasMappingFailure() { if (isTuple) { return false; } else { return !enumFields.isEmpty(); } } } private static void processMetaForClz(Class<?> processingClz, List<java.lang.reflect.Field> unprocessedField, TableMetadata meta, ClassAnnotationProvider annos, MeteModelFields metaModel) { for (java.lang.reflect.Field f : processingClz.getDeclaredFields()) { if (Modifier.isStatic(f.getModifiers())) continue; if (meta.getField(f.getName()) != null) { // 当子类父类中有同名field时,跳过父类的field continue; } FieldAnnotationProvider fa = annos.forField(f); List<Field> fieldss = metaModel.remove(f.getName()); if (fieldss.isEmpty() || fa.getAnnotation(Transient.class)!=null) { unprocessedField.add(f); continue; } Field field = fieldss.get(0); if (field instanceof Enum) { assertFieldEnhanced(field,fieldss,processingClz); } // 在得到了元模型的情况下 boolean isPK = fa.getAnnotation(javax.persistence.Id.class) != null; jef.database.annotation.Type customType = fa.getAnnotation(jef.database.annotation.Type.class); ColumnMapping type = null; Class<?> fieldType; if (customType != null) { type = BeanUtils.newInstance(customType.value()); try { ColumnTypeBuilder.applyParams(customType.parameters(), type); } catch (Exception e) { throw new IllegalArgumentException("@Type annotation on field " + processingClz + "." + field + " is invalid", e); } fieldType = type.getFieldType(); } else { fieldType = f.getType(); } Column c = fa.getAnnotation(Column.class); ColumnType ct; try { ct = new ColumnTypeBuilder(c, f, fieldType, fa).withCustomType(type).build(); } catch (Exception e) { throw new PersistenceException(processingClz + " has invalid field/column " + f.getName(), e); } if (isPK) ct.setNullable(false); try { String columnName = getColumnName(field, c); if (type == null) { type = ColumnMappings.getMapping(field, meta, columnName, ct, false); } else { type.init(field, columnName, ct, meta); } meta.putJavaField(field, type, columnName, isPK); } catch (IllegalArgumentException e) { throw new PersistenceException(meta.getName() + ":" + field.name() + " can not mapping to sql type.", e); } // 设置索引 Indexed i = fa.getAnnotation(Indexed.class);// 单列索引 if (i != null) { IndexDef indexDef = new IndexDef(i.name(), new String[] { i.desc() ? field.name() + " desc" : field.name() }); indexDef.setUnique(i.unique()); indexDef.setDefinition(i.definition()); meta.indexes.add(indexDef); } } } private static void assertFieldEnhanced(Field field, List<Field> fieldss,Class<?> processingClz) { /* * 必须至少有一个meta field的定义类== * processingClz。这样才能保证这个属性被增强过。否则不能保证该属性被增强过。 * * 因为目前增强算法都只按当前类的enum Field中的枚举来增强属性。不会去增强父类中的属性。 * 所以如果在父类中定义属性而在子类中定义元模型来使用。这个属性就会有未被增强的风险。 * * 增加这样的检查逻辑,有利于用户在复杂继承关系下,确保父类的元模型不缺失,从而安全的使用。 * * 关于为什么不作增强父类的功能: a 父类可能在JAR包中,不能直接修改。 b * 如果在子类中通过覆盖方法来实现,也有问题,因为ASM中去解析父类并查找同名方法较为复杂 * 。在增强前,不能调用类实现反射,因此相当于要自行用ASM实现父子类解析的JAVA逻辑,太麻烦了…… c * 此外,如果父类本身也定义了该元模型 * ,子类覆盖父类元模型,此时也很悲剧——子类生成一个增强过的方法覆盖父类方法,而父类本身又做了增强 * ,此时延迟加载和等植入代码将被执行两遍。 * 因此,我们还是要尽可能避免这种父类定义属性,子类定义元模型的方式。即元模型要定义在各自的类里,子类可以覆盖父类的。 */ boolean isEnhancedProperty = false; for (Field ff : fieldss) { Class<?> cc = ff.getClass().getDeclaringClass(); if (cc == processingClz) { isEnhancedProperty = true; break; } } if (!isEnhancedProperty) { throw new IllegalArgumentException("Field [" + field.name() + "] may be not enhanced. Please add the enum Field [" + field.name() + "] into " + processingClz.getName()); } } private static String getColumnName(Field field, Column a) { if (a != null && a.name().length() > 0) { return a.name().trim(); } else { return field.name(); } } private static JoinPath getHint(FieldAnnotationProvider annos, AbstractMetadata meta, ITableMetadata target) { if (annos.getAnnotation(JoinColumn.class) != null) { JoinColumn j = annos.getAnnotation(JoinColumn.class); return processJoin(meta, target, annos, j); } else if (annos.getAnnotation(JoinColumns.class) != null) { JoinColumns jj = annos.getAnnotation(JoinColumns.class); return processJoin(meta, target, annos, jj.value()); } else if (annos.getAnnotation(JoinTable.class) != null) { JoinTable jt = annos.getAnnotation(JoinTable.class); return processJoin(meta, target, annos, jt); } return null; } private static JoinPath processJoin(AbstractMetadata meta, ITableMetadata target, FieldAnnotationProvider annos, JoinTable jt) { String table = jt.name(); LogUtil.info("创建从{}到{}的关系。", meta.getName(), target.getName()); // 计算生成关系表 TupleMetadata rt = getDynamicMeta(table); JoinColumn[] jc1 = jt.joinColumns(); String thisName = meta.getName().replace('.', '_'); if (rt == null) { rt = new TupleMetadata(table); for (JoinColumn jc : jc1) { ColumnType ct = meta.getColumnType(jc.referencedColumnName()); rt.addColumn(jc.name(), jc.name(), toNormal(ct), jt.uniqueConstraints().length > 0); rt.addIndex(jc.name(), null); } JoinColumn[] jc2 = jt.inverseJoinColumns(); for (JoinColumn jc : jc2) { String name = jc.referencedColumnName(); ColumnMapping ct = target.getColumnDef(target.getField(name)); Assert.notNull(ct); rt.addColumn(jc.name(), jc.name(), toNormal(ct.get()), jt.uniqueConstraints().length > 0); rt.addIndex(jc.name(), null); } // 补充关系表注册 putDynamicMeta(rt); } AbstractRefField refs = rt.getRefFieldsByName().get(thisName + "_OBJ"); if (refs == null) { JoinColumn[] jc2 = jt.inverseJoinColumns(); // 创建关系表到目标表的连接 JoinPath path2 = processJoin(rt, target, annos, jc2); rt.addCascadeManyToOne(thisName + "_OBJ", target, path2); } refs = rt.getRefFieldsByName().get(thisName + "_OBJ"); Assert.notNull(refs); // 创建到关系表的连接 JoinColumn[] jc3 = new JoinColumn[jc1.length]; for (int i = 0; i < jc1.length; i++) { JoinColumnImpl jc = new JoinColumnImpl(jc1[i]); jc.reverseColumn(); jc3[i] = jc; } JoinPath path1 = processJoin(meta, rt, annos, jc3); path1.setRelationTable(rt, refs.getReference().getHint()); return path1; } private static ColumnType toNormal(ColumnType columnType) { if (columnType instanceof AutoIncrement) { return ((AutoIncrement) columnType).toNormalType(); } else if (columnType instanceof ColumnType.GUID) { return ((GUID) columnType).toNormalType(); } return columnType; } protected static boolean processReference(AbstractMetadata meta, FieldAnnotationProvider field) { FieldOfTargetEntity targetField = field.getAnnotation(FieldOfTargetEntity.class); Cascade cascade = field.getAnnotation(Cascade.class); if (field.getAnnotation(OneToOne.class) != null) { OneToOne r1Vs1 = field.getAnnotation(OneToOne.class); ITableMetadata target = getTargetType(r1Vs1.targetEntity(), targetField, field, false); CascadeConfig config = new CascadeConfig(cascade, r1Vs1); config.path = getHint(field, meta, target); if (config.path == null) { String mappedBy = r1Vs1.mappedBy(); if (StringUtils.isNotEmpty(mappedBy)) { config.path = processJoin(meta, target, field, mappedBy); } } if (targetField == null) { meta.addCascadeField(field.getName(), target, config); } else { jef.database.Field targetf = target.getField(targetField.value()); meta.addCascadeField(field.getName(), targetf, config); } return true; } if (field.getAnnotation(OneToMany.class) != null) { OneToMany r1VsN = field.getAnnotation(OneToMany.class); ITableMetadata target = getTargetType(r1VsN.targetEntity(), targetField, field, true); CascadeConfig config = new CascadeConfig(cascade, r1VsN); config.path = getHint(field, meta, target); if (config.path == null) { String mappedBy = r1VsN.mappedBy(); if (StringUtils.isNotEmpty(mappedBy)) { config.path = processJoin(meta, target, field, mappedBy); } } if (targetField == null) { meta.addCascadeField(field.getName(), target, config); } else { jef.database.Field targetf = target.getField(targetField.value()); meta.addCascadeField(field.getName(), targetf, config); } return true; } if (field.getAnnotation(ManyToOne.class) != null) { ManyToOne rNVs1 = field.getAnnotation(ManyToOne.class); ITableMetadata target = getTargetType(rNVs1.targetEntity(), targetField, field, false); CascadeConfig config = new CascadeConfig(cascade, rNVs1); config.path = getHint(field, meta, target); if (targetField == null) { meta.addCascadeField(field.getName(), target, config); } else { jef.database.Field targetf = target.getField(targetField.value()); meta.addCascadeField(field.getName(), targetf, config); } return true; } if (field.getAnnotation(ManyToMany.class) != null) { ManyToMany rNVsN = field.getAnnotation(ManyToMany.class); ITableMetadata target = getTargetType(rNVsN.targetEntity(), targetField, field, true); CascadeConfig config = new CascadeConfig(cascade, rNVsN); config.path = getHint(field, meta, target); if (config.path == null) { String mappedBy = rNVsN.mappedBy(); if (StringUtils.isNotEmpty(mappedBy)) { config.path = processJoin(meta, target, field, mappedBy); } } if (targetField == null) { meta.addCascadeField(field.getName(), target, config); } else { jef.database.Field targetf = target.getField(targetField.value()); meta.addCascadeField(field.getName(), targetf, config); } return true; } return false; } /** * 计算出目标连接的类型 * * @param targetEntity * @param targetField * @param type * @param isMany * 是toMany类型的连�? * @return */ private static ITableMetadata getTargetType(Class<?> targetEntity, FieldOfTargetEntity targetField, FieldAnnotationProvider field, boolean isMany) { if (targetEntity != void.class) { if (IQueryableEntity.class.isAssignableFrom(targetEntity)) { return MetaHolder.getMeta(targetEntity.asSubclass(IQueryableEntity.class)); } else { throw new IllegalArgumentException("The target entity type [" + targetEntity.getName() + "] for " + field.getDeclaringClass().getSimpleName() + ":" + field.getName() + " is not subclass of DataObject."); } } if (targetField != null) { throw new IllegalArgumentException(field.getDeclaringClass().getSimpleName() + ":" + field.getName() + " miss its targetEntity annotation."); } if (isMany) { Class<?> compType = CollectionUtils.getSimpleComponentType(field.getGenericType()); if (compType != null && IQueryableEntity.class.isAssignableFrom(compType)) { return MetaHolder.getMeta(compType.asSubclass(IQueryableEntity.class)); } } else { Class<?> compType = field.getType(); if (IQueryableEntity.class.isAssignableFrom(compType)) { return MetaHolder.getMeta(compType.asSubclass(IQueryableEntity.class)); } } throw new IllegalArgumentException(field.getDeclaringClass().getSimpleName() + ":" + field.getName() + " miss its targetEntity annotation."); } private static JoinPath processJoin(AbstractMetadata thisMeta, ITableMetadata target, AnnotationProvider field, JoinColumn... jj) { List<JoinKey> result = new ArrayList<JoinKey>(); String fieldName = field.getName(); for (JoinColumn j : jj) { if (StringUtils.isBlank(j.name())) { throw new IllegalArgumentException("Invalid reference [" + thisMeta.getThisType().getName() + "." + fieldName + "]:The field 'name' in JoinColumn is empty"); } Field left = thisMeta.getField(j.name()); Assert.notNull(left, "Invalid reference [" + thisMeta.getThisType().getName() + "." + fieldName + "]: field [" + j.name() + "] not found from entity " + thisMeta.getThisType().getName()); Field right = target.getField(j.referencedColumnName()); if (right == null) { throw new NoResultException("Invalid reference [" + thisMeta.getThisType().getName() + "." + fieldName + "]: '" + j.referencedColumnName() + "' is not available in " + target.getThisType().getName()); } result.add(new JoinKey(left, right)); } JoinType type = JoinType.LEFT; JoinDescription joinDesc = field.getAnnotation(JoinDescription.class); if (joinDesc != null) { type = joinDesc.type(); } if (result.size() > 0) { JoinPath path = new JoinPath(type, result.toArray(new JoinKey[result.size()])); path.setDescription(joinDesc, field.getAnnotation(OrderBy.class)); if (joinDesc != null && joinDesc.filterCondition().length() > 0) { JoinKey joinExpress = getJoinExpress(thisMeta, target, joinDesc.filterCondition().trim()); if (joinExpress != null) path.addJoinKey(joinExpress); } return path; } return null; } private static JoinPath processJoin(ITableMetadata meta, ITableMetadata target, AnnotationProvider annos, String mappedBy) { JoinDescription joinDesc = annos.getAnnotation(JoinDescription.class); OrderBy orderBy = annos.getAnnotation(OrderBy.class); List<JoinKey> result = new ArrayList<JoinKey>(); if (meta.getPKFields().size() != 1) { throw new IllegalArgumentException(meta.getSimpleName() + " cann't map to " + target.getSimpleName() + " since its primary key field count " + meta.getPKFields().size()); } Field left = meta.getPKFields().get(0).field(); Field right = target.getField(mappedBy); if (right == null) { throw new IllegalArgumentException(meta.getSimpleName() + " cann't map to " + target.getSimpleName() + " since there is no field [" + mappedBy + "] in target entity"); } result.add(new JoinKey(left, right)); JoinType type = JoinType.LEFT; if (joinDesc != null) { type = joinDesc.type(); } if (result.size() > 0) { JoinPath path = new JoinPath(type, result.toArray(new JoinKey[result.size()])); path.setDescription(joinDesc, orderBy); if (joinDesc != null && joinDesc.filterCondition().length() > 0) { JoinKey joinExpress = getJoinExpress(meta, target, joinDesc.filterCondition().trim()); if (joinExpress != null) path.addJoinKey(joinExpress); } return path; } return null; } private static JoinKey getJoinExpress(ITableMetadata thisMeta, ITableMetadata targetMeta, String exp) { try { Expression ex = DbUtils.parseBinaryExpression(exp); if (ex instanceof BinaryExpression) { BinaryExpression bin = (BinaryExpression) ex; String left = bin.getLeftExpression().toString().trim(); Field leftF = parseField(left, thisMeta, targetMeta); JoinKey key; if (leftF == null) { key = new JoinKey(null, null, new FBIField(bin, ReadOnlyQuery.getEmptyQuery(targetMeta)));// 建立一个函数Field } else { String oper = bin.getStringExpression(); Expression right = bin.getRightExpression(); Field rightF = null; if (right.getType() == ExpressionType.column || right.getType() == ExpressionType.function) { rightF = parseField(right.toString(), thisMeta, targetMeta); } if (rightF == null) { key = new JoinKey(leftF, Operator.valueOfKey(oper), new JpqlExpression(right.toString())); } else { key = new JoinKey(leftF, Operator.valueOfKey(oper), rightF); } } return key; } else { throw new RuntimeException("the expression " + exp + " is not a Binary Expression but a " + ex.getClass().getName()); } } catch (ParseException e) { throw new RuntimeException("Unknown expression config on class:" + targetMeta.getThisType().getName() + ": " + exp); } } private static Field parseField(String keyword, ITableMetadata thisMeta, ITableMetadata target) { ITableMetadata meta = null; if (keyword.startsWith("this$")) { keyword = keyword.substring(5); meta = thisMeta; } else if (keyword.startsWith("that$")) { keyword = keyword.substring(5); meta = target; } if (meta != null) { ColumnMapping columnDef = meta.findField(keyword);// 假定左边的是字段 if (columnDef != null) { return columnDef.field(); } else { FBIField field = new FBIField(keyword, ReadOnlyQuery.getEmptyQuery(meta)); field.setBindBase(true); ; return field; } } else { ColumnMapping columnDef = target.findField(keyword); if (columnDef != null) { return columnDef.field(); } columnDef = thisMeta.findField(keyword); if (columnDef != null) { return columnDef.field(); } return null; } } /** * 逆向查找元模型 * * @param schema * @param table */ public static AbstractMetadata lookup(String schema, String table) { String key = (schema + "." + table).toUpperCase(); AbstractMetadata m = inverseMapping.get(key); if (m != null) return m; // Schema还原 if (schema != null) { schema = schema.toUpperCase(); for (Entry<String, String> e : SCHEMA_MAPPING.entrySet()) { if (e.getValue().equals(schema)) { schema = e.getKey(); break; } } } // Lookup static models for (AbstractMetadata meta : pool.values()) { String tablename = meta.getTableName(false); if (schema != null && (!StringUtils.equals(meta.getSchema(), schema))) {// schema不同则跳 continue; } if (tablename.equalsIgnoreCase(table)) { m = meta; break; } } if (m == null) { // Lookup dynamic models for (AbstractMetadata meta : dynPool.values()) { String tablename = meta.getTableName(false); if (schema != null && (!StringUtils.equals(meta.getSchema(), schema))) {// schema不同则跳 continue; } if (tablename.equalsIgnoreCase(table)) { m = meta; break; } } } inverseMapping.put(key, m); return m; } public static void clear() { pool.clear(); dynPool.clear(); inverseMapping.clear(); } }