@@ -1016,11 +1016,12 @@ public static String getSetterName(String propertyName) {
10161016 }
10171017
10181018 /**
1019- * Returns true if the name of the method specified and the number of arguments make it a javabean property
1019+ * Returns true if the name of the method specified and the number of arguments make it a javabean property getter.
1020+ * The name is assumed to be a valid Java method name, that is not verified.
10201021 *
1021- * @param name True if its a Javabean property
1022+ * @param name The name of the method
10221023 * @param args The arguments
1023- * @return true if it is a javabean property method
1024+ * @return true if it is a javabean property getter
10241025 */
10251026 public static boolean isGetter (String name , Class <?>[] args ) {
10261027 if (!StringUtils .hasText (name ) || args == null )return false ;
@@ -1049,90 +1050,121 @@ else if (name.startsWith("is")) {
10491050 * <li>Word</li>
10501051 * <li>aProperty</li>
10511052 * <li>S</li>
1053+ * <li>X567</li>
10521054 * </ul>
10531055 *
1054- * Example sof suffixes that would not be considered property getters:
1056+ * Examples of suffixes that would not be considered property getters:
10551057 * <ul>
10561058 * <li>someProperty</li>
10571059 * <li>word</li>
10581060 * <li>s</li>
1061+ * <li>x567</li>
1062+ * <li>2other</li>
1063+ * <li>5</li>
10591064 * </ul>
1065+ *
1066+ * A suffix like <code>prop</code> from a method <code>getprop()</code> is
1067+ * not recognized as a valid suffix. However Groovy will recognize such a
1068+ * method as a property getter but only if a method <code>getProp()</code> or
1069+ * a property <code>prop</code> does not also exist. The Java Beans
1070+ * specification is unclear on how to treat such method names, it only says
1071+ * that "by default" the suffix will start with a capital letter because of
1072+ * the camel case style usually used. (See the JavaBeans API specification
1073+ * sections 8.3 and 8.8.)
1074+ *
1075+ * This method assumes that all characters in the name are valid Java identifier
1076+ * letters.
1077+ *
10601078 * @param suffix The suffix to inspect
10611079 * @return true if suffix indicates a property name
10621080 */
10631081 protected static boolean isPropertyMethodSuffix (String suffix ) {
1064- if (suffix .length () > 0 ) {
1065- if (suffix .length () == 1 ) {
1066- if (Character .isUpperCase (suffix .charAt (0 ))) {
1067- return true ;
1068- }
1069- } else {
1070- if (Character .isUpperCase (suffix .charAt (0 )) ||
1071- (Character .isUpperCase (suffix .charAt (1 )) && Character .isLowerCase (suffix .charAt (0 )))) {
1072- return true ;
1073- }
1074- }
1075- }
1076- return false ;
1082+ if (suffix .length () == 0 ) return false ;
1083+ if (!Character .isJavaIdentifierStart (suffix .charAt (0 ))) return false ;
1084+ if (suffix .length () == 1 ) return Character .isUpperCase (suffix .charAt (0 ));
1085+ return Character .isUpperCase (suffix .charAt (0 )) || Character .isUpperCase (suffix .charAt (1 ));
10771086 }
10781087
10791088 /**
1080- * Returns a property name equivalent for the given getter name or null if it is not a getter
1089+ * Returns a property name equivalent for the given getter name or null if it is not a valid getter. If not null
1090+ * or empty the getter name is assumed to be a valid identifier.
10811091 *
10821092 * @param getterName The getter name
10831093 * @return The property name equivalent
10841094 */
10851095 public static String getPropertyForGetter (String getterName ) {
1086- if (! StringUtils . hasText ( getterName )) return null ;
1096+ if (getterName == null || getterName . length () == 0 ) return null ;
10871097
10881098 if (getterName .startsWith ("get" )) {
10891099 String prop = getterName .substring (3 );
1090- return convertPropertyName (prop );
1100+ return convertValidPropertyMethodSuffix (prop );
10911101 }
10921102 if (getterName .startsWith ("is" )) {
10931103 String prop = getterName .substring (2 );
1094- return convertPropertyName (prop );
1104+ return convertValidPropertyMethodSuffix (prop );
10951105 }
10961106 return null ;
10971107 }
10981108
1099- private static String convertPropertyName (String prop ) {
1100- if (prop .length () == 1 ) {
1101- return prop .toLowerCase ();
1109+ /**
1110+ * This method functions the same as {@link #isPropertyMethodSuffix(String)},
1111+ * but in addition returns the property name, or null if not a valid property.
1112+ *
1113+ * @param suffix The suffix to inspect
1114+ * @return The property name or null
1115+ */
1116+ private static String convertValidPropertyMethodSuffix (String suffix ) {
1117+ if (suffix .length () == 0 ) return null ;
1118+
1119+ // We assume all characters are Character.isJavaIdentifierPart, but the first one may not be a valid
1120+ // starting character.
1121+ if (!Character .isJavaIdentifierStart (suffix .charAt (0 ))) return null ;
1122+
1123+ if (suffix .length () == 1 ) {
1124+ return Character .isUpperCase (suffix .charAt (0 )) ? suffix .toLowerCase () : null ;
11021125 }
1103- if (Character .isUpperCase (prop .charAt (0 )) && Character .isUpperCase (prop .charAt (1 ))) {
1104- return prop ;
1126+ if (Character .isUpperCase (suffix .charAt (1 ))) {
1127+ // "aProperty", "AProperty"
1128+ return suffix ;
11051129 }
1106- if (Character .isDigit ( prop .charAt (0 ))) {
1107- return prop ;
1130+ if (Character .isUpperCase ( suffix .charAt (0 ))) {
1131+ return Character . toLowerCase ( suffix . charAt ( 0 )) + suffix . substring ( 1 ) ;
11081132 }
1109- return Character . toLowerCase ( prop . charAt ( 0 )) + prop . substring ( 1 ) ;
1133+ return null ;
11101134 }
11111135
11121136 /**
1113- * Returns a property name equivalent for the given setter name or null if it is not a getter
1137+ * Returns a property name equivalent for the given setter name or null if it is not a valid setter. If not null
1138+ * or empty the setter name is assumed to be a valid identifier.
11141139 *
1115- * @param setterName The setter name
1140+ * @param setterName The setter name, must be null or empty or a valid identifier name
11161141 * @return The property name equivalent
11171142 */
11181143 public static String getPropertyForSetter (String setterName ) {
1119- if (! StringUtils . hasText ( setterName )) return null ;
1144+ if (setterName == null || setterName . length () == 0 ) return null ;
11201145
11211146 if (setterName .startsWith ("set" )) {
11221147 String prop = setterName .substring (3 );
1123- return convertPropertyName (prop );
1148+ return convertValidPropertyMethodSuffix (prop );
11241149 }
11251150 return null ;
11261151 }
11271152
1153+ /**
1154+ * Returns true if the name of the method specified and the number of arguments make it a javabean property setter.
1155+ * The name is assumed to be a valid Java method name, that is not verified.
1156+ *
1157+ * @param name The name of the method
1158+ * @param args The arguments
1159+ * @return true if it is a javabean property setter
1160+ */
11281161 @ SuppressWarnings ("rawtypes" )
11291162 public static boolean isSetter (String name , Class [] args ) {
11301163 if (!StringUtils .hasText (name ) || args == null )return false ;
11311164
11321165 if (name .startsWith ("set" )) {
11331166 if (args .length != 1 ) return false ;
1134- name = name .substring (3 );
1135- if (name .length () > 0 && Character .isUpperCase (name .charAt (0 ))) return true ;
1167+ return isPropertyMethodSuffix (name .substring (3 ));
11361168 }
11371169
11381170 return false ;
0 commit comments