/**
  * 一対多の関連を処理します。
  *
  * @param propertyMeta プロパティメタデータ
  * @param field フィールド
  * @param entityMeta エンティティメタデータ
  * @param oneToMany 一対多関連
  */
 protected void doOneToMany(
     PropertyMeta propertyMeta, Field field, EntityMeta entityMeta, OneToMany oneToMany) {
   propertyMeta.setRelationshipType(RelationshipType.ONE_TO_MANY);
   if (!List.class.isAssignableFrom(field.getType())) {
     throw new OneToManyNotListRuntimeException(entityMeta.getName(), propertyMeta.getName());
   }
   Class<?> relationshipClass = ReflectionUtil.getElementTypeOfList(field.getGenericType());
   if (relationshipClass == null) {
     throw new OneToManyNotGenericsRuntimeException(entityMeta.getName(), propertyMeta.getName());
   }
   if (relationshipClass.getAnnotation(Entity.class) == null) {
     throw new RelationshipNotEntityRuntimeException(
         entityMeta.getName(), propertyMeta.getName(), relationshipClass);
   }
   propertyMeta.setRelationshipClass(relationshipClass);
   String mappedBy = oneToMany.mappedBy();
   if (!StringUtil.isEmpty(mappedBy)) {
     if (propertyMeta.getJoinColumnMetaList().size() > 0) {
       throw new BothMappedByAndJoinColumnRuntimeException(
           entityMeta.getName(), propertyMeta.getName());
     }
     propertyMeta.setMappedBy(mappedBy);
   } else {
     throw new MappedByMandatoryRuntimeException(entityMeta.getName(), propertyMeta.getName());
   }
 }
 /**
  * 識別子メタデータを処理します。
  *
  * @param propertyMeta プロパティメタデータ
  * @param field フィールド
  * @param entityMeta エンティティメタデータ
  */
 protected void doId(PropertyMeta propertyMeta, Field field, EntityMeta entityMeta) {
   propertyMeta.setId(field.getAnnotation(Id.class) != null);
   GeneratedValue generatedValue = field.getAnnotation(GeneratedValue.class);
   if (generatedValue == null) {
     return;
   }
   GenerationType generationType = generatedValue.strategy();
   propertyMeta.setGenerationType(generationType);
   switch (generationType) {
     case AUTO:
       doIdentityIdGenerator(propertyMeta, entityMeta);
       doSequenceIdGenerator(propertyMeta, generatedValue, entityMeta);
       doTableIdGenerator(propertyMeta, generatedValue, entityMeta);
       break;
     case IDENTITY:
       doIdentityIdGenerator(propertyMeta, entityMeta);
       break;
     case SEQUENCE:
       if (!doSequenceIdGenerator(propertyMeta, generatedValue, entityMeta)) {
         throw new IdGeneratorNotFoundRuntimeException(
             entityMeta.getName(), propertyMeta.getName(), generatedValue.generator());
       }
       break;
     case TABLE:
       if (!doTableIdGenerator(propertyMeta, generatedValue, entityMeta)) {
         throw new IdGeneratorNotFoundRuntimeException(
             entityMeta.getName(), propertyMeta.getName(), generatedValue.generator());
       }
       break;
   }
 }
 /**
  * テーブルを処理します。
  *
  * @param entityMeta エンティティメタデータ
  * @param propertyMeta プロパティメタデータ
  * @param foreignKeyDesc 外部キー記述
  */
 protected void doTable(
     EntityMeta entityMeta, PropertyMeta propertyMeta, ForeignKeyDesc foreignKeyDesc) {
   EntityMeta inverseEntityMeta =
       entityMetaFactory.getEntityMeta(propertyMeta.getRelationshipClass());
   TableMeta tableMeta = inverseEntityMeta.getTableMeta();
   foreignKeyDesc.setReferencedCatalogName(tableMeta.getCatalog());
   foreignKeyDesc.setReferencedSchemaName(tableMeta.getSchema());
   foreignKeyDesc.setReferencedTableName(tableMeta.getName());
   foreignKeyDesc.setReferencedFullTableName(tableMeta.getFullName());
 }
 /**
  * 外部キー記述を処理します。
  *
  * @param entityMeta エンティティメタデータ
  * @param tableDesc テーブル記述
  * @param table テーブル
  */
 protected void doForeignKeyDesc(EntityMeta entityMeta, TableDesc tableDesc, Table table) {
   for (int i = 0; i < entityMeta.getPropertyMetaSize(); i++) {
     PropertyMeta propertyMeta = entityMeta.getPropertyMeta(i);
     ForeignKeyDesc foreignKeyDesc =
         foreignKeyDescFactory.getForeignKeyDesc(entityMeta, propertyMeta);
     if (foreignKeyDesc != null) {
       tableDesc.addForeignKeyDesc(foreignKeyDesc);
     }
   }
 }
 /**
  * カラム記述を処理します。
  *
  * @param entityMeta エンティティメタデータ
  * @param tableDesc テーブル記述
  * @param table テーブル
  */
 protected void doColumnDesc(EntityMeta entityMeta, final TableDesc tableDesc, Table table) {
   List<ColumnDescRef> columnDescRefList = new ArrayList<ColumnDescRef>();
   for (int i = 0; i < entityMeta.getColumnPropertyMetaSize(); i++) {
     PropertyMeta propertyMeta = entityMeta.getColumnPropertyMeta(i);
     ColumnDesc columnDesc = columnDescFactory.getColumnDesc(entityMeta, propertyMeta);
     if (columnDesc != null) {
       columnDescRefList.add(new ColumnDescRef(i, columnDesc));
     }
   }
   Collections.sort(columnDescRefList, createColumnDescRefComparator(tableDesc));
   for (ColumnDescRef columnDescRef : columnDescRefList) {
     tableDesc.addColumnDesc(columnDescRef.columnDesc);
   }
 }
  /**
   * 識別子生成用のテーブル記述を処理します。
   *
   * @param entityMeta エンティティメタデータ
   * @param tableDesc テーブル記述
   * @param table テーブル
   */
  protected void doIdTableDesc(EntityMeta entityMeta, TableDesc tableDesc, Table table) {
    for (PropertyMeta propertyMeta : entityMeta.getIdPropertyMetaList()) {
      TableDesc idTableDesc = idTableDescFactory.getTableDesc(entityMeta, propertyMeta);
      if (idTableDesc == null) {
        continue;
      }
      tableDesc.addIdTableDesc(idTableDesc);

      String fullName = idTableDesc.getFullName().toLowerCase();
      TableDesc cache = tableDescMap.get(fullName);
      if (cache == null) {
        tableDescMap.put(fullName, idTableDesc);
      } else {
        cache.setCatalogName(idTableDesc.getCatalogName());
        cache.setSchemaName(idTableDesc.getSchemaName());
        cache.setName(idTableDesc.getName());
        cache.setPrimaryKeyDesc(idTableDesc.getPrimaryKeyDesc());
        for (ColumnDesc columnDesc : idTableDesc.getColumnDescList()) {
          cache.addColumnDesc(columnDesc);
        }
        for (UniqueKeyDesc uniqueKeyDesc : idTableDesc.getUniqueKeyDescList()) {
          cache.addUniqueKeyDesc(uniqueKeyDesc);
        }
      }
    }
  }
 /**
  * 名前を処理します。
  *
  * @param entityMeta エンティティメタデータ
  * @param tableDesc テーブル記述
  * @param table テーブル
  */
 protected void doName(EntityMeta entityMeta, TableDesc tableDesc, Table table) {
   TableMeta tableMeta = entityMeta.getTableMeta();
   tableDesc.setCatalogName(tableMeta.getCatalog());
   tableDesc.setSchemaName(tableMeta.getSchema());
   tableDesc.setName(tableMeta.getName());
   tableDesc.setCanonicalName(buildCanonicalName(tableMeta));
 }
 /**
  * シーケンスの名前を返します。
  *
  * @param entityMeta エンティティメタデータ
  * @param propertyMeta プロパティメタデータ
  * @param sequenceGenerator シーケンスジェネレータ
  * @return シーケンスの名前
  */
 protected String getSequenceName(
     EntityMeta entityMeta, PropertyMeta propertyMeta, SequenceGenerator sequenceGenerator) {
   String sequenceName = sequenceGenerator.sequenceName();
   if (!StringUtil.isEmpty(sequenceName)) {
     return sequenceName;
   }
   return entityMeta.getTableMeta().getName() + "_" + propertyMeta.getColumnMeta().getName();
 }
 /**
  * シーケンス記述を処理します。
  *
  * @param entityMeta エンティティメタデータ
  * @param tableDesc テーブル記述
  * @param table テーブル
  */
 protected void doSequenceDesc(EntityMeta entityMeta, TableDesc tableDesc, Table table) {
   for (PropertyMeta propertyMeta : entityMeta.getIdPropertyMetaList()) {
     SequenceDesc sequenceDesc = sequenceDescFactory.getSequenceDesc(entityMeta, propertyMeta);
     if (sequenceDesc != null) {
       tableDesc.addSequenceDesc(sequenceDesc);
     }
   }
 }
 /**
  * 一対一の関連を処理します。
  *
  * @param propertyMeta プロパティメタデータ
  * @param field フィールド
  * @param entityMeta エンティティメタデータ
  * @param oneToOne 一対一関連
  */
 protected void doOneToOne(
     PropertyMeta propertyMeta, Field field, EntityMeta entityMeta, OneToOne oneToOne) {
   propertyMeta.setRelationshipType(RelationshipType.ONE_TO_ONE);
   Class<?> relationshipClass = field.getType();
   if (relationshipClass.getAnnotation(Entity.class) == null) {
     throw new RelationshipNotEntityRuntimeException(
         entityMeta.getName(), propertyMeta.getName(), relationshipClass);
   }
   propertyMeta.setRelationshipClass(relationshipClass);
   String mappedBy = oneToOne.mappedBy();
   if (!StringUtil.isEmpty(mappedBy)) {
     if (propertyMeta.getJoinColumnMetaList().size() > 0) {
       throw new BothMappedByAndJoinColumnRuntimeException(
           entityMeta.getName(), propertyMeta.getName());
     }
     propertyMeta.setMappedBy(mappedBy);
   }
 }
  /**
   * 名前を処理します。
   *
   * @param entityMeta エンティティメタデータ
   * @param tableDesc テーブル記述
   * @param generator テーブルジェネレータ
   */
  protected void doName(EntityMeta entityMeta, TableDesc tableDesc, TableGenerator generator) {
    String catalog = generator.catalog();
    if (StringUtil.isEmpty(catalog)) {
      catalog = entityMeta.getTableMeta().getCatalog();
    }
    String schema = generator.schema();
    if (StringUtil.isEmpty(schema)) {
      schema = entityMeta.getTableMeta().getSchema();
    }
    String name = generator.table();
    if (StringUtil.isEmpty(name)) {
      name = TableIdGenerator.DEFAULT_TABLE;
    }

    tableDesc.setCatalogName(catalog);
    tableDesc.setSchemaName(schema);
    tableDesc.setName(name);
    tableDesc.setCanonicalName(buildCanonicalName(catalog, schema, name));
  }
 public TableDesc getTableDesc(EntityMeta entityMeta) {
   String fullName = entityMeta.getTableMeta().getFullName().toLowerCase();
   TableDesc tableDesc = tableDescMap.get(fullName);
   if (tableDesc != null) {
     return tableDesc;
   }
   tableDesc = createTableDesc(entityMeta);
   tableDescMap.put(fullName, tableDesc);
   return tableDesc;
 }
 /**
  * フェッチタイプを処理します。
  *
  * @param propertyMeta プロパティメタデータ
  * @param field フィールド
  * @param entityMeta エンティティメタデータ
  */
 protected void doFetchType(
     final PropertyMeta propertyMeta, final Field field, final EntityMeta entityMeta) {
   final Basic basic = field.getAnnotation(Basic.class);
   if (basic == null) {
     propertyMeta.setFetchType(FetchType.EAGER);
     return;
   }
   if (propertyMeta.isId() && basic.fetch() == FetchType.LAZY) {
     throw new LazyFetchSpecifiedRuntimeException(entityMeta.getName(), propertyMeta.getName());
   }
   propertyMeta.setFetchType(basic.fetch());
 }
 /**
  * 時制の種別を処理します。
  *
  * @param propertyMeta プロパティメタデータ
  * @param field フィールド
  * @param entityMeta エンティティメタデータ
  */
 protected void doTemporal(PropertyMeta propertyMeta, Field field, EntityMeta entityMeta) {
   if (propertyMeta.getPropertyClass() != java.util.Date.class
       && propertyMeta.getPropertyClass() != Calendar.class) {
     return;
   }
   Temporal temporal = field.getAnnotation(Temporal.class);
   if (temporal == null) {
     throw new TemporalTypeNotSpecifiedRuntimeException(
         entityMeta.getName(), propertyMeta.getName());
   }
   propertyMeta.setTemporalType(temporal.value());
 }
 /**
  * 関連用のクラスを返します。
  *
  * @param propertyMeta プロパティメタデータ
  * @param field フィールド
  * @param entityMeta エンティティメタデータ
  * @return 関連用のクラス
  * @throws OneToManyNotGenericsRuntimeException 一対多の関連がジェネリクスのリストではない場合。
  */
 protected Class<?> getRelationshipClass(
     PropertyMeta propertyMeta, Field field, EntityMeta entityMeta)
     throws OneToManyNotGenericsRuntimeException {
   Class<?> clazz = field.getType();
   if (List.class.isAssignableFrom(clazz)) {
     clazz = ReflectionUtil.getElementTypeOfList(field.getGenericType());
     if (clazz == null) {
       throw new OneToManyNotGenericsRuntimeException(
           entityMeta.getName(), propertyMeta.getName());
     }
   }
   return clazz;
 }
 /**
  * 多対一の関連を処理します。
  *
  * @param propertyMeta プロパティメタデータ
  * @param field フィールド
  * @param entityMeta エンティティメタデータ
  * @param manyToOne 多対一関連
  */
 protected void doManyToOne(
     PropertyMeta propertyMeta,
     Field field,
     EntityMeta entityMeta,
     @SuppressWarnings("unused") ManyToOne manyToOne) {
   propertyMeta.setRelationshipType(RelationshipType.MANY_TO_ONE);
   Class<?> relationshipClass = field.getType();
   if (relationshipClass.getAnnotation(Entity.class) == null) {
     throw new RelationshipNotEntityRuntimeException(
         entityMeta.getName(), propertyMeta.getName(), relationshipClass);
   }
   propertyMeta.setRelationshipClass(relationshipClass);
 }
 /**
  * 関連を処理します。
  *
  * @param propertyMeta プロパティメタデータ
  * @param field フィールド
  * @param entityMeta エンティティメタデータ
  * @param annotation 関連のアノテーション
  */
 protected void doRelationship(
     PropertyMeta propertyMeta, Field field, EntityMeta entityMeta, Object annotation) {
   doJoinColumn(propertyMeta, field, entityMeta);
   if (OneToOne.class.isInstance(annotation)) {
     doOneToOne(propertyMeta, field, entityMeta, OneToOne.class.cast(annotation));
   } else if (OneToMany.class.isInstance(annotation)) {
     doOneToMany(propertyMeta, field, entityMeta, OneToMany.class.cast(annotation));
   } else if (ManyToOne.class.isInstance(annotation)) {
     doManyToOne(propertyMeta, field, entityMeta, ManyToOne.class.cast(annotation));
   } else {
     throw new UnsupportedRelationshipRuntimeException(
         entityMeta.getName(), propertyMeta.getName());
   }
 }
 /**
  * バージョンチェック用かどうかを処理します。
  *
  * @param propertyMeta プロパティメタデータ
  * @param field フィールド
  * @param entityMeta エンティティメタデータ
  */
 protected void doVersion(
     PropertyMeta propertyMeta, Field field, @SuppressWarnings("unused") EntityMeta entityMeta) {
   if (field.getAnnotation(Version.class) == null) {
     return;
   }
   Class<?> clazz = ClassUtil.getWrapperClassIfPrimitive(field.getType());
   if (clazz != Integer.class
       && clazz != Long.class
       && clazz != int.class
       && clazz != long.class) {
     throw new VersionPropertyNotNumberRuntimeException(
         entityMeta.getName(), propertyMeta.getName());
   }
   propertyMeta.setVersion(true);
 }
 /**
  * {@link GenerationType#TABLE}方式で識別子の値を自動生成するIDジェネレータを処理します。
  *
  * @param propertyMeta プロパティメタデータ
  * @param generatedValue 識別子に付けられた{@link GeneratedValue}アノテーション
  * @param entityMeta エンティティのメタデータ
  * @return {@link GenerationType#TABLE}方式で識別子の値を自動生成するIDジェネレータが存在した場合に <code>true</code>
  */
 protected boolean doTableIdGenerator(
     PropertyMeta propertyMeta, GeneratedValue generatedValue, EntityMeta entityMeta) {
   String name = generatedValue.generator();
   TableGenerator tableGenerator;
   if (StringUtil.isEmpty(name)) {
     tableGenerator = DEFAULT_TABLE_GENERATOR;
   } else {
     tableGenerator = propertyMeta.getField().getAnnotation(TableGenerator.class);
     if (tableGenerator == null || !name.equals(tableGenerator.name())) {
       tableGenerator = entityMeta.getEntityClass().getAnnotation(TableGenerator.class);
       if (tableGenerator == null || !name.equals(tableGenerator.name())) {
         return false;
       }
     }
   }
   propertyMeta.setTableIdGenerator(
       new TableIdGenerator(entityMeta, propertyMeta, tableGenerator));
   return true;
 }
 /**
  * {@link GenerationType#SEQUENCE}方式で識別子の値を自動生成するIDジェネレータを処理します。
  *
  * @param propertyMeta プロパティメタデータ
  * @param generatedValue 識別子に付けられた{@link GeneratedValue}アノテーション
  * @param entityMeta エンティティのメタデータ
  * @return {@link GenerationType#SEQUENCE}方式で識別子の値を自動生成するIDジェネレータが存在した場合に <code>true</code>
  */
 protected boolean doSequenceIdGenerator(
     PropertyMeta propertyMeta, GeneratedValue generatedValue, EntityMeta entityMeta) {
   String name = generatedValue.generator();
   SequenceGenerator sequenceGenerator;
   if (StringUtil.isEmpty(name)) {
     sequenceGenerator = DEFAULT_SEQUENCE_GENERATOR;
   } else {
     sequenceGenerator = propertyMeta.getField().getAnnotation(SequenceGenerator.class);
     if (sequenceGenerator == null || !name.equals(sequenceGenerator.name())) {
       sequenceGenerator = entityMeta.getEntityClass().getAnnotation(SequenceGenerator.class);
       if (sequenceGenerator == null || !name.equals(sequenceGenerator.name())) {
         return false;
       }
     }
   }
   propertyMeta.setSequenceIdGenerator(
       new SequenceIdGenerator(entityMeta, propertyMeta, sequenceGenerator));
   return true;
 }
 /**
  * テーブルジェネレータを返します。
  *
  * @param entityMeta エンティティメタデータ
  * @param propertyMeta プロパティメタデータ
  * @return テーブルジェネレータ
  */
 protected TableGenerator getTableGenerator(EntityMeta entityMeta, PropertyMeta propertyMeta) {
   Field field = propertyMeta.getField();
   GeneratedValue generatedValue = field.getAnnotation(GeneratedValue.class);
   if (generatedValue == null) {
     throw new IllegalStateException("@GeneratedValue not found.");
   }
   String name = generatedValue.generator();
   if (StringUtil.isEmpty(name)) {
     return AnnotationUtil.getDefaultTableGenerator();
   }
   TableGenerator tableGenerator = field.getAnnotation(TableGenerator.class);
   if (tableGenerator != null && name.equals(tableGenerator.name())) {
     return tableGenerator;
   }
   tableGenerator = entityMeta.getEntityClass().getAnnotation(TableGenerator.class);
   if (tableGenerator != null && name.equals(tableGenerator.name())) {
     return tableGenerator;
   }
   throw new IllegalStateException("@TableGenerator not found.");
 }
 public SequenceDesc getSequenceDesc(EntityMeta entityMeta, PropertyMeta propertyMeta) {
   GenerationType generationType = propertyMeta.getGenerationType();
   if (generationType == GenerationType.AUTO) {
     generationType = dialect.getDefaultGenerationType();
   }
   if (generationType == GenerationType.SEQUENCE) {
     if (!dialect.supportsSequence()) {
       throw new UnsupportedGenerationTypeRuntimeException(
           GenerationType.SEQUENCE, entityMeta.getName(), propertyMeta.getName());
     }
     SequenceGenerator generator = getSequenceGenerator(entityMeta, propertyMeta);
     SequenceDesc sequenceDesc = new SequenceDesc();
     String sequenceName = getSequenceName(entityMeta, propertyMeta, generator);
     sequenceDesc.setSequenceName(sequenceName);
     sequenceDesc.setInitialValue(generator.initialValue());
     sequenceDesc.setAllocationSize(generator.allocationSize());
     sequenceDesc.setDataType(getDataType(propertyMeta));
     return sequenceDesc;
   }
   return null;
 }
 /**
  * JoinColumnを処理します。
  *
  * @param propertyMeta プロパティメタデータ
  * @param field フィールド
  * @param entityMeta エンティティメタデータ
  */
 protected void doJoinColumn(PropertyMeta propertyMeta, Field field, EntityMeta entityMeta) {
   JoinColumn joinColumn = field.getAnnotation(JoinColumn.class);
   if (joinColumn != null) {
     JoinColumnMeta meta =
         new JoinColumnMeta(joinColumn.name(), joinColumn.referencedColumnName());
     propertyMeta.addJoinColumnMeta(meta);
   } else {
     JoinColumns joinColumns = field.getAnnotation(JoinColumns.class);
     if (joinColumns != null) {
       JoinColumn[] array = joinColumns.value();
       for (int i = 0; i < array.length; i++) {
         JoinColumn jc = array[i];
         JoinColumnMeta meta = new JoinColumnMeta(jc.name(), jc.referencedColumnName());
         if (i > 0 && (meta.getName() == null || meta.getReferencedColumnName() == null)) {
           throw new JoinColumnNameAndReferencedColumnNameMandatoryRuntimeException(
               entityMeta.getName(), propertyMeta.getName(), i + 1);
         }
         propertyMeta.addJoinColumnMeta(meta);
       }
     }
   }
 }
 /**
  * テーブルを取得します。
  *
  * @param entityMeta エンティティメタデータ
  * @return テーブル
  */
 protected Table getTable(EntityMeta entityMeta) {
   Class<?> clazz = entityMeta.getEntityClass();
   Table table = clazz.getAnnotation(Table.class);
   return table != null ? table : AnnotationUtil.getDefaultTable();
 }
  /**
   * {@link ValueType}を処理します。
   *
   * @param propertyMeta プロパティメタデータ
   * @param entityMeta エンティティメタデータ
   */
  @SuppressWarnings("unchecked")
  protected void doValueType(final PropertyMeta propertyMeta, final EntityMeta entityMeta) {
    final Class<?> propertyClass = propertyMeta.getPropertyClass();
    final ValueType valueType = valueTypes.get(propertyClass);
    if (valueType != null) {
      propertyMeta.setValueType(valueType);
      return;
    }

    if (propertyClass == String.class) {
      if (propertyMeta.isLob()) {
        propertyMeta.setValueType(ValueTypes.CLOB);
      } else {
        propertyMeta.setValueType(ValueTypes.STRING);
      }
      return;
    }

    if (propertyClass == byte[].class) {
      if (propertyMeta.isLob()) {
        propertyMeta.setValueType(ValueTypes.BLOB);
      } else {
        propertyMeta.setValueType(ValueTypes.BYTE_ARRAY);
      }
      return;
    }

    if (propertyClass == Date.class) {
      switch (propertyMeta.getTemporalType()) {
        case DATE:
          propertyMeta.setValueType(ValueTypes.DATE_SQLDATE);
          return;
        case TIME:
          propertyMeta.setValueType(ValueTypes.DATE_TIME);
          return;
        case TIMESTAMP:
          propertyMeta.setValueType(ValueTypes.DATE_TIMESTAMP);
          return;
      }
    }

    if (propertyClass == Calendar.class) {
      switch (propertyMeta.getTemporalType()) {
        case DATE:
          propertyMeta.setValueType(ValueTypes.CALENDAR_SQLDATE);
          return;
        case TIME:
          propertyMeta.setValueType(ValueTypes.CALENDAR_TIME);
          return;
        case TIMESTAMP:
          propertyMeta.setValueType(ValueTypes.CALENDAR_TIMESTAMP);
          return;
      }
    }

    if (propertyClass.isEnum()) {
      if (propertyMeta.getEnumType() == null) {
        propertyMeta.setValueType(ValueTypes.getValueType(propertyClass));
        return;
      }
      switch (propertyMeta.getEnumType()) {
        case ORDINAL:
          propertyMeta.setValueType(ValueTypes.getEnumOrdinalValueType(propertyClass));
          return;
        case STRING:
          propertyMeta.setValueType(ValueTypes.getEnumStringValueType(propertyClass));
          return;
      }
    }

    final ValueType userDefinedValueType = ValueTypes.createUserDefineValueType(propertyClass);
    if (userDefinedValueType != null) {
      propertyMeta.setValueType(userDefinedValueType);
      return;
    }

    if (Serializable.class.isAssignableFrom(propertyClass)) {
      if (propertyMeta.isLob()) {
        propertyMeta.setValueType(ValueTypes.SERIALIZABLE_BLOB);
      } else {
        propertyMeta.setValueType(ValueTypes.SERIALIZABLE_BYTE_ARRAY);
      }
      return;
    }

    throw new UnsupportedPropertyTypeRuntimeException(
        entityMeta.getName(), propertyMeta.getName(), propertyMeta.getPropertyClass());
  }