GriffonNameUtils.java
001 /* 
002  * Copyright 2008-2012 the original author or authors.
003  *
004  * Licensed under the Apache License, Version 2.0 (the "License");
005  * you may not use this file except in compliance with the License.
006  * You may obtain a copy of the License at
007  *
008  *      http://www.apache.org/licenses/LICENSE-2.0
009  *
010  * Unless required by applicable law or agreed to in writing, software
011  * distributed under the License is distributed on an "AS IS" BASIS,
012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013  * See the License for the specific language governing permissions and
014  * limitations under the License.
015  */
016 package griffon.util;
017 
018 import java.util.ArrayList;
019 import java.util.Iterator;
020 import java.util.List;
021 import java.util.Locale;
022 
023 /**
024  * Contains utility methods for converting between different name types,
025  * for example from class names -> property names and vice-versa. The
026  * key aspect of this class is that it has no dependencies outside the
027  * JDK!
028  */
029 public class GriffonNameUtils {
030     private static final String PROPERTY_SET_PREFIX = "set";
031 
032     /**
033      * Capitalizes a String (makes the first char uppercase) taking care
034      * of blank strings and single character strings.
035      *
036      @param str The String to be capitalized
037      @return Capitalized version of the target string if it is not blank
038      */
039     public static String capitalize(String str) {
040         if (isBlank(str)) return str;
041         if (str.length() == 1return str.toUpperCase();
042         return str.substring(01).toUpperCase(Locale.ENGLISH+ str.substring(1);
043     }
044 
045     /**
046      * Uncapitalizes a String (makes the first char lowercase) taking care
047      * of blank strings and single character strings.
048      *
049      @param str The String to be uncapitalized
050      @return Uncapitalized version of the target string if it is not blank
051      */
052     public static String uncapitalize(String str) {
053         if (isBlank(str)) return str;
054         if (str.length() == 1return String.valueOf(Character.toLowerCase(str.charAt(0)));
055         return Character.toLowerCase(str.charAt(0)) + str.substring(1);
056     }
057 
058     /**
059      * Retrieves the name of a setter for the specified property name
060      *
061      @param propertyName The property name
062      @return The setter equivalent
063      */
064     public static String getSetterName(String propertyName) {
065         return PROPERTY_SET_PREFIX + capitalize(propertyName);
066     }
067 
068     /**
069      * Calculate the name for a getter method to retrieve the specified property
070      *
071      @param propertyName
072      @return The name for the getter method for this property, if it were to exist, i.e. getConstraints
073      */
074     public static String getGetterName(String propertyName) {
075         return "get" + capitalize(propertyName);
076     }
077 
078     /**
079      * Returns the class name for the given logical name and trailing name. For example "person" and "Controller" would evaluate to "PersonController"
080      *
081      @param logicalName  The logical name
082      @param trailingName The trailing name
083      @return The class name
084      */
085     public static String getClassName(String logicalName, String trailingName) {
086         if (isBlank(logicalName)) {
087             throw new IllegalArgumentException("Argument [logicalName] cannot be null or blank");
088         }
089 
090         String className = capitalize(logicalName);
091         if (trailingName != null) {
092             className = className + trailingName;
093         }
094         return className;
095     }
096 
097     /**
098      * Returns the class name representation of the given name
099      *
100      @param name The name to convert
101      @return The property name representation
102      */
103     public static String getClassNameRepresentation(String name) {
104         StringBuilder buf = new StringBuilder();
105         if (name != null && name.length() 0) {
106             String[] tokens = name.split("[^\\w\\d]");
107             for (String token1 : tokens) {
108                 String token = token1.trim();
109                 buf.append(capitalize(token));
110             }
111         }
112 
113         return buf.toString();
114     }
115 
116     /**
117      * Converts foo-bar into FooBar. Empty and null strings are returned
118      * as-is.
119      *
120      @param name The lower case hyphen separated name
121      @return The class name equivalent.
122      */
123     public static String getClassNameForLowerCaseHyphenSeparatedName(String name) {
124         // Handle null and empty strings.
125         if (isBlank(name)) return name;
126 
127         if (name.indexOf('-'> -1) {
128             StringBuilder buf = new StringBuilder();
129             String[] tokens = name.split("-");
130             for (String token : tokens) {
131                 if (token == null || token.length() == 0continue;
132                 buf.append(capitalize(token));
133             }
134             return buf.toString();
135         }
136 
137         return capitalize(name);
138     }
139 
140     /**
141      * Retrieves the logical class name of a Griffon artifact given the Griffon class
142      * and a specified trailing name
143      *
144      @param clazz        The class
145      @param trailingName The trailing name such as "Controller" or "TagLib"
146      @return The logical class name
147      */
148     public static String getLogicalName(Class<?> clazz, String trailingName) {
149         return getLogicalName(clazz.getName(), trailingName);
150     }
151 
152     /**
153      * Retrieves the logical name of the class without the trailing name
154      *
155      @param name         The name of the class
156      @param trailingName The trailing name
157      @return The logical name
158      */
159     public static String getLogicalName(String name, String trailingName) {
160         if (!isBlank(trailingName)) {
161             String shortName = getShortName(name);
162             if (shortName.indexOf(trailingName> -1) {
163                 return shortName.substring(0, shortName.length() - trailingName.length());
164             }
165         }
166         return name;
167     }
168 
169     public static String getLogicalPropertyName(String className, String trailingName) {
170         if (!isBlank(className&& !isBlank(trailingName)) {
171             if (className.length() == trailingName.length() && className.endsWith(trailingName)) {
172                 return className.substring(01).toLowerCase();
173             }
174         }
175         return getLogicalName(getPropertyName(className), trailingName);
176     }
177 
178     /**
179      * Shorter version of getPropertyNameRepresentation
180      *
181      @param name The name to convert
182      @return The property name version
183      */
184     public static String getPropertyName(String name) {
185         return getPropertyNameRepresentation(name);
186     }
187 
188     /**
189      * Shorter version of getPropertyNameRepresentation
190      *
191      @param clazz The clazz to convert
192      @return The property name version
193      */
194     public static String getPropertyName(Class<?> clazz) {
195         return getPropertyNameRepresentation(clazz);
196     }
197 
198     /**
199      * Returns the property name equivalent for the specified class
200      *
201      @param targetClass The class to get the property name for
202      @return A property name reperesentation of the class name (eg. MyClass becomes myClass)
203      */
204     public static String getPropertyNameRepresentation(Class<?> targetClass) {
205         String shortName = getShortName(targetClass);
206         return getPropertyNameRepresentation(shortName);
207     }
208 
209     /**
210      * Returns the property name representation of the given name
211      *
212      @param name The name to convert
213      @return The property name representation
214      */
215     public static String getPropertyNameRepresentation(String name) {
216         // Strip any package from the name.
217         int pos = name.lastIndexOf('.');
218         if (pos != -1) {
219             name = name.substring(pos + 1);
220         }
221 
222         // Check whether the name begins with two upper case letters.
223         if (name.length() && Character.isUpperCase(name.charAt(0)) && Character.isUpperCase(name.charAt(1))) {
224             return name;
225         }
226 
227         String propertyName = name.substring(01).toLowerCase(Locale.ENGLISH+ name.substring(1);
228         if (propertyName.indexOf(' '> -1) {
229             propertyName = propertyName.replaceAll("\\s""");
230         }
231         return propertyName;
232     }
233 
234     /**
235      * Converts foo-bar into fooBar
236      *
237      @param name The lower case hyphen separated name
238      @return The property name equivalent
239      */
240     public static String getPropertyNameForLowerCaseHyphenSeparatedName(String name) {
241         return getPropertyName(getClassNameForLowerCaseHyphenSeparatedName(name));
242     }
243 
244     /**
245      * Returns the class name without the package prefix
246      *
247      @param targetClass The class to get a short name for
248      @return The short name of the class
249      */
250     public static String getShortName(Class<?> targetClass) {
251         String className = targetClass.getName();
252         return getShortName(className);
253     }
254 
255     /**
256      * Returns the class name without the package prefix
257      *
258      @param className The class name to get a short name for
259      @return The short name of the class
260      */
261     public static String getShortName(String className) {
262         int i = className.lastIndexOf(".");
263         if (i > -1) {
264             className = className.substring(i + 1, className.length());
265         }
266         return className;
267     }
268 
269     /**
270      * Converts a property name into its natural language equivalent eg ('firstName' becomes 'First Name')
271      *
272      @param name The property name to convert
273      @return The converted property name
274      */
275     public static String getNaturalName(String name) {
276         name = getShortName(name);
277         List<String> words = new ArrayList<String>();
278         int i = 0;
279         char[] chars = name.toCharArray();
280         for (int j = 0; j < chars.length; j++) {
281             char c = chars[j];
282             String w;
283             if (i >= words.size()) {
284                 w = "";
285                 words.add(i, w);
286             else {
287                 w = words.get(i);
288             }
289 
290             if (Character.isLowerCase(c|| Character.isDigit(c)) {
291                 if (Character.isLowerCase(c&& w.length() == 0) {
292                     c = Character.toUpperCase(c);
293                 else if (w.length() && Character.isUpperCase(w.charAt(w.length() 1))) {
294                     w = "";
295                     words.add(++i, w);
296                 }
297 
298                 words.set(i, w + c);
299             else if (Character.isUpperCase(c)) {
300                 if ((i == && w.length() == 0|| Character.isUpperCase(w.charAt(w.length() 1))) {
301                     words.set(i, w + c);
302                 else {
303                     words.add(++i, String.valueOf(c));
304                 }
305             }
306         }
307 
308         StringBuilder buf = new StringBuilder();
309         for (Iterator<String> j = words.iterator(); j.hasNext()) {
310             String word = j.next();
311             buf.append(word);
312             if (j.hasNext()) {
313                 buf.append(' ');
314             }
315         }
316         return buf.toString();
317     }
318 
319     /**
320      <p>Determines whether a given string is <code>null</code>, empty,
321      * or only contains whitespace. If it contains anything other than
322      * whitespace then the string is not considered to be blank and the
323      * method returns <code>false</code>.</p>
324      <p>We could use Commons Lang for this, but we don't want GriffonNameUtils
325      * to have a dependency on any external library to minimise the number of
326      * dependencies required to bootstrap Griffon.</p>
327      *
328      @param str The string to test.
329      @return <code>true</code> if the string is <code>null</code>, or
330      *         blank.
331      */
332     public static boolean isBlank(String str) {
333         return str == null || str.trim().length() == 0;
334     }
335 
336     /**
337      * Retrieves the hyphenated name representation of the supplied class. For example
338      * MyFunkyGriffonThingy would be my-funky-griffon-thingy.
339      *
340      @param clazz The class to convert
341      @return The hyphenated name representation
342      */
343     public static String getHyphenatedName(Class clazz) {
344         if (clazz == null) {
345             return null;
346         }
347         return getHyphenatedName(clazz.getName());
348     }
349 
350     /**
351      * Retrieves the hyphenated name representation of the given class name.
352      * For example MyFunkyGriffonThingy would be my-funky-griffon-thingy.
353      *
354      @param name The class name to convert.
355      @return The hyphenated name representation.
356      */
357     public static String getHyphenatedName(String name) {
358         if (name == null) {
359             return null;
360         }
361         if (name.endsWith(".groovy")) {
362             name = name.substring(0, name.length() 7);
363         }
364         String naturalName = getNaturalName(getShortName(name));
365         return naturalName.replaceAll("\\s""-").toLowerCase();
366     }
367 }