/*
* Copyright 2004-2015 the Seasar Foundation and the Others.
*
* 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 org.seasar.extension.jdbc.meta;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import javax.persistence.Basic;
import javax.persistence.Entity;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinColumns;
import javax.persistence.Lob;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.TableGenerator;
import javax.persistence.Temporal;
import javax.persistence.Transient;
import javax.persistence.Version;
import org.seasar.extension.jdbc.ColumnMetaFactory;
import org.seasar.extension.jdbc.EntityMeta;
import org.seasar.extension.jdbc.JoinColumnMeta;
import org.seasar.extension.jdbc.PropertyMeta;
import org.seasar.extension.jdbc.PropertyMetaFactory;
import org.seasar.extension.jdbc.RelationshipType;
import org.seasar.extension.jdbc.ValueType;
import org.seasar.extension.jdbc.exception.BothMappedByAndJoinColumnRuntimeException;
import org.seasar.extension.jdbc.exception.IdGeneratorNotFoundRuntimeException;
import org.seasar.extension.jdbc.exception.JoinColumnNameAndReferencedColumnNameMandatoryRuntimeException;
import org.seasar.extension.jdbc.exception.LazyFetchSpecifiedRuntimeException;
import org.seasar.extension.jdbc.exception.MappedByMandatoryRuntimeException;
import org.seasar.extension.jdbc.exception.OneToManyNotGenericsRuntimeException;
import org.seasar.extension.jdbc.exception.OneToManyNotListRuntimeException;
import org.seasar.extension.jdbc.exception.RelationshipNotEntityRuntimeException;
import org.seasar.extension.jdbc.exception.TemporalTypeNotSpecifiedRuntimeException;
import org.seasar.extension.jdbc.exception.UnsupportedPropertyTypeRuntimeException;
import org.seasar.extension.jdbc.exception.UnsupportedRelationshipRuntimeException;
import org.seasar.extension.jdbc.exception.VersionPropertyNotNumberRuntimeException;
import org.seasar.extension.jdbc.id.IdentityIdGenerator;
import org.seasar.extension.jdbc.id.SequenceIdGenerator;
import org.seasar.extension.jdbc.id.TableIdGenerator;
import org.seasar.extension.jdbc.types.ValueTypes;
import org.seasar.framework.container.annotation.tiger.Binding;
import org.seasar.framework.container.annotation.tiger.BindingType;
import org.seasar.framework.convention.PersistenceConvention;
import org.seasar.framework.util.ClassUtil;
import org.seasar.framework.util.ModifierUtil;
import org.seasar.framework.util.StringUtil;
import org.seasar.framework.util.tiger.CollectionsUtil;
import org.seasar.framework.util.tiger.ReflectionUtil;
/**
* {@link PropertyMetaFactory}の実装クラスです。
*
* @author higa
*
*/
@SequenceGenerator(name = "default")
@TableGenerator(name = "default")
public class PropertyMetaFactoryImpl implements PropertyMetaFactory {
/**
* デフォルトの{@link SequenceGenerator}です。
*/
protected static final SequenceGenerator DEFAULT_SEQUENCE_GENERATOR = PropertyMetaFactoryImpl.class
.getAnnotation(SequenceGenerator.class);
/**
* デフォルトの{@link TableGenerator}です。
*/
protected static final TableGenerator DEFAULT_TABLE_GENERATOR = PropertyMetaFactoryImpl.class
.getAnnotation(TableGenerator.class);
/**
* フィールドの型に対応する値タイプのマップです。
*/
protected static final Map<Class<?>, ValueType> valueTypes = CollectionsUtil
.newHashMap();
static {
valueTypes.put(boolean.class, ValueTypes.BOOLEAN);
valueTypes.put(Boolean.class, ValueTypes.BOOLEAN);
valueTypes.put(char.class, ValueTypes.CHARACTER);
valueTypes.put(Character.class, ValueTypes.CHARACTER);
valueTypes.put(byte.class, ValueTypes.BYTE);
valueTypes.put(Byte.class, ValueTypes.BYTE);
valueTypes.put(short.class, ValueTypes.SHORT);
valueTypes.put(Short.class, ValueTypes.SHORT);
valueTypes.put(int.class, ValueTypes.INTEGER);
valueTypes.put(Integer.class, ValueTypes.INTEGER);
valueTypes.put(long.class, ValueTypes.LONG);
valueTypes.put(Long.class, ValueTypes.LONG);
valueTypes.put(float.class, ValueTypes.FLOAT);
valueTypes.put(Float.class, ValueTypes.FLOAT);
valueTypes.put(double.class, ValueTypes.DOUBLE);
valueTypes.put(Double.class, ValueTypes.DOUBLE);
valueTypes.put(BigDecimal.class, ValueTypes.BIGDECIMAL);
valueTypes.put(BigInteger.class, ValueTypes.BIGINTEGER);
valueTypes.put(java.sql.Date.class, ValueTypes.SQLDATE);
valueTypes.put(java.sql.Time.class, ValueTypes.TIME);
valueTypes.put(java.sql.Timestamp.class, ValueTypes.TIMESTAMP);
}
/**
* カラムメタデータファクトリです。
*/
protected ColumnMetaFactory columnMetaFactory;
/**
* 永続化層の命名規約です。
*/
protected PersistenceConvention persistenceConvention;
public PropertyMeta createPropertyMeta(Field field, EntityMeta entityMeta) {
PropertyMeta propertyMeta = new PropertyMeta();
doField(propertyMeta, field, entityMeta);
doName(propertyMeta, field, entityMeta);
doTransient(propertyMeta, field, entityMeta);
if (!propertyMeta.isTransient()) {
Object relationshipAnnotation = getRelationshipAnnotation(field);
if (relationshipAnnotation == null) {
doColumnMeta(propertyMeta, field, entityMeta);
doId(propertyMeta, field, entityMeta);
doFetchType(propertyMeta, field, entityMeta);
doTemporal(propertyMeta, field, entityMeta);
doEnum(propertyMeta, field, entityMeta);
doVersion(propertyMeta, field, entityMeta);
doLob(propertyMeta, field, entityMeta);
doValueType(propertyMeta, entityMeta);
} else {
doRelationship(propertyMeta, field, entityMeta,
relationshipAnnotation);
}
}
doCustomize(propertyMeta, field, entityMeta);
return propertyMeta;
}
/**
* フィールドを処理します。
*
* @param propertyMeta
* プロパティメタデータ
* @param field
* フィールド
* @param entityMeta
* エンティティメタデータ
*/
protected void doField(PropertyMeta propertyMeta, Field field,
@SuppressWarnings("unused") EntityMeta entityMeta) {
propertyMeta.setField(field);
}
/**
* 名前を処理します。
*
* @param propertyMeta
* プロパティメタデータ
* @param field
* フィールド
* @param entityMeta
* エンティティメタデータ
*/
protected void doName(PropertyMeta propertyMeta, Field field,
@SuppressWarnings("unused") EntityMeta entityMeta) {
propertyMeta.setName(persistenceConvention
.fromFieldNameToPropertyName(field.getName()));
}
/**
* カラムメタデータを処理します。
*
* @param propertyMeta
* プロパティメタデータ
* @param field
* フィールド
* @param entityMeta
* エンティティメタデータ
*/
protected void doColumnMeta(PropertyMeta propertyMeta, Field field,
EntityMeta entityMeta) {
propertyMeta.setColumnMeta(columnMetaFactory.createColumnMeta(field,
entityMeta, propertyMeta));
}
/**
* 識別子メタデータを処理します。
*
* @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;
}
}
/**
* {@link GenerationType#IDENTITY}方式で識別子の値を自動生成するIDジェネレータを処理します。
*
* @param propertyMeta
* プロパティメタデータ
* @param entityMeta
* エンティティのメタデータ
*/
protected void doIdentityIdGenerator(PropertyMeta propertyMeta,
EntityMeta entityMeta) {
propertyMeta.setIdentityIdGenerator(new IdentityIdGenerator(entityMeta,
propertyMeta));
}
/**
* {@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;
}
/**
* {@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;
}
/**
* フェッチタイプを処理します。
*
* @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());
}
/**
* enumの種別を処理します。
*
* @param propertyMeta
* プロパティメタデータ
* @param field
* フィールド
* @param entityMeta
* エンティティメタデータ
*/
protected void doEnum(PropertyMeta propertyMeta, Field field,
EntityMeta entityMeta) {
if (!propertyMeta.getPropertyClass().isEnum()) {
return;
}
Enumerated enumerated = field.getAnnotation(Enumerated.class);
if (enumerated == null) {
return;
}
propertyMeta.setEnumType(enumerated.value());
}
/**
* バージョンチェック用かどうかを処理します。
*
* @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);
}
/**
* 一時的かどうかを処理します。
*
* @param propertyMeta
* プロパティメタデータ
* @param field
* フィールド
* @param entityMeta
* エンティティメタデータ
*/
protected void doTransient(PropertyMeta propertyMeta, Field field,
@SuppressWarnings("unused") EntityMeta entityMeta) {
propertyMeta.setTransient(field.getAnnotation(Transient.class) != null
|| ModifierUtil.isTransient(field));
}
/**
* <code>LOB</code>かどうかを処理します。
*
* @param propertyMeta
* プロパティメタデータ
* @param field
* フィールド
* @param entityMeta
* エンティティメタデータ
*/
protected void doLob(PropertyMeta propertyMeta, Field field,
@SuppressWarnings("unused") EntityMeta entityMeta) {
propertyMeta.setLob(field.getAnnotation(Lob.class) != null);
}
/**
* {@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());
}
/**
* フィールドに関連のアノテーションが指定されていればそれを返します。
*
* @param field
* フィールド
* @return 関連のアノテーションまたは<code>null</code>
*/
protected Object getRelationshipAnnotation(final Field field) {
final OneToOne oneToOne = field.getAnnotation(OneToOne.class);
if (oneToOne != null) {
return oneToOne;
}
final OneToMany oneToMany = field.getAnnotation(OneToMany.class);
if (oneToMany != null) {
return oneToMany;
}
final ManyToOne manyToOne = field.getAnnotation(ManyToOne.class);
if (manyToOne != null) {
return manyToOne;
}
final ManyToMany manyToMany = field.getAnnotation(ManyToMany.class);
if (manyToMany != null) {
return manyToMany;
}
return null;
}
/**
* 関連を処理します。
*
* @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());
}
}
/**
* 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 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 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
* エンティティメタデータ
* @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
* エンティティメタデータ
* @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
* エンティティメタデータ
*/
@SuppressWarnings("unused")
protected void doCustomize(PropertyMeta propertyMeta, Field field,
EntityMeta entityMeta) {
}
/**
* カラムメタデータファクトリを返します。
*
* @return カラムメタデータファクトリ
*/
public ColumnMetaFactory getColumnMetaFactory() {
return columnMetaFactory;
}
/**
* カラムメタデータファクトリを設定します。
*
* @param columnMetaFactory
* カラムメタデータファクトリ
*/
@Binding(bindingType = BindingType.MUST)
public void setColumnMetaFactory(ColumnMetaFactory columnMetaFactory) {
this.columnMetaFactory = columnMetaFactory;
}
/**
* 永続化層の命名規約を返します。
*
* @return 永続化層の命名規約
*/
public PersistenceConvention getPersistenceConvention() {
return persistenceConvention;
}
/**
* 永続化層の命名規約を設定します。
*
* @param persistenceConvention
* 永続化層の命名規約
*/
public void setPersistenceConvention(
PersistenceConvention persistenceConvention) {
this.persistenceConvention = persistenceConvention;
}
}