/* * 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.util; import java.lang.reflect.Method; import java.util.List; import java.util.Map; import org.seasar.framework.util.MethodUtil; import org.seasar.framework.util.StringUtil; import org.seasar.framework.util.Tokenizer; /** * Dxoのユーティリティクラスです。 * * @author koichik * @author higa */ public class DxoUtil { /** genericな{@link Map}から値の型を取得するためのメソッドです。 */ protected static final Method GET_VALUE_TYPE_OF_TARGET_MAP_METHOD = getValueTypeOfTargetMapMethod(); /** * S2-Tigerが利用可能な場合、Dxoのメソッドからgenericな{@link List}である変換先の要素型を返します。 * * @param method * Dxoのメソッド * @return Dxoのメソッドからgenericな{@link List}である変換先の要素型 */ public static Class getElementTypeOfList(final Method method) { final Class[] parameterTypes = method.getParameterTypes(); return parameterTypes.length == 1 ? MethodUtil .getElementTypeOfListFromReturnType(method) : MethodUtil .getElementTypeOfListFromParameterType(method, 1); } /** * S2-Tigerが利用可能な場合、Dxoのメソッドからgenericな{@link Map}である変換先の値の型を返します。 * * @param method * Dxoのメソッド * @return Dxoのメソッドからgenericな{@link Map}である変換先の値の型 */ public static Class getValueTypeOfTargetMap(final Method method) { if (GET_VALUE_TYPE_OF_TARGET_MAP_METHOD == null) { return null; } return (Class) MethodUtil.invoke(GET_VALUE_TYPE_OF_TARGET_MAP_METHOD, null, new Object[] { method }); } /** * S2-Tigerが利用可能な場合、Dxoのメソッドからgenericな{@link Map}である変換先の値の型を返すメソッドを返します。 * * @return Dxoのメソッドからgenericな{@link Map}である変換先の値の型を返すメソッド */ protected static Method getValueTypeOfTargetMapMethod() { try { final Class clazz = Class .forName("org.seasar.extension.dxo.util.DxoTigerUtil"); return clazz.getMethod("getValueTypeOfTargetMap", new Class[] { Method.class }); } catch (final Throwable ignore) { } return null; } /** * 変換ルールを解析した結果の式オブジェクトを返します。 * * @param rule * 変換ルール * @return 変換ルールを解析した結果の式オブジェクト */ public static Expression parseRule(final String rule) { if (StringUtil.isEmpty(rule)) { return null; } Expression exp = SimpleExpressionParser.parse(rule); if (exp == null) { exp = new OgnlExpression(rule); } return exp; } /** * <code>CONVERSION_RULE</code>アノテーションで指定される簡素な{@link Map}表現を OGNLの{@link Map}リテラルに変換して返します。 * <p> * 簡素な{@link Map}表現は次の形式の文字列です。 * </p> * * <pre> * key1 : value1, key2 : value2 ... * </pre> * * <p> * これをOGNLの{@link Map}リテラルにするため,キーをシングルクオートで囲んだ文字列を返します。 * 値に複雑な式が指定されると適切に変換できない場合があります。 そのような場合は簡素な{@link Map}表現ではなく、 OGNLの{@link Map}リテラルを使用してください。 * </p> * * @param expr * <code>CONVERSION_RULE</code>アノテーションで指定される簡素な{@link Map}表現 * @return OGNLの{@link Map}リテラル */ protected static String addQuote(final String expr) { final MyTokenizer tokenizer = new MyTokenizer(expr); final StringBuffer buf = new StringBuffer(expr.length() + 10); for (int token = tokenizer.nextToken(); token != Tokenizer.TT_EOF;) { if (token == Tokenizer.TT_QUOTE || token == Tokenizer.TT_WORD) { buf.append('\'').append(tokenizer.getStringValue()) .append('\''); } else { throw new IllegalArgumentException(expr + "(" + token + ")"); } token = tokenizer.nextToken(); if (token == MyTokenizer.TT_COLON) { buf.append((char) token); } else { throw new IllegalArgumentException(expr + "(" + token + ")"); } token = tokenizer.nextToken(); if (token == Tokenizer.TT_QUOTE) { buf.append('\'').append(tokenizer.getStringValue()) .append('\''); } else if (token == Tokenizer.TT_WORD) { buf.append(tokenizer.getStringValue()); } else { throw new IllegalArgumentException(expr + "(" + token + ")"); } token = tokenizer.nextToken(); if (token == MyTokenizer.TT_COMMA) { buf.append((char) token); token = tokenizer.nextToken(); } else if (token == Tokenizer.TT_EOF) { break; } else { throw new IllegalArgumentException(expr + "(" + token + ")"); } } return buf.toString(); } /** * <code>CONVERSION_RULE</code>アノテーションで指定される簡素な{@link Map}表現からトークンを取り出すクラスです。 */ protected static class MyTokenizer extends Tokenizer { /** コロン */ public static final int TT_COLON = ':'; /** カンマ */ public static final int TT_COMMA = ','; /** 単語の構成要素ではない文字の配列 */ private static byte[] defaultCtype = new byte[256]; static { setup(defaultCtype); } /** * インスタンスを構築します。 * * @param str * <code>CONVERSION_RULE</code>アノテーションで指定される簡素な{@link Map}表現 */ public MyTokenizer(final String str) { this(str, defaultCtype); } /** * インスタンスを構築します。 * * @param str * <code>CONVERSION_RULE</code>アノテーションで指定される簡素な{@link Map}表現 * @param ctype */ public MyTokenizer(final String str, final byte[] ctype) { super(str, ctype); } protected static void setup(final byte[] ctype2) { Tokenizer.setup(ctype2); ordinaryChar(ctype2, TT_COLON); ordinaryChar(ctype2, TT_COMMA); } } }