1 package org.springframework.roo.model; 2 3 import java.util.regex.Matcher; 4 import java.util.regex.Pattern; 5 6 import org.springframework.roo.support.util.Assert; 7 import org.springframework.roo.support.util.StringUtils; 8 9 /** 10 * Immutable representation of a Java field name, method name, or other common legal Java identifier. 11 * 12 * <p> 13 * Ensures the field is properly formed. 14 * 15 * @author Ben Alex 16 * @since 1.0 17 * 18 */ 19 public final class JavaSymbolName implements Comparable<JavaSymbolName> { 20 private String symbolName; 21 22 /** 23 * Construct a Java symbol name. 24 * 25 * <p> 26 * The name will be enforced as follows: 27 * 28 * <ul> 29 * <li>The rules listed in {link {@link JavaTypeUtils#assertJavaNameLegal(String)}} 30 * </ul> 31 * 32 * @param symbolName the name (mandatory) 33 */ 34 public JavaSymbolName(String symbolName) { 35 Assert.hasText(symbolName, "Fully qualified type name required"); 36 assertJavaNameLegal(symbolName); 37 this.symbolName = symbolName; 38 } 39 40 /** 41 * @return the symbol name (never null or empty) 42 */ 43 public String getSymbolName() { 44 return symbolName; 45 } 46 47 /** 48 * @return the symbol name, capitalising the first letter (never null or empty) 49 */ 50 public String getSymbolNameCapitalisedFirstLetter() { 51 return StringUtils.capitalize(symbolName); 52 } 53 54 /** 55 * 56 * @return the symbol name in human readable form 57 */ 58 public String getReadableSymbolName() { 59 Pattern p = Pattern.compile("[A-Z][^A-Z]*"); 60 Matcher m = p.matcher(StringUtils.capitalize(symbolName)); 61 StringBuilder string = new StringBuilder(); 62 while (m.find()) { 63 string.append(m.group()).append(" "); 64 } 65 return string.toString().trim(); 66 } 67 68 public final int hashCode() { 69 return this.symbolName.hashCode(); 70 } 71 72 public final boolean equals(Object obj) { 73 // NB: Not using the normal convention of delegating to compareTo (for efficiency reasons) 74 return obj != null && obj instanceof JavaSymbolName && this.symbolName.equals(((JavaSymbolName) obj).symbolName); 75 } 76 77 public final int compareTo(JavaSymbolName o) { 78 // NB: If adding more fields to this class ensure the equals(Object) method is updated accordingly 79 if (o == null) return -1; 80 return this.symbolName.compareTo(o.symbolName); 81 } 82 83 public final String toString() { 84 return symbolName; 85 } 86 87 /** 88 * Verifies the presented name is a valid Java name. Specifically, the following is enforced: 89 * 90 * <ul> 91 * <li>Textual content must be provided in the name</li> 92 * <li>Must not have any slashes in the name</li> 93 * <li>Must not start with a number</li> 94 * <li>Must not have any spaces or other illegal characters in the name</li> 95 * <li>Must not start or end with a period</li> 96 * </ul> 97 * 98 * @param name to evaluate (required) 99 */ 100 public static final void assertJavaNameLegal(String name) { 101 if (name == null) { 102 throw new IllegalArgumentException("Name required"); 103 } 104 // Note regular expression for legal characters found to be x5 slower in profiling than this approach 105 char[] value = name.toCharArray(); 106 for (int i = 0; i < value.length; i++) { 107 char c = value[i]; 108 if ('/' == c || ' ' == c || '*' == c || '>' == c || '<' == c || '!' == c || '@' == c || '%' == c || '^' == c || 109 '?' == c || '(' == c || ')' == c || '~' == c || '`' == c || '{' == c || '}' == c || '[' == c || ']' == c || 110 '|' == c || '\\' == c || '\'' == c || '+' == c) { 111 throw new IllegalArgumentException("Illegal name '" + name + "' (illegal character)"); 112 } 113 if (i == 0) { 114 if ('1' == c || '2' == c || '3' == c || '4' == c || '5' == c || '6' == c || '7' == c || '8' == c || '9' == c || '0' == c) { 115 throw new IllegalArgumentException("Illegal name '" + name + "' (cannot start with a number)"); 116 } 117 } 118 if (i+1 == value.length || i == 0) { 119 if ('.' == c) { 120 throw new IllegalArgumentException("Illegal name '" + name + "' (cannot start or end with a period)"); 121 } 122 } 123 } 124 /* 125 Assert.notNull(name, "Name required"); 126 Assert.isTrue(!name.contains("/"), "Slashes are prohibited in the name"); 127 Assert.isTrue(!name.contains(" "), "Spaces are prohibited in the name"); 128 Assert.isTrue(!name.contains("*"), "Illegal name"); 129 Assert.isTrue(!name.contains(">"), "Illegal name"); 130 Assert.isTrue(!name.contains("<"), "Illegal name"); 131 Assert.isTrue(!name.contains("!"), "Illegal name"); 132 Assert.isTrue(!name.contains("@"), "Illegal name"); 133 Assert.isTrue(!name.contains("%"), "Illegal name"); 134 Assert.isTrue(!name.contains("^"), "Illegal name"); 135 Assert.isTrue(!name.contains("?"), "Illegal name"); 136 Assert.isTrue(!name.contains("("), "Illegal name"); 137 Assert.isTrue(!name.contains(")"), "Illegal name"); 138 Assert.isTrue(!name.contains("~"), "Illegal name"); 139 Assert.isTrue(!name.contains("`"), "Illegal name"); 140 Assert.isTrue(!name.contains("{"), "Illegal name"); 141 Assert.isTrue(!name.contains("}"), "Illegal name"); 142 Assert.isTrue(!name.contains("["), "Illegal name"); 143 Assert.isTrue(!name.contains("]"), "Illegal name"); 144 Assert.isTrue(!name.contains("|"), "Illegal name"); 145 Assert.isTrue(!name.contains("\""), "Illegal name"); 146 Assert.isTrue(!name.contains("'"), "Illegal name"); 147 Assert.isTrue(!name.contains("+"), "Illegal name"); 148 Assert.isTrue(!name.startsWith("1"), "Illegal name"); 149 Assert.isTrue(!name.startsWith("2"), "Illegal name"); 150 Assert.isTrue(!name.startsWith("3"), "Illegal name"); 151 Assert.isTrue(!name.startsWith("4"), "Illegal name"); 152 Assert.isTrue(!name.startsWith("5"), "Illegal name"); 153 Assert.isTrue(!name.startsWith("6"), "Illegal name"); 154 Assert.isTrue(!name.startsWith("7"), "Illegal name"); 155 Assert.isTrue(!name.startsWith("8"), "Illegal name"); 156 Assert.isTrue(!name.startsWith("9"), "Illegal name"); 157 Assert.isTrue(!name.startsWith("0"), "Illegal name"); 158 Assert.isTrue(!name.startsWith("."), "The name cannot begin with a period"); 159 Assert.isTrue(!name.endsWith("."), "The name cannot end with a period"); 160 */ 161 } 162 }