/*
* 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.dxo.annotation.impl;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import org.seasar.extension.dxo.DxoConstants;
import org.seasar.extension.dxo.annotation.AnnotationReader;
import org.seasar.extension.dxo.converter.Converter;
import org.seasar.framework.beans.BeanDesc;
import org.seasar.framework.beans.factory.BeanDescFactory;
import org.seasar.framework.beans.util.BeanUtil;
import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.util.ConstantAnnotationUtil;
import org.seasar.framework.util.ClassUtil;
import org.seasar.framework.util.FieldUtil;
import org.seasar.framework.util.MapUtil;
/**
* Dxoから定数アノテーションを読み取る{@link AnnotationReader}の実装クラスです。
*
* @author Satoshi Kimura
* @author koichik
*/
public class ConstantAnnotationReader implements AnnotationReader {
/** S2コンテナ */
protected S2Container container;
/** 変換先クラスに指定されたコンバータのキャッシュです */
protected Map convertersCache = MapUtil.createHashMap();
/**
* インスタンスを構築します。
*
* @param container
* S2コンテナ
*/
public ConstantAnnotationReader(final S2Container container) {
this.container = container.getRoot();
}
public String getDatePattern(final Class dxoClass, final Method method) {
return getDatePattern(dxoClass, method, DxoConstants.DATE_PATTERN);
}
public String getTimePattern(final Class dxoClass, final Method method) {
return getDatePattern(dxoClass, method, DxoConstants.TIME_PATTERN);
}
public String getTimestampPattern(final Class dxoClass, final Method method) {
return getDatePattern(dxoClass, method, DxoConstants.TIMESTAMP_PATTERN);
}
public String getConversionRule(final Class dxoClass, final Method method) {
final BeanDesc dxoBeanDesc = BeanDescFactory.getBeanDesc(dxoClass);
String fieldName = getConstantAnnotationName(method,
DxoConstants.CONVERSION_RULE);
if (dxoBeanDesc.hasField(fieldName)) {
return (String) dxoBeanDesc.getFieldValue(fieldName, null);
}
fieldName = method.getName() + "_" + DxoConstants.CONVERSION_RULE;
if (dxoBeanDesc.hasField(fieldName)) {
return (String) dxoBeanDesc.getFieldValue(fieldName, null);
}
return null;
}
public boolean isExcludeNull(final Class dxoClass, final Method method) {
final BeanDesc dxoBeanDesc = BeanDescFactory.getBeanDesc(dxoClass);
String fieldName = getConstantAnnotationName(method,
DxoConstants.EXCLUDE_NULL);
if (dxoBeanDesc.hasField(fieldName)) {
return true;
}
fieldName = method.getName() + "_" + DxoConstants.EXCLUDE_NULL;
if (dxoBeanDesc.hasField(fieldName)) {
return true;
}
return false;
}
public boolean isExcludeWhitespace(final Class dxoClass, final Method method) {
final BeanDesc dxoBeanDesc = BeanDescFactory.getBeanDesc(dxoClass);
String fieldName = getConstantAnnotationName(method,
DxoConstants.EXCLUDE_WHITESPACE);
if (dxoBeanDesc.hasField(fieldName)) {
return true;
}
fieldName = method.getName() + "_" + DxoConstants.EXCLUDE_WHITESPACE;
if (dxoBeanDesc.hasField(fieldName)) {
return true;
}
return false;
}
public String getSourcePrefix(final Class dxoClass, final Method method) {
final BeanDesc dxoBeanDesc = BeanDescFactory.getBeanDesc(dxoClass);
String fieldName = getConstantAnnotationName(method,
DxoConstants.SOURCE_PREFIX);
if (dxoBeanDesc.hasField(fieldName)) {
return (String) dxoBeanDesc.getFieldValue(fieldName, null);
}
fieldName = method.getName() + "_" + DxoConstants.SOURCE_PREFIX;
if (dxoBeanDesc.hasField(fieldName)) {
return (String) dxoBeanDesc.getFieldValue(fieldName, null);
}
return null;
}
public String getDestPrefix(final Class dxoClass, final Method method) {
final BeanDesc dxoBeanDesc = BeanDescFactory.getBeanDesc(dxoClass);
String fieldName = getConstantAnnotationName(method,
DxoConstants.DEST_PREFIX);
if (dxoBeanDesc.hasField(fieldName)) {
return (String) dxoBeanDesc.getFieldValue(fieldName, null);
}
fieldName = method.getName() + "_" + DxoConstants.DEST_PREFIX;
if (dxoBeanDesc.hasField(fieldName)) {
return (String) dxoBeanDesc.getFieldValue(fieldName, null);
}
return null;
}
public Map getConverters(final Class destClass) {
final Map converters = (Map) convertersCache.get(destClass);
if (converters != null) {
return converters;
}
return createConverters(destClass);
}
/**
* 日付(<code>Date, Time, Timestamp</code>)と<code>String</code>の変換フォーマットを返します。
*
* @param dxoClass
* Dxoクラスまたはインタフェース
* @param method
* Dxoメソッド
* @param annotation
* 定数アノテーション名
* @return 変換フォーマット
*/
protected String getDatePattern(final Class dxoClass, final Method method,
final String annotation) {
final BeanDesc dxoBeanDesc = BeanDescFactory.getBeanDesc(dxoClass);
String fieldName = getConstantAnnotationName(method, annotation);
if (dxoBeanDesc.hasField(fieldName)) {
return (String) dxoBeanDesc.getFieldValue(fieldName, null);
}
fieldName = method.getName() + "_" + annotation;
if (dxoBeanDesc.hasField(fieldName)) {
return (String) dxoBeanDesc.getFieldValue(fieldName, null);
}
fieldName = annotation;
if (dxoBeanDesc.hasField(fieldName)) {
return (String) dxoBeanDesc.getFieldValue(fieldName, null);
}
return null;
}
/**
* 変換先クラスに指定されたコンバータの{@link Map}を作成して返します。
*
* @param destClass
* 変換先クラス
* @return 変換先クラスに指定されたコンバータの{@link Map}
*/
protected Map createConverters(final Class destClass) {
final Map converters = new HashMap();
final BeanDesc beanDesc = BeanDescFactory.getBeanDesc(destClass);
for (int i = 0; i < beanDesc.getFieldSize(); ++i) {
final Field field = beanDesc.getField(i);
if (!ConstantAnnotationUtil.isConstantAnnotation(field)) {
continue;
}
if (!field.getName().endsWith("DxoConverter")) {
continue;
}
final String fieldName = field.getName();
final int index = fieldName.lastIndexOf("_");
final String propertyName = fieldName.substring(0, index);
if (!beanDesc.hasPropertyDesc(propertyName)) {
continue;
}
final String converterName = fieldName.substring(index + 1);
if (!container.hasComponentDef(converterName)) {
continue;
}
final Converter converter = (Converter) container
.getComponent(converterName);
final String s = (String) FieldUtil.get(field, null);
final Map props = ConstantAnnotationUtil.convertExpressionToMap(s);
BeanUtil.copyProperties(props, converter);
converters.put(propertyName, converter);
}
convertersCache.put(destClass, converters);
return converters;
}
/**
* 指定されたメソッド固有の定数アノテーション名を返します。
*
* @param method
* メソッド
* @param suffix
* 定数アノテーションのsuffix
* @return 指定されたメソッド固有の定数アノテーション名
*/
protected String getConstantAnnotationName(final Method method,
final String suffix) {
final StringBuffer buf = new StringBuffer(100).append(method.getName());
final Class[] parameterTypes = method.getParameterTypes();
for (int i = 0; i < parameterTypes.length; i++) {
buf.append("_").append(getShortClassName(parameterTypes[i]));
}
buf.append("_").append(suffix);
return new String(buf);
}
/**
* クラスを表す単純な名前を返します。
*
* @param clazz
* クラス
* @return クラスを表す単純な名前
*/
protected String getShortClassName(final Class clazz) {
if (clazz.isArray()) {
return ClassUtil.getShortClassName(clazz.getComponentType()) + "$";
}
return ClassUtil.getShortClassName(clazz);
}
}