View Javadoc

1   /*
2    * Copyright 2012-2013 smartics, Kronseder & Reiner GmbH
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package de.smartics.properties.spi.config.proxy;
17  
18  import java.lang.annotation.Annotation;
19  import java.lang.reflect.Method;
20  
21  import org.apache.commons.lang.WordUtils;
22  
23  import de.smartics.properties.api.core.annotations.PropertyMetaDataMethod;
24  
25  /**
26   * Helper.
27   */
28  public final class PropertyMethodNameUtilities
29  { // NOPMD
30  
31    // ********************************* Fields *********************************
32  
33    // --- constants ------------------------------------------------------------
34  
35    /**
36     * The "get" string prefix for getter methods.
37     */
38    private static final String GET_PREFIX = "get";
39  
40    /**
41     * The default naming convention suffix used to indicate that the method that
42     * ends with this string is a method to get the property descriptor.
43     */
44    private static final String PROPERTY_DESCRIPTOR_SUFFIX = "PropertyDescriptor";
45  
46    /**
47     * The default naming convention suffix used to indicate that the method that
48     * ends with this string is a method to get the property key.
49     */
50    private static final String PROPERTY_KEY_SUFFIX = "PropertyKey";
51  
52    // --- members --------------------------------------------------------------
53  
54    // ****************************** Initializer *******************************
55  
56    // ****************************** Constructors ******************************
57  
58    private PropertyMethodNameUtilities()
59    {
60  
61    }
62  
63    // ****************************** Inner Classes *****************************
64  
65    // ********************************* Methods ********************************
66  
67    // --- init -----------------------------------------------------------------
68  
69    // --- get&set --------------------------------------------------------------
70  
71    // --- business -------------------------------------------------------------
72  
73    /**
74     * Helper that determines the property method that belongs to the method
75     * given.
76     *
77     * @param m the method whose property method shall be determined.
78     * @return the property method for the given method.
79     */
80    public static Method fetchPropertyMethod(final Method m)
81    {
82      final Method propertyMethod;
83      if (isMethodAnnotatedWithAnnotation(PropertyMetaDataMethod.class, m))
84      {
85        propertyMethod = fetchPropertyMethodUsingAnnotation(m);
86      }
87      else
88      {
89        propertyMethod = fetchPropertyMethodUsingNamingConvention(m);
90      }
91      return propertyMethod;
92    }
93  
94    /**
95     * Determine whether or not the given method is annotated with a special
96     * annotation.
97     *
98     * @param annotation the annotation that shall be detected.
99     * @param m the method whose annotation shall be checked.
100    * @param <T> to limit the parameter to Annotations.
101    * @return true if the given method is annotated wit the given annotation,
102    *         false otherwise.
103    */
104   public static <T extends Annotation> boolean isMethodAnnotatedWithAnnotation(
105       final Class<T> annotation, final Method m)
106   {
107     return fetchAnnotation(annotation, m) != null;
108   }
109 
110   private static Method fetchPropertyMethodUsingNamingConvention(final Method m)
111   {
112     // TODO HERE AND Immediately Tests for all
113     final String methodName = m.getName();
114     final String propertyMethodName =
115         calculateMethodNameUsingNamingConvention(methodName);
116     final Class<?> propertyClass = m.getDeclaringClass();
117     Method propertyMethod = null;
118     try
119     {
120       final Method[] methods = propertyClass.getDeclaredMethods();
121       propertyMethod = lookupMethod(propertyMethodName, methods);
122 
123       if (propertyMethod == null)
124       {
125         propertyMethod = lookupGetterMethod(propertyMethodName, methods);
126       }
127 
128       if (propertyMethod == null)
129       {
130         throw new PropertyMethodNotFoundException(
131             "Method :'" // NOPMD
132                 + propertyMethodName
133                 + "' or its getter type method could not be found in interface: "
134                 + propertyClass.getCanonicalName());
135       }
136     }
137     catch (final SecurityException e)
138     {
139       throw new PropertyMethodNotFoundException(
140           "Method :'" + methodName + "' could not be found in interface: " // NOPMD
141               + propertyClass.getCanonicalName(), e);
142     }
143     return propertyMethod;
144   }
145 
146   private static Method lookupGetterMethod(final String propertyMethodName,
147       final Method[] methods)
148   {
149     Method propertyMethod;
150     final String getter = GET_PREFIX + WordUtils.capitalize(propertyMethodName);
151     propertyMethod = lookupMethod(getter, methods);
152     return propertyMethod;
153   }
154 
155   private static Method lookupMethod(final String propertyMethodName,
156       final Method[] methods)
157   {
158     for (int i = 0; i < methods.length; i++)
159     {
160       final String name = methods[i].getName();
161       if (name.equals(propertyMethodName))
162       {
163         return methods[i];
164       }
165     }
166     return null;
167   }
168 
169   private static String calculateMethodNameUsingNamingConvention(
170       final String methodName)
171   {
172     String propertyMethodName;
173     if (methodName.endsWith(PROPERTY_KEY_SUFFIX))
174     {
175       propertyMethodName = eliminateSuffix(methodName, PROPERTY_KEY_SUFFIX);
176     }
177     else if (methodName.endsWith(PROPERTY_DESCRIPTOR_SUFFIX))
178     {
179       propertyMethodName =
180           eliminateSuffix(methodName, PROPERTY_DESCRIPTOR_SUFFIX);
181     }
182     else
183     {
184       throw new PropertyMethodNotFoundException(
185           "Method :'"
186               + methodName // NOPMD
187               + "' is not a valid name for a property metadata method. "
188               + "Property metadata methods for keys must end with '"
189               + PROPERTY_KEY_SUFFIX + "' and for property descriptors with '"
190               + PROPERTY_DESCRIPTOR_SUFFIX
191               + "'. They may start with \"get\" but must not.");
192     }
193 
194     if (propertyMethodName.startsWith(GET_PREFIX))
195     {
196       propertyMethodName = eliminatePrefix(propertyMethodName, GET_PREFIX);
197     }
198     return propertyMethodName;
199   }
200 
201   private static String eliminatePrefix(
202       final String propertyMethodNameWithPrefix, final String prefix)
203   {
204     final String methodNameWithoutGet =
205         propertyMethodNameWithPrefix.substring(prefix.length());
206     final String propertyMethodName =
207         WordUtils.uncapitalize(methodNameWithoutGet);
208     return propertyMethodName;
209   }
210 
211   private static String eliminateSuffix(final String methodName,
212       final String suffix)
213   {
214     String propertyMethodName;
215     propertyMethodName =
216         methodName.substring(0, methodName.length() - suffix.length());
217     return propertyMethodName;
218   }
219 
220   private static Method fetchPropertyMethodUsingAnnotation(final Method m)
221   {
222     final PropertyMetaDataMethod annotation =
223         fetchAnnotation(PropertyMetaDataMethod.class, m);
224     final String methodName = annotation.value();
225     final Method propertyMethod =
226         fetchMethodByName(m.getDeclaringClass(), methodName);
227     return propertyMethod;
228   }
229 
230   private static Method fetchMethodByName(final Class<?> class1,
231       final String methodName)
232   {
233     try
234     {
235       return class1.getDeclaredMethod(methodName, (Class<?>[]) null);
236     }
237     catch (final SecurityException e)
238     {
239       throw new PropertyMethodNotFoundException("Method :'" + methodName
240                                                 + "' not found in interface: "
241                                                 + class1.getCanonicalName(), e);
242     }
243     catch (final NoSuchMethodException e)
244     {
245       throw new PropertyMethodNotFoundException("Method :'" + methodName
246                                                 + "' not found in interface: "
247                                                 + class1.getCanonicalName(), e);
248     }
249   }
250 
251   private static <T extends Annotation> T fetchAnnotation(
252       final Class<T> annotationClass, final Method m)
253   {
254     final T annotation = m.getAnnotation(annotationClass);
255     return annotation;
256   }
257 
258   // --- object basics --------------------------------------------------------
259 
260 }