001 // Copyright 2005 The Apache Software Foundation 002 // 003 // Licensed under the Apache License, Version 2.0 (the "License"); 004 // you may not use this file except in compliance with the License. 005 // You may obtain a copy of the License at 006 // 007 // http://www.apache.org/licenses/LICENSE-2.0 008 // 009 // Unless required by applicable law or agreed to in writing, software 010 // distributed under the License is distributed on an "AS IS" BASIS, 011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 012 // See the License for the specific language governing permissions and 013 // limitations under the License. 014 015 package org.apache.tapestry.annotations; 016 017 import java.beans.Introspector; 018 import java.lang.annotation.Annotation; 019 import java.lang.reflect.Method; 020 import java.util.Iterator; 021 022 import org.apache.hivemind.ApplicationRuntimeException; 023 import org.apache.hivemind.Location; 024 import org.apache.hivemind.Resource; 025 import org.apache.tapestry.spec.IBindingSpecification; 026 import org.apache.tapestry.spec.IContainedComponent; 027 import org.apache.tapestry.util.DescribedLocation; 028 029 /** 030 * @author Howard M. Lewis Ship 031 * @since 4.0 032 */ 033 034 public final class AnnotationUtils 035 { 036 /* defeat instantiation */ 037 private AnnotationUtils() { } 038 039 /** 040 * Determines the property name for a method, by stripping off the is/get/set prefix and 041 * decapitalizing the first name. 042 * 043 * @param method 044 * accessor method (get/set/is) 045 * @return the property name for the method 046 * @throws ApplicationRuntimeException 047 * if the method is not an accessor or mutator method 048 */ 049 public static String getPropertyName(Method method) 050 { 051 String name = method.getName(); 052 053 if (name.startsWith("is")) 054 { 055 checkGetter(method); 056 return Introspector.decapitalize(name.substring(2)); 057 } 058 059 if (name.startsWith("get")) 060 { 061 checkGetter(method); 062 return Introspector.decapitalize(name.substring(3)); 063 } 064 065 if (name.startsWith("set")) 066 { 067 checkSetter(method); 068 return Introspector.decapitalize(name.substring(3)); 069 } 070 071 throw new ApplicationRuntimeException(AnnotationMessages.notAccessor(method)); 072 } 073 074 /** 075 * Converts a method name to a property key. The steps performed are: 076 * <p>The prefix "get" is stripped off (if present) 077 * <p>The letter following "get" is converted to lower case 078 * <p>Other capitalized letters are converted to lower case and preceded with a dash ("-") 079 * 080 * @param methodName the method to convert 081 * @return the converted key 082 * 083 * @since 4.1.1 084 */ 085 public static String convertMethodNameToKeyName(String methodName) 086 { 087 StringBuffer buffer = new StringBuffer(); 088 089 int cursorx = methodName.startsWith("get") ? 3 : 0; 090 int length = methodName.length(); 091 boolean atStart = true; 092 093 while (cursorx < length) 094 { 095 char ch = methodName.charAt(cursorx); 096 097 if (Character.isUpperCase(ch)) 098 { 099 if (!atStart) 100 buffer.append('-'); 101 buffer.append(Character.toLowerCase(ch)); 102 } 103 else 104 buffer.append(ch); 105 106 atStart = false; 107 108 cursorx++; 109 } 110 111 return buffer.toString(); 112 } 113 114 /** 115 * Copies all bindings of a component to another one. 116 * @param source 117 * @param target 118 * 119 * @since 4.1.1 120 */ 121 public static void copyBindings(IContainedComponent source, IContainedComponent target) 122 { 123 Iterator i = source.getBindingNames().iterator(); 124 while (i.hasNext()) 125 { 126 String bindingName = (String) i.next(); 127 IBindingSpecification binding = source.getBinding(bindingName); 128 target.setBinding(bindingName, binding); 129 } 130 131 target.setType(source.getType()); 132 } 133 134 private static void checkGetter(Method method) 135 { 136 if (method.getParameterTypes().length > 0) 137 throw new ApplicationRuntimeException(AnnotationMessages.noParametersExpected(method)); 138 139 if (method.getReturnType().equals(void.class)) 140 throw new ApplicationRuntimeException(AnnotationMessages.voidAccessor(method)); 141 142 } 143 144 private static void checkSetter(Method method) 145 { 146 if (!method.getReturnType().equals(void.class)) 147 throw new ApplicationRuntimeException(AnnotationMessages.nonVoidMutator(method)); 148 149 if (method.getParameterTypes().length != 1) 150 throw new ApplicationRuntimeException(AnnotationMessages.wrongParameterCount(method)); 151 } 152 153 public static Location buildLocationForAnnotation(Method method, Annotation annotation, 154 Resource classResource) 155 { 156 return new DescribedLocation(classResource, AnnotationMessages.methodAnnotation( 157 annotation, 158 method)); 159 } 160 }