StoredPropertyMeta.java
package com.github.mygreen.sqlmapper.core.meta;
import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import java.util.NoSuchElementException;
import java.util.Optional;
import javax.annotation.Nullable;
import org.springframework.util.LinkedCaseInsensitiveMap;
import com.github.mygreen.sqlmapper.core.annotation.In;
import com.github.mygreen.sqlmapper.core.annotation.InOut;
import com.github.mygreen.sqlmapper.core.annotation.Out;
import com.github.mygreen.sqlmapper.core.annotation.ResultSet;
import com.github.mygreen.sqlmapper.core.type.ValueType;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
/**
* ストアドプロシージャ/ストアドファンクションのDTO形式のパラメータのプロパティ。
*
* @since 0.3
* @author T.TSUCHIE
*
*/
@Slf4j
public class StoredPropertyMeta extends PropertyBase {
/**
* パラメータ名。
*/
@Getter
@Setter
private String paramName;
/**
* 値の変換処理
*/
private Optional<ValueType<?>> valueType = Optional.empty();
/**
* Bean形式ではない1つのオブジェクトの場合
*/
@Getter
@Setter
private boolean singleValue;
/**
* ネストしたBean形式のプロパティの情報
* <p>key=プロパティ名</p>
*/
private LinkedCaseInsensitiveMap<PropertyMeta> nestedPropertyMetaMap = new LinkedCaseInsensitiveMap<>();
/**
* ネストしたBean形式のプロパティの情報
* <p>key=カラム名</p>
*/
private LinkedCaseInsensitiveMap<PropertyMeta> nestedColumnPropertyMetaMap = new LinkedCaseInsensitiveMap<>();
/**
* Beanの親のプロパティ情報
*/
private Optional<StoredPropertyMeta> parent = Optional.empty();
/**
* Genericsのコンポーネントタイプ
*/
@Getter
private Optional<Class<?>> componentType = Optional.empty();
/**
* プロパティのインスタンス情報を作成します。
* @param name プロパティ名
* @param propertyType プロパティのクラスタイプ
*/
public StoredPropertyMeta(String name, Class<?> propertyType) {
super(name, propertyType);
}
/**
* {@literal IN}用のパラメータかどうか。
* @return 他のパラメータ(OUT/IN-OUT/ResultSet)でない場合も該当します。
*/
public boolean isIn() {
return hasAnnotation(In.class)
|| (!isOut() && !isInOut() && !isResultSet());
}
/**
* {@literal OUT}用のパラメータかどうか。
* @return
*/
public boolean isOut() {
return hasAnnotation(Out.class);
}
/**
* {@literal IN-OUT}用のパラメータかどうか。
* @return
*/
public boolean isInOut() {
return hasAnnotation(InOut.class);
}
/**
* {@literal ResultSet}用のパラメータかどうか。
* @return
*/
public boolean isResultSet() {
return hasAnnotation(ResultSet.class);
}
/**
* このプロパティに対して値を設定する。
* @param entityObject 親のオブジェクト
* @param propertyValue 設定するプロパティの値
* @throws NullPointerException 引数{@literal entityObject}がnullの場合
*/
public void setPropertyValue(final @NonNull Object entityObject, final Object propertyValue) {
if(getWriteMethod().isPresent()) {
try {
getWriteMethod().get().invoke(entityObject, propertyValue);
} catch (IllegalAccessException | IllegalArgumentException
| InvocationTargetException e) {
//TODO: 例外を見直す
throw new RuntimeException("Fail set property value for writer method.", e);
}
} else if(getField().isPresent()) {
try {
getField().get().set(entityObject, propertyValue);
} catch (IllegalArgumentException | IllegalAccessException e) {
//TODO: 例外を見直す
throw new RuntimeException("Fail set property value for field.", e);
}
} else {
log.warn("Not found saving method or field with property value in {}#{}",
entityObject.getClass().getName(), getName());
//TODO: フラグでquietlyをつける
throw new IllegalStateException();
}
}
/**
* このプロパティの値を取得する。
* @param entityObject ルートとなるエンティティオブジェクト
* @return プロパティの値。
* @throws NullPointerException 引数がnullのとき
* @throws IllegalStateException 取得対象のフィールドやメソッドがない場合
*/
public Object getPropertyValue(final @NonNull Object entityObject) {
// ルート直下のプロパティの場合
if(getReadMethod().isPresent()) {
try {
return getReadMethod().get().invoke(entityObject);
} catch (IllegalAccessException | IllegalArgumentException
| InvocationTargetException e) {
//TODO: 例外を見直す
throw new RuntimeException("Fail get property value for reader method.", e);
}
} else if(getField().isPresent()) {
try {
return getField().get().get(entityObject);
} catch (IllegalArgumentException | IllegalAccessException e) {
//TODO: 例外を見直す
throw new RuntimeException("Fail get property value for field.", e);
}
} else {
log.warn("Not found reading method or field with property value in {}#{}",
entityObject.getClass().getName(), getName());
throw new IllegalStateException();
}
}
/**
* プロパティに対する {@link ValueType} を取得します。
* @return JavaBean({@link #isSingleValue()} = false) のとき、{@literal null} を返します。
*/
public ValueType<?> getValueType() {
return valueType.orElse(null);
}
/**
* プロパティに対する {@link ValueType} を設定します。
* @param valueType プロパティに対する {@link ValueType}。
*/
public void setValueType(@NonNull ValueType<?> valueType) {
this.valueType = Optional.of(valueType);
}
/**
* JavaBean形式のネストしたプロパティ情報を追加する
* @param nestedPropertyMeta JavaBean形式のネストしたプロパティ
*/
public void addNestedPropertyMeta(@NonNull PropertyMeta nestedPropertyMeta) {
this.nestedPropertyMetaMap.put(nestedPropertyMeta.getName(), nestedPropertyMeta);
if(nestedPropertyMeta.getColumnMeta() != null) {
this.nestedColumnPropertyMetaMap.put(nestedPropertyMeta.getColumnMeta().getName(), nestedPropertyMeta);
}
}
/**
* JavaBean形式のネストしたクラスのプロパティかどか判定する。
* @return 埋め込み用のクラスのプロパティの場合trueを変す。
*/
public boolean hasParent() {
return parent.isPresent();
}
/**
* JavaBean形式のネストしたクラスのプロパティの親情報を取得する。
* @return 親情のプロパティ情報
* @throws NoSuchElementException 親が存在しないときにスローされます。
*/
public StoredPropertyMeta getParent() {
return parent.get();
}
/**
* JavaBean形式のネストしたプロパティの一覧を取得する。
* @return
*/
public Collection<PropertyMeta> getAllNestedPopertyMetaList() {
return nestedPropertyMetaMap.values();
}
/**
* カラムに紐づく全てのプロパティメタ情報を取得します。
* @return カラムに紐づく全てのプロパティメタ情報
*/
public Collection<PropertyMeta> getAllNestedColumnPropertyMeta() {
return nestedColumnPropertyMetaMap.values();
}
/**
* 指定したカラム名に一致するネストしたプロパティを探索します。
*
*
* @param columnName カラム名
* @return 一致するプロパティ情報
*/
public Optional<PropertyMeta> findNestedColumnPropertyMeta(final String columnName) {
PropertyMeta foundPropertyMeta = nestedColumnPropertyMetaMap.get(columnName);
if(foundPropertyMeta != null) {
return Optional.of(foundPropertyMeta);
}
return Optional.empty();
}
/**
* コンポーネントタイプを設定します。
* <p>CollectionのときなどのGenericsのタイプを取得します。
* @param componentType コンポーネントタイプ
*/
public void setComponentType(@Nullable Class<?> componentType) {
this.componentType = Optional.of(componentType);
}
}