Package org.nutz.dao.impl.entity

Source Code of org.nutz.dao.impl.entity.AnnotationEntityMaker

package org.nutz.dao.impl.entity;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.sql.DataSource;

import org.nutz.dao.DB;
import org.nutz.dao.entity.Entity;
import org.nutz.dao.entity.EntityField;
import org.nutz.dao.entity.EntityMaker;
import org.nutz.dao.entity.MappingField;
import org.nutz.dao.entity.annotation.Column;
import org.nutz.dao.entity.annotation.EL;
import org.nutz.dao.entity.annotation.Id;
import org.nutz.dao.entity.annotation.Index;
import org.nutz.dao.entity.annotation.Many;
import org.nutz.dao.entity.annotation.ManyMany;
import org.nutz.dao.entity.annotation.Name;
import org.nutz.dao.entity.annotation.One;
import org.nutz.dao.entity.annotation.PK;
import org.nutz.dao.entity.annotation.SQL;
import org.nutz.dao.entity.annotation.Table;
import org.nutz.dao.entity.annotation.TableIndexes;
import org.nutz.dao.entity.annotation.TableMeta;
import org.nutz.dao.entity.annotation.View;
import org.nutz.dao.impl.EntityHolder;
import org.nutz.dao.impl.entity.field.ManyLinkField;
import org.nutz.dao.impl.entity.field.ManyManyLinkField;
import org.nutz.dao.impl.entity.field.NutMappingField;
import org.nutz.dao.impl.entity.field.OneLinkField;
import org.nutz.dao.impl.entity.info.LinkInfo;
import org.nutz.dao.impl.entity.info.MappingInfo;
import org.nutz.dao.impl.entity.info.TableInfo;
import org.nutz.dao.impl.entity.info._Infos;
import org.nutz.dao.impl.entity.macro.ElFieldMacro;
import org.nutz.dao.impl.entity.macro.SqlFieldMacro;
import org.nutz.dao.jdbc.JdbcExpert;
import org.nutz.dao.jdbc.Jdbcs;
import org.nutz.dao.sql.Pojo;
import org.nutz.lang.Lang;
import org.nutz.lang.Mirror;
import org.nutz.lang.Strings;
import org.nutz.lang.segment.CharSegment;
import org.nutz.log.Log;
import org.nutz.log.Logs;

/**
* 根据一个 Class 对象生成 Entity 的实例
*
* @author zozoh(zozohtnt@gmail.com)
*/
public class AnnotationEntityMaker implements EntityMaker {

  private static final Log log = Logs.get();

  private DataSource datasource;

  private JdbcExpert expert;

  private EntityHolder holder;

  public AnnotationEntityMaker(DataSource datasource, JdbcExpert expert, EntityHolder holder) {
    this.datasource = datasource;
    this.expert = expert;
    this.holder = holder;
  }

  public <T> Entity<T> make(Class<T> type) {
    NutEntity<T> en = new NutEntity<T>(type);

    TableInfo ti = _createTableInfo(type);

    /*
     * 获取实体的扩展描述
     */
    // 全局
    if (null != expert.getConf()) {
      for (String key : expert.getConf().keySet())
        en.getMetas().put(key, expert.getConf().get(key));
    }
    // 当前表
    if (null != ti.annMeta) {
      Map<String, Object> map = Lang.map(ti.annMeta.value());
      for (Entry<String, Object> entry : map.entrySet()) {
        en.getMetas().put(entry.getKey(), entry.getValue().toString());
      }
    }

    /*
     * 获得表名以及视图名称
     */
    String tableName = null == ti.annTable  ? Strings.lowerWord(type.getSimpleName(), '_')
                        : ti.annTable.value();

    String viewName = null == ti.annView ? tableName : ti.annView.value();

    en.setTableName(tableName);
    en.setViewName(viewName);

    /*
     * 获取所有的数据库字段
     */
    // 字段里面是不是有声明过 '@Column'
    boolean shouldUseColumn = false;
    for (Field field : en.getMirror().getFields()) {
      if (null != field.getAnnotation(Column.class)) {
        shouldUseColumn = true;
        break;
      }
    }

    /*
     * 循环获取实体字段
     */
    List<MappingInfo> infos = new ArrayList<MappingInfo>();
    List<LinkInfo> ones = new ArrayList<LinkInfo>();
    List<LinkInfo> manys = new ArrayList<LinkInfo>();
    List<LinkInfo> manymanys = new ArrayList<LinkInfo>();

    // 循环所有的字段,查找有没有数据库映射字段
    for (Field field : en.getMirror().getFields()) {
      // '@One'
      if (null != field.getAnnotation(One.class)) {
        ones.add(_Infos.createLinkInfo(field));
      }
      // '@Many'
      else if (null != field.getAnnotation(Many.class)) {
        manys.add(_Infos.createLinkInfo(field));
      }
      // '@ManyMany'
      else if (null != field.getAnnotation(ManyMany.class)) {
        manymanys.add(_Infos.createLinkInfo(field));
      }
      // 应该忽略
      else if (shouldUseColumn
            && (null == field.getAnnotation(Column.class)
              && null == field.getAnnotation(Id.class) && null == field.getAnnotation(Name.class))) {
        continue;
      }
      // '@Column'
      else {
        infos.add(_Infos.createMappingInfo(ti.annPK, field));
      }

    }
    // 循环所有方法,查找有没有虚拟数据库映射字段
    for (Method method : en.getType().getMethods()) {
      // '@One'
      if (null != method.getAnnotation(One.class)) {
        ones.add(_Infos.createLinkInfo(method));
      }
      // '@Many'
      else if (null != method.getAnnotation(Many.class)) {
        manys.add(_Infos.createLinkInfo(method));
      }
      // '@ManyMany'
      else if (null != method.getAnnotation(ManyMany.class)) {
        manymanys.add(_Infos.createLinkInfo(method));
      }
      // 应该忽略
      else if (null == method.getAnnotation(Column.class)
            && null == method.getAnnotation(Id.class)
            && null == method.getAnnotation(Name.class)) {
        continue;
      }
      // '@Column'
      else {
        infos.add(_Infos.createMapingInfo(ti.annPK, method));
      }
    }

    /*
     * 解析所有映射字段
     */
    for (MappingInfo info : infos) {
      NutMappingField ef = new NutMappingField(en);
      _evalMappingField(ef, info);
      en.addMappingField(ef);
    }
    holder.set(en); // 保存一下,这样别的实体映射到这里时会用的到
    /*
     * 解析所有关联字段
     */
    // 一对一 '@One'
    for (LinkInfo li : ones) {
      en.addLinkField(new OneLinkField(en, holder, li));
    }
    // 一对多 '@Many'
    for (LinkInfo li : manys) {
      en.addLinkField(new ManyLinkField(en, holder, li));
    }
    // 多对多 '@ManyMany'
    for (LinkInfo li : manymanys) {
      en.addLinkField(new ManyManyLinkField(en, holder, li));
    }
    // 检查复合主键
    en.checkCompositeFields(null == ti.annPK ? null : ti.annPK.value());

    /*
     * 交付给 expert 来检查一下数据库一致性
     */
    if (null != datasource && null != expert) {
      _checkupEntityFieldsWithDatabase(en);
    }

    /*
     * 检查字段宏
     */
    _evalFieldMacro(en, infos);

    /*
     * 解析实体索引
     */
    if (null != ti.annIndexes)
      _evalEntityIndexes(en, ti.annIndexes);

    // 搞定收工,哦耶 ^_^
    return en;
  }

  /**
   * 向父类递归查找实体的配置
   *
   * @param type
   *            实体类型
   * @return 实体表描述
   */
  private TableInfo _createTableInfo(Class<?> type) {
    TableInfo info = new TableInfo();
    Mirror<?> mirror = Mirror.me(type);
    info.annTable = mirror.getAnnotation(Table.class);
    info.annView = mirror.getAnnotation(View.class);
    info.annMeta = mirror.getAnnotation(TableMeta.class);
    info.annPK = mirror.getAnnotation(PK.class);
    info.annIndexes = mirror.getAnnotation(TableIndexes.class);
    return info;
  }

  /**
   * 根据 '@Next' 和 '@Prev' 的信息,生成一个 FieldMacroInfo 对象
   *
   * @param els
   *            表达式
   * @param sqls
   *            SQL
   * @return 一个字段宏信息的列表
   */
  private List<FieldMacroInfo> _annToFieldMacroInfo(EL[] els, SQL[] sqls) {
    List<FieldMacroInfo> mis = new LinkedList<FieldMacroInfo>();
    if (els.length > 0) { // els 没有机会为 null 的
      for (EL el : els)
        mis.add(new FieldMacroInfo(el));
    }
    if (sqls.length > 0) { // @SQL 没有 @EL 优先级高
      for (SQL sql : sqls)
        mis.add(new FieldMacroInfo(sql));
    }
    return mis;
  }

  /**
   * @param ef
   * @param info
   */
  private void _evalMappingField(NutMappingField ef, MappingInfo info) {
    // 字段的 Java 名称
    ef.setName(info.name);
    ef.setType(info.fieldType);

    // 字段的数据库名
    if (null == info.annColumn || Strings.isBlank(info.annColumn.value()))
      ef.setColumnName(info.name);
    else
      ef.setColumnName(info.annColumn.value());

    // Id 字段
    if (null != info.annId) {
      ef.setAsId();
      if (info.annId.auto())
        ef.setAsAutoIncreasement();
    }

    // Name 字段
    if (null != info.annName) {
      ef.setAsName();
      ef.setCasesensitive(info.annName.casesensitive());
    }

    // 检查 @Id 和 @Name 的冲突
    if (ef.isId() && ef.isName())
      throw Lang.makeThrow"Field '%s'(%s) can not be @Id and @Name at same time!",
                  ef.getName(),
                  ef.getEntity().getType().getName());

    // 检查 PK
    if (null != info.annPK) {
      // 用 @PK 的方式声明的主键
      if (info.annPK.value().length == 1) {
        if (Lang.contains(info.annPK.value(), info.name)) {
          if (ef.getTypeMirror().isIntLike())
            ef.setAsId();
          else
            ef.setAsName();
        }
      }
      // 看看是不是复合主键
      else if (Lang.contains(info.annPK.value(), info.name))
        ef.setAsCompositePk();
    }

    // 默认值
    if (null != info.annDefault)
      ef.setDefaultValue(new CharSegment(info.annDefault.value()));

    // 只读
    if (null != info.annReadonly)
      ef.setAsReadonly();

    // 字段更多定义
    if (null != info.annDefine) {
      // 类型
      ef.setColumnType(info.annDefine.type());
      // 宽度
      ef.setWidth(info.annDefine.width());
      // 精度
      ef.setPrecision(info.annDefine.precision());
      // 无符号
      if (info.annDefine.unsigned())
        ef.setAsUnsigned();
      // 非空约束
      if (info.annDefine.notNull())
        ef.setAsNotNull();
      // 自增,如果 @Id(auto=false),则忽略
      if (info.annDefine.auto() && !ef.isId())
        ef.setAsAutoIncreasement();
    }
    // 猜测字段类型
    else {
      Jdbcs.guessEntityFieldColumnType(ef);
    }

    // 字段值的适配器
    ef.setAdaptor(expert.getAdaptor(ef));

    // 输入输出
    ef.setInjecting(info.injecting);
    ef.setEjecting(info.ejecting);

  }

  private void _evalFieldMacro(Entity<?> en, List<MappingInfo> infos) {
    for (MappingInfo info : infos) {
      // '@Prev' : 预设值
      if (null != info.annPrev) {
        en.addBeforeInsertMacro(__macro(en.getField(info.name),
                        _annToFieldMacroInfoinfo.annPrev.els(),
                                    info.annPrev.value())));
      }

      // '@Next' : 后续获取
      if (null != info.annNext
        && en.addAfterInsertMacro(__macroen.getField(info.name),
                          _annToFieldMacroInfoinfo.annNext.els(),
                                      info.annNext.value())))) {
        continue;
      }
      // '@Id' : 的自动后续获取
      else if (null != info.annId && info.annId.auto()) {
        MappingField idField = en.getField(info.name);
        String autoSql = "SELECT MAX($field) AS $field FROM $view";
        Pojo autoInfo = new SqlFieldMacro(idField, autoSql);
        autoInfo.setEntity(en);
        en.addAfterInsertMacro(autoInfo);
      }
    }
  }

  private Pojo __macro(MappingField ef, List<FieldMacroInfo> infoList) {
    FieldMacroInfo theInfo = null;
    // 根据当前数据库,找到合适的宏
    for (FieldMacroInfo info : infoList) {
      if (DB.OTHER == info.getDb()) {
        theInfo = info;
      } else if (info.getDb().name().equalsIgnoreCase(expert.getDatabaseType())) {
        theInfo = info;
        break;
      }
    }
    // 如果找到,增加
    if (null != theInfo) {
      if (theInfo.isEl())
        return new ElFieldMacro(ef, theInfo.getValue());
      else
        return new SqlFieldMacro(ef, theInfo.getValue());
    }
    return null;
  }

  private void _evalEntityIndexes(NutEntity<?> en, TableIndexes indexes) {
    for (Index idx : indexes.value()) {
      NutEntityIndex index = new NutEntityIndex();
      index.setUnique(idx.unique());
      index.setName(idx.name());
      for (String indexName : idx.fields()) {
        EntityField ef = en.getField(indexName);
        if (null == ef) {
          throw Lang.makeThrow"Fail to find field '%s' in '%s' by @Index(%s:%s)",
                      indexName,
                      en.getType().getName(),
                      index.getName(),
                      Lang.concat(idx.fields()));
        }
        index.addField(ef);
      }
      en.addIndex(index);
    }
  }

  private void _checkupEntityFieldsWithDatabase(NutEntity<?> en) {
    Connection conn = null;
    try {
      conn = datasource.getConnection();
      expert.setupEntityField(conn, en);
    }
    catch (Exception e) {
      if (log.isDebugEnabled())
        log.debugf"Fail to setup '%s'(%s) by DB, because: (%s)'%s'",
              en.getType().getName(),
              en.getTableName(),
              e.getClass().getName(),
              e.getMessage());
    }
    finally {
      if (null != conn) {
        try {
          conn.close();
        }
        catch (SQLException e) {
          if (log.isWarnEnabled())
            log.warn("Fail to close connection!", e);
        }
      }
    }
  }

}
TOP

Related Classes of org.nutz.dao.impl.entity.AnnotationEntityMaker

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.