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() == 1) return str.toUpperCase();
042 return str.substring(0, 1).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() == 1) return 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() == 0) continue;
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() + 1 && className.endsWith(trailingName)) {
172 return className.substring(0, 1).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() > 1 && Character.isUpperCase(name.charAt(0)) && Character.isUpperCase(name.charAt(1))) {
224 return name;
225 }
226
227 String propertyName = name.substring(0, 1).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() > 1 && 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 == 0 && 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 }
|