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 }