/* * 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.framework.aop.intertype; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.seasar.framework.aop.InterType; import org.seasar.framework.log.Logger; import org.seasar.framework.util.ClassUtil; import org.seasar.framework.util.StringUtil; /** * プロパティを追加するための{@link InterType}です。 * * @author y-komori * */ public class PropertyInterType extends AbstractInterType { private static final String SETTER_PREFIX = "set"; private static final String GETTER_PREFIX = "get"; /** * プロパティを追加しません。 */ protected static final int NONE = 0; /** * getterメソッドだけを追加します。 */ protected static final int READ = 1; /** * setterメソッドだけを追加します。 */ protected static final int WRITE = 2; /** * getter、setterメソッドを追加します。 */ protected static final int READWRITE = 3; /** * noneの値 */ protected static final String STR_NONE = "none"; /** * readの値 */ protected static final String STR_READ = "read"; /** * writeの値 */ protected static final String STR_WRITE = "write"; /** * readwriteの値 */ protected static final String STR_READWRITE = "readwrite"; private static final String TIGER_ANNOTATION_HANDLER = "org.seasar.framework.aop.intertype.TigerPropertyAnnotationHandler"; private static final String BACKPORT175_ANNOTATION_HANDLER = "org.seasar.framework.aop.intertype.Backport175PropertyAnnotationHandler"; private static Logger logger = Logger.getLogger(PropertyInterType.class); private static PropertyAnnotationHandler annotationHandler = new DefaultPropertyAnnotationHandler(); private boolean trace; private int defaultPropertyType = READWRITE; static { setupAnnotationHandler(); } /** * 値を求めます。 * * @param type * タイプ * @return 値 */ protected static int valueOf(String type) { int propertyType = NONE; if (STR_READ.equals(type)) { propertyType = READ; } else if (STR_WRITE.equals(type)) { propertyType = WRITE; } else if (STR_READWRITE.equals(type)) { propertyType = READWRITE; } return propertyType; } private static void setupAnnotationHandler() { Class clazz = null; try { clazz = Class.forName(TIGER_ANNOTATION_HANDLER, true, PropertyInterType.class.getClassLoader()); } catch (ClassNotFoundException e) { try { clazz = Class.forName(BACKPORT175_ANNOTATION_HANDLER, true, PropertyInterType.class.getClassLoader()); } catch (ClassNotFoundException e2) { return; } } annotationHandler = (PropertyAnnotationHandler) ClassUtil .newInstance(clazz); } /** * トレースを出力するかどうか設定します。 * * @param trace */ public void setTrace(boolean trace) { this.trace = trace; } /** * デフォルトのpropertyType(NONE, READ, WRITE, READWRITE)を設定します。 * * @param defaultPropertyType */ public void setDefaultPropertyType(String defaultPropertyType) { this.defaultPropertyType = valueOf(defaultPropertyType); } protected void introduce() { if (logger.isDebugEnabled()) { logger.debug("[PropertyInterType] Introducing... " + targetClass.getName()); } int defaultValue = annotationHandler.getPropertyType(getTargetClass(), defaultPropertyType); List targetFields = getTargetFields(targetClass); for (Iterator iter = targetFields.iterator(); iter.hasNext();) { Field field = (Field) iter.next(); int property = annotationHandler.getPropertyType(field, defaultValue); switch (property) { case READ: createGetter(targetClass, field); break; case WRITE: createSetter(targetClass, field); break; case READWRITE: createGetter(targetClass, field); createSetter(targetClass, field); break; default: break; } } } private void createGetter(Class targetClass, Field targetField) { String targetFieldName = targetField.getName(); String methodName = GETTER_PREFIX + createMethodName(targetFieldName); if (hasMethod(methodName, null)) { return; } if (logger.isDebugEnabled()) { logger.debug("[PropertyInterType] Creating getter " + targetClass.getName() + "#" + methodName); } StringBuffer src = new StringBuffer(512); src.append("{"); if (trace) { src.append("org.seasar.framework.log.Logger logger ="); src.append("org.seasar.framework.log.Logger.getLogger($class);"); src.append("if(logger.isDebugEnabled()){"); src .append("logger.debug(\"CALL \" + $class.getSuperclass().getName() + \"#"); src.append(methodName); src.append("() : \" + this."); src.append(targetFieldName); src.append(");}"); } src.append("return this."); src.append(targetFieldName); src.append(";}"); addMethod(targetField.getType(), methodName, src.toString()); } private void createSetter(Class targetClass, Field targetField) { String targetFieldName = targetField.getName(); String methodName = SETTER_PREFIX + createMethodName(targetFieldName); if (hasMethod(methodName, targetField.getType())) { return; } if (logger.isDebugEnabled()) { logger.debug("[PropertyInterType] Creating setter " + targetClass.getName() + "#" + methodName); } StringBuffer src = new StringBuffer(512); src.append("{"); if (trace) { src.append("org.seasar.framework.log.Logger logger ="); src.append("org.seasar.framework.log.Logger.getLogger($class);"); src.append("if(logger.isDebugEnabled()){"); src .append("logger.debug(\"CALL \" + $class.getSuperclass().getName() + \"#"); src.append(methodName); src.append("(\" + $1 + \")\");}"); } src.append("this."); src.append(targetFieldName); src.append(" = $1;}"); addMethod(methodName, new Class[] { targetField.getType() }, src .toString()); } private List getTargetFields(Class targetClass) { final Map nominationFields = new LinkedHashMap(); gatherFields(targetClass, nominationFields); final List targetFields = new ArrayList(nominationFields.size()); for (final Iterator it = nominationFields.values().iterator(); it .hasNext();) { final Field field = (Field) it.next(); final int modifier = field.getModifiers(); if (!Modifier.isPrivate(modifier)) { targetFields.add(field); } } return targetFields; } private void gatherFields(final Class targetClass, final Map fields) { final Field[] declaredFields = targetClass.getDeclaredFields(); for (int i = 0; i < declaredFields.length; ++i) { final Field field = declaredFields[i]; final String name = field.getName(); if (!fields.containsKey(name)) { fields.put(name, field); } } final Class superClass = targetClass.getSuperclass(); if (superClass != null && superClass != Object.class) { gatherFields(superClass, fields); } } private String createMethodName(String fieldName) { String methodName = StringUtil.capitalize(fieldName); if (methodName.endsWith("_")) { methodName = methodName.substring(0, methodName.length() - 1); } return methodName; } private boolean hasMethod(String methodName, Class paramType) { Class[] param = null; if (paramType != null) { param = new Class[] { paramType }; } try { getTargetClass().getMethod(methodName, param); return true; } catch (NoSuchMethodException e) { return false; } } /** * */ public interface PropertyAnnotationHandler { /** * propertyTypeを返します。 * * @param clazz * @param defaultValue * @return propertyType */ int getPropertyType(Class clazz, int defaultValue); /** * propertyTypeを返します。 * * @param field * @param defaultValue * @return */ int getPropertyType(Field field, int defaultValue); } /** * {@link PropertyInterType.PropertyAnnotationHandler}のデフォルト実装です。 * */ public static class DefaultPropertyAnnotationHandler implements PropertyAnnotationHandler { public int getPropertyType(Class clazz, int defaultValue) { return defaultValue; } public int getPropertyType(Field field, int defaultValue) { return defaultValue; } } }