/* * 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.command.impl; import java.lang.reflect.Array; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.seasar.extension.dxo.IllegalSignatureRuntimeException; import org.seasar.extension.dxo.annotation.AnnotationReader; import org.seasar.extension.dxo.command.DxoCommand; import org.seasar.extension.dxo.converter.ConversionContext; import org.seasar.extension.dxo.converter.Converter; import org.seasar.extension.dxo.converter.ConverterFactory; import org.seasar.extension.dxo.converter.impl.ConversionContextImpl; import org.seasar.framework.exception.SIllegalArgumentException; /** * Dxoのメソッドに応じた変換を行うコマンドの抽象クラスです。 * * @author koichik */ public abstract class AbstractDxoCommand implements DxoCommand { /** Dxoのインターフェースまたはクラス */ protected Class dxoClass; /** Dxoのメソッド */ protected Method method; /** {@link Converter}のファクトリです。 */ protected ConverterFactory converterFactory; /** {@link AnnotationReader}のファクトリです。 */ protected AnnotationReader annotationReader; /** 変換のヘルパです。 */ protected ConversionHelper conversionHelper; /** * インスタンスを構築します。 * * @param dxoClass * Dxoのインターフェースまたはクラス * @param method * Dxoのメソッド * @param converterFactory * {@link Converter}のファクトリ * @param annotationReader * {@link AnnotationReader}のファクトリ */ public AbstractDxoCommand(final Class dxoClass, final Method method, final ConverterFactory converterFactory, final AnnotationReader annotationReader) { this.dxoClass = dxoClass; this.method = method; this.converterFactory = converterFactory; this.annotationReader = annotationReader; this.conversionHelper = getConversionHelper(method); } public Object execute(final Object[] args) { return conversionHelper.convert(args); } /** * 単一のオブジェクトを変換して返します。 * * @param source * 変換元のオブジェクト * @return 変換した結果のオブジェクト */ protected abstract Object convertScalar(Object source); /** * 単一のオブジェクト<code>src</code>を<code>dest</code>に変換します。 * * @param source * 変換元のオブジェクト * @param dest * 変換先のオブジェクト */ protected abstract void convertScalar(Object source, Object dest); /** * 変換先の要素の型を返します。 * * @return 変換先の要素の型 */ protected abstract Class getDestElementType(); /** * 変換先の要素型の配列を作成して返します。 * * @param length * 配列の長さ * @return 変換先の要素型の配列 */ protected Object[] createArray(final int length) { return (Object[]) Array.newInstance(getDestElementType(), length); } /** * 変換コンテキストを作成して返します。 * * @param source * 変換元のオブジェクト * @return 変換コンテキスト */ protected ConversionContext createContext(final Object source) { return new ConversionContextImpl(dxoClass, method, converterFactory, annotationReader, source); } /** * 変換ヘルパを作成して返します。 * * @param method * Dxoのメソッド * @return 変換ヘルパ */ protected ConversionHelper getConversionHelper(final Method method) { final Class[] parameterTypes = method.getParameterTypes(); final int parameterSize = parameterTypes.length; if (parameterSize != 1 && parameterSize != 2) { throw new IllegalSignatureRuntimeException(method .getDeclaringClass(), method); } final Class sourceType = parameterTypes[0]; final Class destType = parameterSize == 1 ? method.getReturnType() : parameterTypes[1]; if (sourceType.isArray()) { if (destType.isArray()) { return new ArrayToArrayConversionHelper(); } else if (List.class.isAssignableFrom(destType)) { return new ArrayToListConversionHelper(); } } else if (List.class.isAssignableFrom(sourceType)) { if (destType.isArray()) { return new ListToArrayConversionHelper(); } else if (List.class.isAssignableFrom(destType)) { return new ListToListConversionHelper(); } } else { return new ScalarConversionHelper(); } throw new IllegalSignatureRuntimeException(method.getDeclaringClass(), method); } /** * 変換元となる引数がnullの場合に{@link SIllegalArgumentException}をスローします。 * * @param source * 変換元となる引数 * @throws SIllegalArgumentException * 引数がnullの場合 */ protected void assertSource(Object source) throws SIllegalArgumentException { if (source == null) { throw new SIllegalArgumentException("ESSR0601", new Object[] { dxoClass, method }); } } /** * 変換先となる引数がnullの場合に{@link SIllegalArgumentException}をスローします。 * * @param dest * 変換先となる引数 * @throws SIllegalArgumentException * 引数がnullの場合 */ protected void assertDest(Object dest) throws SIllegalArgumentException { if (dest == null) { throw new SIllegalArgumentException("ESSR0602", new Object[] { dxoClass, method }); } } /** * メソッドのシグネチャに応じて変換を行うヘルパのインターフェースです。 */ public interface ConversionHelper { /** * 変換を行います。 * * @param args * Dxoメソッドの引数の配列 * @return Dxoメソッドの戻り値 */ Object convert(Object[] args); } /** * スカラ値 (配列でも{@link List}でもない型) を変換するヘルパです。 */ public class ScalarConversionHelper implements ConversionHelper { public Object convert(final Object[] args) { if (args.length == 1) { return convertScalar(args[0]); } final Object dest = args[1]; convertScalar(args[0], dest); return dest; } } /** * 配列から配列へ変換するヘルパです。 */ public class ArrayToArrayConversionHelper implements ConversionHelper { public Object convert(final Object[] args) { final Object[] src = (Object[]) args[0]; final Object[] dest = args.length == 1 ? createArray(src.length) : (Object[]) args[1]; for (int i = 0; i < src.length && i < dest.length; ++i) { dest[i] = convertScalar(src[i]); } return dest; } } /** * 配列から{@link List}へ変換するヘルパです。 */ public class ArrayToListConversionHelper implements ConversionHelper { public Object convert(final Object[] args) { final Object[] src = (Object[]) args[0]; final List dest = args.length == 1 ? new ArrayList() : (List) args[1]; dest.clear(); for (int i = 0; i < src.length; ++i) { dest.add(convertScalar(src[i])); } return dest; } } /** * {@link List}から配列へ変換するヘルパです。 */ public class ListToArrayConversionHelper implements ConversionHelper { public Object convert(final Object[] args) { final List src = (List) args[0]; final Object[] dest = args.length == 1 ? createArray(src.size()) : (Object[]) args[1]; int i = 0; for (final Iterator it = src.iterator(); it.hasNext() && i < dest.length; ++i) { dest[i] = convertScalar(it.next()); } return dest; } } /** * {@link List}から{@link List}へ変換するヘルパです。 */ public class ListToListConversionHelper implements ConversionHelper { public Object convert(final Object[] args) { final List source = (List) args[0]; final List dest = args.length == 1 ? new ArrayList() : (List) args[1]; dest.clear(); for (final Iterator it = source.iterator(); it.hasNext();) { dest.add(convertScalar(it.next())); } return dest; } } }