package jef.database.wrapper.populator; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import jef.database.IQueryableEntity; import jef.database.PojoWrapper; import jef.database.Session.PopulateStrategy; import jef.database.VarObject; import jef.database.meta.ITableMetadata; import jef.database.meta.MetaHolder; import jef.database.query.SqlContext; import jef.database.wrapper.populator.Mappers.BeanMapper; import jef.script.javascript.Var; import jef.tools.ArrayUtils; import jef.tools.Assert; import jef.tools.StringUtils; /** * 查询结果转换器。 * 用于描述对查询结果的转换(拼装)策略 * * 用户可以使用此类—— * <ul> * <li>{@linkplain #setResultType(Class)} | {@linkplain #setResultType(ITableMetadata)}<br>指定查询的操作结果</li> * <li>{@linkplain #setLoadVsMany(boolean)}<br>指定是否加载对多关联的字段</li> * <li>{@link #setLoadVsOne(boolean)}<br>指定是否加载对一关联的字段</li> * <li>{@link #addMapper(Mapper)}<br>指定自定义的映射器,例子参见 {@link Mappers}</li> * <li>{@link #ignoreAll()} | {@link #ignoreColumn(String)} | {@link #ignoreSchema(String)}<br>让框架在拼装结果时忽略指定的列</li> * </ul> * * @author jiyi * */ public class Transformer { /** * @see PopulateStrategy */ private PopulateStrategy[] strategy; /** * 返回的对象类 */ Class<?> resultClazz; /** * 如果resultClazz是VarObject,那么指定TableMetadata */ ITableMetadata meta; /** * 默认情况下,ORM总是根据结果类的字段名(列名)去对应查询结果中的各个字段,从而映射出返回的对象。<br> * 一旦ignoreAll,ORM将不再使用任何内建映射策略,而是完全以用户自定义的Mapper来映射 */ private boolean ignoreAll; /** * 让内建映射规则忽略这些列。 */ private Set<String> ignoreColumns; // 所有不需要系统默认拼装的列的名称 大写 /** * 让内建映射规则忽略这些别名的前缀。例如 select id as T1__ID ...这里两个下划线前面的T1就是前缀。 */ private Set<String> ignoreSchemas; // 所有不需要系统默认拼装的列的名称 大写 /** * 自定义的映射器。可以自己编写代码实现,也可以使用{@link Mappers}里的工具方法自动生成。 * * @see Mappers */ private List<Mapper<?>> mapper;// replace populator /** * 记录自定义的映射器所写入的字段名,可能为null,数量总是和mapper的数量一致 */ private List<String> mapperProperties; /** * 是否加载対一关联 */ private boolean loadVsOne; /** * 是否加载对多关联 */ private boolean loadVsMany; public static final Transformer VAR = new Transformer(Var.class); /** * 空构造 */ public Transformer() { } /** * 构造一个Transformer * * @param clz 返回结果类型 * @param strategies 返回结果转换策略 */ public Transformer(Class<?> clz, PopulateStrategy... strategies) { this.strategy = strategies; setResultType(clz); } /** * 构造一个ResultTransformer * * @param meta 返回结果类型模型 * @param strategies 返回结果转换策略 */ public Transformer(ITableMetadata meta, PopulateStrategy... strategies) { setResultType(meta); this.strategy = strategies; } /** * 返回结果转换策略 * * @return 结果转换策略 */ public PopulateStrategy[] getStrategy() { return strategy; } /** * 设置结果转换策略 * * @param strategy 结果转换策略. * @see PopulateStrategy */ public void setStrategy(PopulateStrategy... strategy) { this.strategy = strategy; } /** * 增加一个结果转换策略 * * @param strategy */ public void addStrategy(PopulateStrategy strategy) { if (this.strategy == null || this.strategy.length == 0) { this.strategy = new PopulateStrategy[] { strategy }; } else { this.strategy = ArrayUtils.addElement(this.strategy, strategy); } } /** * 获得结果转换类 * * @return 结果类 */ public Class<?> getResultClazz() { return resultClazz; } /** * 如果是复杂对象,得到metadata * * @return 结果是数据库实体得到metadata,如果是简单类型返回null */ public ITableMetadata getResultMeta() { return meta; } /** * 获得排除列 * * @return 框架不进行转换的结果列 */ public Set<String> getSkipColumns() { return ignoreColumns; } /** * 设置查询结果排除列 * * @param skipColumns 排除这些列。框架在拼装结果时不会处理查询结果中的这些列。用户可以用自定义的映射器(mapper)处理这些列。 * @see Mapper */ public void setSkipColumns(Set<String> skipColumns) { this.ignoreColumns = skipColumns; } /** * 获得自定义映射器 * * @return 所有自定义映射器 * @see Mapper */ @SuppressWarnings("unchecked") public List<Mapper<?>> getMapper() { return mapper == null ? Collections.EMPTY_LIST : mapper; } /** * 设置自定义映射器 * @param mapper 自定义的映射器 */ public void setMapper(List<Mapper<?>> mapper) { this.mapper = mapper; } /** * 排除所有列。让框架在拼装结果是不处理查询中的所有列。此时只有用户自定义的映射器(Mapper)会生效。 */ public void ignoreAll() { ignoreAll = true; } /** * 让ORM默认转换器不处理该命名空间下所有列 * * @param schema */ public void ignoreSchema(String schema) { if (schema == null) return; if (ignoreSchemas == null) { ignoreSchemas = new HashSet<String>(4); } ignoreSchemas.add(schema.toUpperCase()); } /** * 让ORM默认转换器不处理该列 * * @param column */ public void ignoreColumn(String column) { if (StringUtils.isEmpty(column)) return; if (ignoreColumns == null) { ignoreColumns = new HashSet<String>(8); } ignoreColumns.add(column.toUpperCase()); } /** * 让ORM默认转换器不处理这些列 * * @param schema 命名空间 * @param column 列名 */ public void ignoreColumn(String schema, String column) { if (schema == null && column == null) { return; } if (schema == null) { ignoreColumn(column); } else if (column == null) { ignoreSchema(schema); } else { ignoreColumn(schema + SqlContext.DIVEDER + column); } } /** * 清除所有自定义映射器. */ public void clearMapper() { if (mapper != null) { mapper.clear(); } if (mapperProperties != null) { mapperProperties.clear(); } } /** * 添加一个自定义的映射器。Mapper可以自定实现,也可以从Mappers工具类构造。 * * @param accessor * @see Mappers */ public void addMapper(Mapper<?> accessor) { if (accessor != null) { if (mapper == null) { mapper = new ArrayList<Mapper<?>>(); } mapper.add(accessor); if (accessor instanceof Mappers.BeanMapper) { BeanMapper<?> s = (BeanMapper<?>) accessor; addMapperProperties(s.toField); } } } private void addMapperProperties(String value){ if(value==null)return; if(mapperProperties==null){ mapperProperties = new ArrayList<String>(); } mapperProperties.add(value); } /* * 内部使用 */ void prepareTransform(Map<String, ColumnDescription> nameIndex) { if (mapper != null) { for (Mapper<?> m : mapper) { m.prepare(nameIndex); } } } /* * 内部使用 */ boolean hasIgnoreSchema(String schema) { if (ignoreAll) return true; return ignoreSchemas == null ? false : ignoreSchemas.contains(schema); } /* * 内部使用 */ boolean hasIgnoreColumn(String column) { if (ignoreAll) return true; return ignoreColumns == null ? false : ignoreColumns.contains(column); } /* * 内部使用:当使用自定义查询需要返回多个结果类的时候,用这个方法来计算数组的长度。 */ int getMaxMapperIndex() { int max = 0; if (mapperProperties != null) { for (String s : mapperProperties) { if (StringUtils.isNumeric(s)) { try { int index = Integer.parseInt(s); if (index > max) max = index; } catch (NumberFormatException e) {// Skip } } } } return max; } /* * 内部使用 */ public boolean hasStrategy(PopulateStrategy ps) { if (strategy == null) return false; for (int i = 0; i < strategy.length; i++) { if (strategy[i] == ps) { return true; } } return false; } /** * 是否加载対多关联 * * @return 否加载対多关联 */ public boolean isLoadVsMany() { return loadVsMany; } /** * 设置是否加载对多关联 * * @param loadVsMany 是否加载对多关联 */ public void setLoadVsMany(boolean loadVsMany) { this.loadVsMany = loadVsMany; } /** * 是否加载対一关联 * * @return 是否加载対一关联 */ public boolean isLoadVsOne() { return loadVsOne; } /** * 设置是否加载対一关联 * @param loadVsOne 是否加载対一级联 */ public void setLoadVsOne(boolean loadVsOne) { this.loadVsOne = loadVsOne; } /** * 询问是否为数据库实体。 * * @return 是否为数据库实体。 */ public boolean isQueryableEntity() { return meta != null; } /** * 询问是否为动态对象实体 * * @return 是否为动态对象实体 */ public boolean isVarObject() { if (resultClazz == VarObject.class || resultClazz==PojoWrapper.class) { Assert.notNull(meta); return true; } return false; } /** * 设置返回结果的类型 * * @param clz 查询要返回的结果类型 */ public void setResultType(Class<?> clz) { if (clz == null) return; this.resultClazz = clz; if (IQueryableEntity.class.isAssignableFrom(clz)) { meta = MetaHolder.getMeta(resultClazz.asSubclass(IQueryableEntity.class)); } else { meta = null; } } /** * 设置返回结果的类型 * * @param meta 询要返回的结果类型 */ public void setResultType(ITableMetadata meta) { if (meta == null) return; this.resultClazz = meta.getContainerType(); this.meta = meta; } /** * 将结果的返回类型设置为Object数组,同时指定数组的最大长度 * @param size */ public void setResultTypeAsObjectArray(int size){ this.resultClazz=Object[].class; addMapperProperties(String.valueOf(size-1)); } }