`GriffonClassUtils.java`
`0001 /* 0002 * Copyright 2004-2012 the original author or authors. 0003 * 0004 * Licensed under the Apache License, Version 2.0 (the "License"); 0005 * you may not use this file except in compliance with the License. 0006 * You may obtain a copy of the License at 0007 * 0008 * http://www.apache.org/licenses/LICENSE-2.0 0009 * 0010 * Unless required by applicable law or agreed to in writing, software 0011 * distributed under the License is distributed on an "AS IS" BASIS, 0012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 0013 * See the License for the specific language governing permissions and 0014 * limitations under the License. 0015 */ 0016 package griffon.util; 0017 0018 import griffon.core.MVCClosure; 0019 import griffon.exceptions.BeanException; 0020 import griffon.exceptions.BeanInstantiationException; 0021 import groovy.lang.*; 0022 import groovy.util.FactoryBuilderSupport; 0023 import org.codehaus.groovy.reflection.CachedClass; 0024 0025 import java.beans.*; 0026 import java.lang.reflect.Field; 0027 import java.lang.reflect.InvocationTargetException; 0028 import java.lang.reflect.Method; 0029 import java.lang.reflect.Modifier; 0030 import java.util.*; 0031 import java.util.concurrent.Callable; 0032 import java.util.concurrent.ExecutorService; 0033 import java.util.regex.Pattern; 0034 0035 import static griffon.util.MethodUtils.invokeExactMethod; 0036 import static griffon.util.MethodUtils.invokeMethod; 0037 0038 /** 0039 * Class containing utility methods for dealing with Griffon class artifacts.<p> 0040 * Contains utility methods copied from commons-lang and commons-beanutils in order 0041 * to reduce dependencies on external libraries.<p> 0042 * <p/> 0043 * <b>Contains code copied from commons-beanutils and commons-langs</b> 0044 * 0045 * @author Graeme Rocher (Grails 0.1) 0046 */ 0047 public final class GriffonClassUtils { 0048 public static final Class[] EMPTY_CLASS_ARRAY = new Class[0]; 0049 public static final Object[] EMPTY_OBJECT_ARRAY = new Object[0]; 0050 public static final Class[] EMPTY_TYPES = EMPTY_CLASS_ARRAY; 0051 public static final Object[] EMPTY_ARGS = EMPTY_OBJECT_ARRAY; 0052 0053 private static final String PROPERTY_GET_PREFIX = "get"; 0054 private static final String PROPERTY_IS_PREFIX = "is"; 0055 private static final String PROPERTY_SET_PREFIX = "set"; 0056 public static final Map<Class, Class> PRIMITIVE_TYPE_COMPATIBLE_CLASSES = new HashMap<Class, Class>(); 0057 0058 private static final Pattern EVENT_HANDLER_PATTERN = Pattern.compile("^on[A-Z][\\w]*$"); 0059 private static final Pattern GETTER_PATTERN_1 = Pattern.compile("^get[A-Z][\\w]*$"); 0060 private static final Pattern GETTER_PATTERN_2 = Pattern.compile("^is[A-Z][\\w]*$"); 0061 private static final Pattern SETTER_PATTERN = Pattern.compile("^set[A-Z][\\w]*$"); 0062 private static final Set<MethodDescriptor> BASIC_METHODS = new TreeSet<MethodDescriptor>(); 0063 private static final Set<MethodDescriptor> MVC_METHODS = new TreeSet<MethodDescriptor>(); 0064 private static final Set<MethodDescriptor> THREADING_METHODS = new TreeSet<MethodDescriptor>(); 0065 private static final Set<MethodDescriptor> EVENT_PUBLISHER_METHODS = new TreeSet<MethodDescriptor>(); 0066 private static final Set<MethodDescriptor> OBSERVABLE_METHODS = new TreeSet<MethodDescriptor>(); 0067 0068 /** 0069 * Just add two entries to the class compatibility map 0070 * 0071 * @param left 0072 * @param right 0073 */ 0074 private static void registerPrimitiveClassPair(Class<?> left, Class<?> right) { 0075 PRIMITIVE_TYPE_COMPATIBLE_CLASSES.put(left, right); 0076 PRIMITIVE_TYPE_COMPATIBLE_CLASSES.put(right, left); 0077 } 0078 0079 static { 0080 registerPrimitiveClassPair(Boolean.class, boolean.class); 0081 registerPrimitiveClassPair(Integer.class, int.class); 0082 registerPrimitiveClassPair(Short.class, short.class); 0083 registerPrimitiveClassPair(Byte.class, byte.class); 0084 registerPrimitiveClassPair(Character.class, char.class); 0085 registerPrimitiveClassPair(Long.class, long.class); 0086 registerPrimitiveClassPair(Float.class, float.class); 0087 registerPrimitiveClassPair(Double.class, double.class); 0088 0089 for (Method method : GroovyObject.class.getMethods()) { 0090 MethodDescriptor md = MethodDescriptor.forMethod(method); 0091 if (!BASIC_METHODS.contains(md)) { 0092 BASIC_METHODS.add(md); 0093 } 0094 } 0095 for (Method method : GroovyObjectSupport.class.getMethods()) { 0096 MethodDescriptor md = MethodDescriptor.forMethod(method); 0097 if (!BASIC_METHODS.contains(md)) { 0098 BASIC_METHODS.add(md); 0099 } 0100 } 0101 for (Method method : Object.class.getMethods()) { 0102 MethodDescriptor md = MethodDescriptor.forMethod(method); 0103 if (!BASIC_METHODS.contains(md)) { 0104 BASIC_METHODS.add(md); 0105 } 0106 } 0107 0108 MVC_METHODS.add(new MethodDescriptor("mvcGroupInit", new Class[]{Map.class})); 0109 MVC_METHODS.add(new MethodDescriptor("mvcGroupDestroy")); 0110 MVC_METHODS.add(new MethodDescriptor("newInstance", new Class[]{Class.class, String.class})); 0111 MVC_METHODS.add(new MethodDescriptor("buildMVCGroup", new Class[]{String.class})); 0112 MVC_METHODS.add(new MethodDescriptor("buildMVCGroup", new Class[]{String.class, Map.class})); 0113 MVC_METHODS.add(new MethodDescriptor("buildMVCGroup", new Class[]{Map.class, String.class})); 0114 MVC_METHODS.add(new MethodDescriptor("buildMVCGroup", new Class[]{String.class, String.class})); 0115 MVC_METHODS.add(new MethodDescriptor("buildMVCGroup", new Class[]{String.class, String.class, Map.class})); 0116 MVC_METHODS.add(new MethodDescriptor("buildMVCGroup", new Class[]{Map.class, String.class, String.class})); 0117 MVC_METHODS.add(new MethodDescriptor("createMVCGroup", new Class[]{String.class})); 0118 MVC_METHODS.add(new MethodDescriptor("createMVCGroup", new Class[]{String.class, Map.class})); 0119 MVC_METHODS.add(new MethodDescriptor("createMVCGroup", new Class[]{Map.class, String.class})); 0120 MVC_METHODS.add(new MethodDescriptor("createMVCGroup", new Class[]{String.class, String.class})); 0121 MVC_METHODS.add(new MethodDescriptor("createMVCGroup", new Class[]{String.class, String.class, Map.class})); 0122 MVC_METHODS.add(new MethodDescriptor("createMVCGroup", new Class[]{Map.class, String.class, String.class})); 0123 MVC_METHODS.add(new MethodDescriptor("destroyMVCGroup", new Class[]{String.class})); 0124 MVC_METHODS.add(new MethodDescriptor("withMVCGroup", new Class[]{String.class, Closure.class})); 0125 MVC_METHODS.add(new MethodDescriptor("withMVCGroup", new Class[]{String.class, Map.class, Closure.class})); 0126 MVC_METHODS.add(new MethodDescriptor("withMVCGroup", new Class[]{Map.class, String.class, Closure.class})); 0127 MVC_METHODS.add(new MethodDescriptor("withMVCGroup", new Class[]{String.class, String.class, Closure.class})); 0128 MVC_METHODS.add(new MethodDescriptor("withMVCGroup", new Class[]{String.class, String.class, Map.class, Closure.class})); 0129 MVC_METHODS.add(new MethodDescriptor("withMVCGroup", new Class[]{Map.class, String.class, String.class, Closure.class})); 0130 MVC_METHODS.add(new MethodDescriptor("withMVCGroup", new Class[]{String.class, MVCClosure.class})); 0131 MVC_METHODS.add(new MethodDescriptor("withMVCGroup", new Class[]{String.class, Map.class, MVCClosure.class})); 0132 MVC_METHODS.add(new MethodDescriptor("withMVCGroup", new Class[]{Map.class, String.class, MVCClosure.class})); 0133 MVC_METHODS.add(new MethodDescriptor("withMVCGroup", new Class[]{String.class, String.class, MVCClosure.class})); 0134 MVC_METHODS.add(new MethodDescriptor("withMVCGroup", new Class[]{String.class, String.class, Map.class, MVCClosure.class})); 0135 MVC_METHODS.add(new MethodDescriptor("withMVCGroup", new Class[]{Map.class, String.class, String.class, MVCClosure.class})); 0136 0137 // Special cases due to the usage of varargs 0138 MVC_METHODS.add(new MethodDescriptor("newInstance", new Class[]{Object[].class})); 0139 MVC_METHODS.add(new MethodDescriptor("buildMVCGroup", new Class[]{Object[].class})); 0140 MVC_METHODS.add(new MethodDescriptor("createMVCGroup", new Class[]{Object[].class})); 0141 MVC_METHODS.add(new MethodDescriptor("withMVCGroup", new Class[]{Object[].class})); 0142 0143 MVC_METHODS.add(new MethodDescriptor("getApp")); 0144 MVC_METHODS.add(new MethodDescriptor("getLog")); 0145 MVC_METHODS.add(new MethodDescriptor("getArtifactManager")); 0146 MVC_METHODS.add(new MethodDescriptor("getGriffonClass")); 0147 MVC_METHODS.add(new MethodDescriptor("setBuilder", new Class[]{FactoryBuilderSupport.class})); 0148 0149 THREADING_METHODS.add(new MethodDescriptor("isUIThread")); 0150 THREADING_METHODS.add(new MethodDescriptor("execAsync", new Class[]{Runnable.class})); 0151 THREADING_METHODS.add(new MethodDescriptor("execAsync", new Class[]{Script.class})); 0152 THREADING_METHODS.add(new MethodDescriptor("execSync", new Class[]{Runnable.class})); 0153 THREADING_METHODS.add(new MethodDescriptor("execSync", new Class[]{Script.class})); 0154 THREADING_METHODS.add(new MethodDescriptor("execOutside", new Class[]{Runnable.class})); 0155 THREADING_METHODS.add(new MethodDescriptor("execOutside", new Class[]{Script.class})); 0156 THREADING_METHODS.add(new MethodDescriptor("execFuture", new Class[]{Closure.class})); 0157 THREADING_METHODS.add(new MethodDescriptor("execFuture", new Class[]{Callable.class})); 0158 THREADING_METHODS.add(new MethodDescriptor("execFuture", new Class[]{ExecutorService.class, Closure.class})); 0159 THREADING_METHODS.add(new MethodDescriptor("execFuture", new Class[]{ExecutorService.class, Callable.class})); 0160 THREADING_METHODS.add(new MethodDescriptor("edt", new Class[]{Runnable.class})); 0161 THREADING_METHODS.add(new MethodDescriptor("edt", new Class[]{Closure.class})); 0162 THREADING_METHODS.add(new MethodDescriptor("doLater", new Class[]{Runnable.class})); 0163 THREADING_METHODS.add(new MethodDescriptor("doLater", new Class[]{Closure.class})); 0164 THREADING_METHODS.add(new MethodDescriptor("doOutside", new Class[]{Runnable.class})); 0165 THREADING_METHODS.add(new MethodDescriptor("doOutside", new Class[]{Closure.class})); 0166 // Special case due to the usage of varargs 0167 THREADING_METHODS.add(new MethodDescriptor("execFuture", new Class[]{Object[].class})); 0168 0169 EVENT_PUBLISHER_METHODS.add(new MethodDescriptor("addEventListener", new Class[]{Object.class})); 0170 EVENT_PUBLISHER_METHODS.add(new MethodDescriptor("addEventListener", new Class[]{String.class, Closure.class})); 0171 EVENT_PUBLISHER_METHODS.add(new MethodDescriptor("addEventListener", new Class[]{String.class, RunnableWithArgs.class})); 0172 EVENT_PUBLISHER_METHODS.add(new MethodDescriptor("removeEventListener", new Class[]{Object.class})); 0173 EVENT_PUBLISHER_METHODS.add(new MethodDescriptor("removeEventListener", new Class[]{String.class, Closure.class})); 0174 EVENT_PUBLISHER_METHODS.add(new MethodDescriptor("removeEventListener", new Class[]{String.class, RunnableWithArgs.class})); 0175 EVENT_PUBLISHER_METHODS.add(new MethodDescriptor("publishEvent", new Class[]{String.class})); 0176 EVENT_PUBLISHER_METHODS.add(new MethodDescriptor("publishEvent", new Class[]{String.class, List.class})); 0177 EVENT_PUBLISHER_METHODS.add(new MethodDescriptor("publishEventAsync", new Class[]{String.class})); 0178 EVENT_PUBLISHER_METHODS.add(new MethodDescriptor("publishEventAsync", new Class[]{String.class, List.class})); 0179 EVENT_PUBLISHER_METHODS.add(new MethodDescriptor("publishEventOutside", new Class[]{String.class})); 0180 EVENT_PUBLISHER_METHODS.add(new MethodDescriptor("publishEventOutside", new Class[]{String.class, List.class})); 0181 0182 OBSERVABLE_METHODS.add(new MethodDescriptor("addPropertyChangeListener", new Class[]{PropertyChangeListener.class})); 0183 OBSERVABLE_METHODS.add(new MethodDescriptor("addPropertyChangeListener", new Class[]{String.class, PropertyChangeListener.class})); 0184 OBSERVABLE_METHODS.add(new MethodDescriptor("removePropertyChangeListener", new Class[]{PropertyChangeListener.class})); 0185 OBSERVABLE_METHODS.add(new MethodDescriptor("removePropertyChangeListener", new Class[]{String.class, PropertyChangeListener.class})); 0186 OBSERVABLE_METHODS.add(new MethodDescriptor("getPropertyChangeListeners", new Class[0])); 0187 OBSERVABLE_METHODS.add(new MethodDescriptor("getPropertyChangeListeners", new Class[]{String.class})); 0188 } 0189 0190 /** 0191 * Finds out if the given string represents the name of an 0192 * event handler by matching against the following pattern: 0193 * "^on[A-Z][\\w]*$"<p> 0194 * <p/> 0195 * <pre> 0196 * GriffonClassUtils.isEventHandler("onBootstrapEnd") = true 0197 * GriffonClassUtils.isEventHandler("mvcGroupInit") = false 0198 * GriffonClassUtils.isEventHandler("online") = false 0199 * </pre> 0200 * 0201 * @param name the name of a possible event handler 0202 * @return true if the name matches the given event handler 0203 * pattern, false otherwise. 0204 */ 0205 public static boolean isEventHandler(String name) { 0206 if (GriffonNameUtils.isBlank(name)) return false; 0207 return EVENT_HANDLER_PATTERN.matcher(name).matches(); 0208 } 0209 0210 /** 0211 * Finds out if the given Method represents an event handler 0212 * by matching its name against the following pattern: 0213 * "^on[A-Z][\\w]*$"<p> 0214 * <pre> 0215 * GriffonClassUtils.isEventHandler("onBootstrapEnd") = true 0216 * GriffonClassUtils.isEventHandler("mvcGroupInit") = false 0217 * GriffonClassUtils.isEventHandler("online") = false 0218 * </pre> 0219 * 0220 * @param method a Method reference 0221 * @return true if the method name matches the given event handler 0222 * pattern, false otherwise. 0223 */ 0224 public static boolean isEventHandler(Method method) { 0225 return isEventHandler(MethodDescriptor.forMethod(method)); 0226 } 0227 0228 /** 0229 * Finds out if the given Method represents an event handler 0230 * by matching its name against the following pattern: 0231 * "^on[A-Z][\\w]*$"<p> 0232 * <pre> 0233 * GriffonClassUtils.isEventHandler("onBootstrapEnd") = true 0234 * GriffonClassUtils.isEventHandler("mvcGroupInit") = false 0235 * GriffonClassUtils.isEventHandler("online") = false 0236 * </pre> 0237 * 0238 * @param method a MetaMethod reference 0239 * @return true if the method name matches the given event handler 0240 * pattern, false otherwise. 0241 */ 0242 public static boolean isEventHandler(MetaMethod method) { 0243 return isEventHandler(MethodDescriptor.forMethod(method)); 0244 } 0245 0246 /** 0247 * Finds out if the given Method represents an event handler 0248 * by matching its name against the following pattern: 0249 * "^on[A-Z][\\w]*$"<p> 0250 * <pre> 0251 * GriffonClassUtils.isEventHandler("onBootstrapEnd") = true 0252 * GriffonClassUtils.isEventHandler("mvcGroupInit") = false 0253 * GriffonClassUtils.isEventHandler("online") = false 0254 * </pre> 0255 * 0256 * @param method a MethodDescriptor reference 0257 * @return true if the method name matches the given event handler 0258 * pattern, false otherwise. 0259 */ 0260 public static boolean isEventHandler(MethodDescriptor method) { 0261 if (method == null || method.getModifiers() - Modifier.PUBLIC != 0) return false; 0262 return EVENT_HANDLER_PATTERN.matcher(method.getName()).matches(); 0263 } 0264 0265 /** 0266 * Finds out if the given {@code Method} belongs either to the 0267 * {@code Object} class or the {@code GroovyObject} class.<p> 0268 * 0269 * @param method a Method reference 0270 * @return true if the method belongs to {@code Object} or 0271 * {@code GroovyObject}, false otherwise. 0272 */ 0273 public static boolean isBasicMethod(Method method) { 0274 return isBasicMethod(MethodDescriptor.forMethod(method)); 0275 } 0276 0277 /** 0278 * Finds out if the given {@code MetaMethod} belongs either to the 0279 * {@code Object} class or the {@code GroovyObject} class.<p> 0280 * 0281 * @param method a MetaMethod reference 0282 * @return true if the method belongs to {@code Object} or 0283 * {@code GroovyObject}, false otherwise. 0284 */ 0285 public static boolean isBasicMethod(MetaMethod method) { 0286 return isBasicMethod(MethodDescriptor.forMethod(method)); 0287 } 0288 0289 /** 0290 * Finds out if the given {@code MethodDescriptor} belongs either to the 0291 * {@code Object} class or the {@code GroovyObject} class.<p> 0292 * 0293 * @param method a MethodDescriptor reference 0294 * @return true if the method belongs to {@code Object} or 0295 * {@code GroovyObject}, false otherwise. 0296 */ 0297 public static boolean isBasicMethod(MethodDescriptor method) { 0298 if (method == null || !isInstanceMethod(method)) return false; 0299 return BASIC_METHODS.contains(method); 0300 } 0301 0302 /** 0303 * Finds out if the given {@code Method} was injected by the Groovy 0304 * compiler.<p> 0305 * Performs a basic checks against the method's name, returning true 0306 * if the name starts with either "super$" or "this$". 0307 * 0308 * @param method a Method reference 0309 * @return true if the method matches the given criteria, false otherwise. 0310 */ 0311 public static boolean isGroovyInjectedMethod(Method method) { 0312 return isGroovyInjectedMethod(MethodDescriptor.forMethod(method)); 0313 } 0314 0315 /** 0316 * Finds out if the given {@code MetaMethod} was injected by the Groovy 0317 * compiler.<p> 0318 * Performs a basic checks against the method's name, returning true 0319 * if the name starts with either "super$" or "this$". 0320 * 0321 * @param method a MetaMethod reference 0322 * @return true if the method matches the given criteria, false otherwise. 0323 */ 0324 public static boolean isGroovyInjectedMethod(MetaMethod method) { 0325 return isGroovyInjectedMethod(MethodDescriptor.forMethod(method)); 0326 } 0327 0328 /** 0329 * Finds out if the given {@code MethodDescriptor} was injected by the Groovy 0330 * compiler.<p> 0331 * Performs a basic checks against the method's name, returning true 0332 * if the name starts with either "super$" or "this$". 0333 * 0334 * @param method a MethodDescriptor reference 0335 * @return true if the method matches the given criteria, false otherwise. 0336 */ 0337 public static boolean isGroovyInjectedMethod(MethodDescriptor method) { 0338 if (method == null || !isInstanceMethod(method)) return false; 0339 return method.getName().startsWith("super$") || 0340 method.getName().startsWith("this$"); 0341 } 0342 0343 /** 0344 * Finds out if the given {@code Method} is a getter method. 0345 * <p/> 0346 * <pre> 0347 * // assuming getMethod() returns an appropriate Method reference 0348 * isGetterMethod(getMethod("getFoo")) = true 0349 * isGetterMethod(getMethod("getfoo") ) = false 0350 * isGetterMethod(getMethod("mvcGroupInit")) = false 0351 * isGetterMethod(getMethod("isFoo")) = true 0352 * isGetterMethod(getMethod("island")) = false 0353 * </pre> 0354 * 0355 * @param method a Method reference 0356 * @return true if the method is a getter, false otherwise. 0357 */ 0358 public static boolean isGetterMethod(Method method) { 0359 return isGetterMethod(MethodDescriptor.forMethod(method)); 0360 } 0361 0362 /** 0363 * Finds out if the given {@code MetaMethod} is a getter method. 0364 * <p/> 0365 * <pre> 0366 * // assuming getMethod() returns an appropriate MetaMethod reference 0367 * isGetterMethod(getMethod("getFoo")) = true 0368 * isGetterMethod(getMethod("getfoo") ) = false 0369 * isGetterMethod(getMethod("mvcGroupInit")) = false 0370 * isGetterMethod(getMethod("isFoo")) = true 0371 * isGetterMethod(getMethod("island")) = false 0372 * </pre> 0373 * 0374 * @param method a Method reference 0375 * @return true if the method is a getter, false otherwise. 0376 */ 0377 public static boolean isGetterMethod(MetaMethod method) { 0378 return isGetterMethod(MethodDescriptor.forMethod(method)); 0379 } 0380 0381 /** 0382 * Finds out if the given {@code MetaMethod} is a getter method. 0383 * <p/> 0384 * <pre> 0385 * // assuming getMethod() returns an appropriate MethodDescriptor reference 0386 * isGetterMethod(getMethod("getFoo")) = true 0387 * isGetterMethod(getMethod("getfoo") ) = false 0388 * isGetterMethod(getMethod("mvcGroupInit")) = false 0389 * isGetterMethod(getMethod("isFoo")) = true 0390 * isGetterMethod(getMethod("island")) = false 0391 * </pre> 0392 * 0393 * @param method a MethodDescriptor reference 0394 * @return true if the method is a getter, false otherwise. 0395 */ 0396 public static boolean isGetterMethod(MethodDescriptor method) { 0397 if (method == null || !isInstanceMethod(method)) return false; 0398 return GETTER_PATTERN_1.matcher(method.getName()).matches() || 0399 GETTER_PATTERN_2.matcher(method.getName()).matches(); 0400 } 0401 0402 /** 0403 * Finds out if the given {@code Method} is a setter method. 0404 * <p/> 0405 * <pre> 0406 * // assuming getMethod() returns an appropriate Method reference 0407 * isGetterMethod(getMethod("setFoo")) = true 0408 * isGetterMethod(getMethod("setfoo")) = false 0409 * isGetterMethod(getMethod("mvcGroupInit")) = false 0410 * </pre> 0411 * 0412 * @param method a Method reference 0413 * @return true if the method is a setter, false otherwise. 0414 */ 0415 public static boolean isSetterMethod(Method method) { 0416 return isSetterMethod(MethodDescriptor.forMethod(method)); 0417 } 0418 0419 /** 0420 * Finds out if the given {@code MetaMethod} is a setter method. 0421 * <p/> 0422 * <pre> 0423 * // assuming getMethod() returns an appropriate MetaMethod reference 0424 * isGetterMethod(getMethod("setFoo")) = true 0425 * isGetterMethod(getMethod("setfoo")) = false 0426 * isGetterMethod(getMethod("mvcGroupInit")) = false 0427 * </pre> 0428 * 0429 * @param method a MetaMethod reference 0430 * @return true if the method is a setter, false otherwise. 0431 */ 0432 public static boolean isSetterMethod(MetaMethod method) { 0433 return isSetterMethod(MethodDescriptor.forMethod(method)); 0434 } 0435 0436 /** 0437 * Finds out if the given {@code MethodDescriptor} is a setter method. 0438 * <p/> 0439 * <pre> 0440 * // assuming getMethod() returns an appropriate MethodDescriptor reference 0441 * isGetterMethod(getMethod("setFoo")) = true 0442 * isGetterMethod(getMethod("setfoo")) = false 0443 * isGetterMethod(getMethod("mvcGroupInit")) = false 0444 * </pre> 0445 * 0446 * @param method a MethodDescriptor reference 0447 * @return true if the method is a setter, false otherwise. 0448 */ 0449 public static boolean isSetterMethod(MethodDescriptor method) { 0450 if (method == null || !isInstanceMethod(method)) return false; 0451 return SETTER_PATTERN.matcher(method.getName()).matches(); 0452 } 0453 0454 /** 0455 * Finds out if the given {@code Method} belongs to the set of 0456 * predefined MVC methods by convention. 0457 * <p/> 0458 * <pre> 0459 * // assuming getMethod() returns an appropriate Method reference 0460 * isMvcMethod(getMethod("mvcGroupInit")) = true 0461 * isMvcMethod(getMethod("mvcGroupDestroy")) = true 0462 * isMvcMethod(getMethod("foo")) = false 0463 * </pre> 0464 * 0465 * @param method a Method reference 0466 * @return true if the method is an MVC method, false otherwise. 0467 */ 0468 public static boolean isMvcMethod(Method method) { 0469 return isMvcMethod(MethodDescriptor.forMethod(method)); 0470 } 0471 0472 /** 0473 * Finds out if the given {@code MetaMethod} belongs to the set of 0474 * predefined MVC methods by convention. 0475 * <p/> 0476 * <pre> 0477 * // assuming getMethod() returns an appropriate MetaMethod reference 0478 * isMvcMethod(getMethod("mvcGroupInit")) = true 0479 * isMvcMethod(getMethod("mvcGroupDestroy")) = true 0480 * isMvcMethod(getMethod("foo")) = false 0481 * </pre> 0482 * 0483 * @param method a Method reference 0484 * @return true if the method is an MVC method, false otherwise. 0485 */ 0486 public static boolean isMvcMethod(MetaMethod method) { 0487 return isMvcMethod(MethodDescriptor.forMethod(method)); 0488 } 0489 0490 /** 0491 * Finds out if the given {@code MethodDescriptor} belongs to the set of 0492 * predefined MVC methods by convention. 0493 * <p/> 0494 * <pre> 0495 * // assuming getMethod() returns an appropriate MethodDescriptor reference 0496 * isMvcMethod(getMethod("mvcGroupInit")) = true 0497 * isMvcMethod(getMethod("mvcGroupDestroy")) = true 0498 * isMvcMethod(getMethod("foo")) = false 0499 * </pre> 0500 * 0501 * @param method a Method reference 0502 * @return true if the method is an MVC method, false otherwise. 0503 */ 0504 public static boolean isMvcMethod(MethodDescriptor method) { 0505 if (method == null || !isInstanceMethod(method)) return false; 0506 return MVC_METHODS.contains(method); 0507 } 0508 0509 /** 0510 * Finds out if the given {@code Method} belongs to the set of 0511 * predefined threading methods by convention. 0512 * <p/> 0513 * <pre> 0514 * // assuming getMethod() returns an appropriate Method reference 0515 * isThreadingMethod(getMethod("execOutside")) = true 0516 * isThreadingMethod(getMethod("doLater")) = true 0517 * isThreadingMethod(getMethod("foo")) = false 0518 * </pre> 0519 * 0520 * @param method a Method reference 0521 * @return true if the method is a threading method, false otherwise. 0522 */ 0523 public static boolean isThreadingMethod(Method method) { 0524 return isThreadingMethod(MethodDescriptor.forMethod(method)); 0525 } 0526 0527 /** 0528 * Finds out if the given {@code MetaMethod} belongs to the set of 0529 * predefined threading methods by convention. 0530 * <p/> 0531 * <pre> 0532 * // assuming getMethod() returns an appropriate MetaMethod reference 0533 * isThreadingMethod(getMethod("execOutside")) = true 0534 * isThreadingMethod(getMethod("doLater")) = true 0535 * isThreadingMethod(getMethod("foo")) = false 0536 * </pre> 0537 * 0538 * @param method a Method reference 0539 * @return true if the method is a threading method, false otherwise. 0540 */ 0541 public static boolean isThreadingMethod(MetaMethod method) { 0542 return isThreadingMethod(MethodDescriptor.forMethod(method)); 0543 } 0544 0545 /** 0546 * Finds out if the given {@code MethodDescriptor} belongs to the set of 0547 * predefined threading methods by convention. 0548 * <p/> 0549 * <pre> 0550 * // assuming getMethod() returns an appropriate MethodDescriptor reference 0551 * isThreadingMethod(getMethod("execOutside")) = true 0552 * isThreadingMethod(getMethod("doLater")) = true 0553 * isThreadingMethod(getMethod("foo")) = false 0554 * </pre> 0555 * 0556 * @param method a Method reference 0557 * @return true if the method is a threading method, false otherwise. 0558 */ 0559 public static boolean isThreadingMethod(MethodDescriptor method) { 0560 if (method == null || !isInstanceMethod(method)) return false; 0561 return THREADING_METHODS.contains(method); 0562 } 0563 0564 /** 0565 * Finds out if the given {@code Method} belongs to the set of 0566 * predefined EVENT_PUBLISHER methods by convention. 0567 * <p/> 0568 * <pre> 0569 * // assuming getMethod() returns an appropriate Method reference 0570 * isEventPublisherMethod(getMethod("addEventPublisher")) = true 0571 * isEventPublisherMethod(getMethod("publishEvent")) = true 0572 * isEventPublisherMethod(getMethod("foo")) = false 0573 * </pre> 0574 * 0575 * @param method a Method reference 0576 * @return true if the method is an @EventPublisher method, false otherwise. 0577 */ 0578 public static boolean isEventPublisherMethod(Method method) { 0579 return isEventPublisherMethod(MethodDescriptor.forMethod(method)); 0580 } 0581 0582 /** 0583 * Finds out if the given {@code MetaMethod} belongs to the set of 0584 * predefined EVENT_PUBLISHER methods by convention. 0585 * <p/> 0586 * <pre> 0587 * // assuming getMethod() returns an appropriate MetaMethod reference 0588 * isEventPublisherMethod(getMethod("addEventPublisher")) = true 0589 * isEventPublisherMethod(getMethod("publishEvent")) = true 0590 * isEventPublisherMethod(getMethod("foo")) = false 0591 * </pre> 0592 * 0593 * @param method a Method reference 0594 * @return true if the method is an @EventPublisher method, false otherwise. 0595 */ 0596 public static boolean isEventPublisherMethod(MetaMethod method) { 0597 return isEventPublisherMethod(MethodDescriptor.forMethod(method)); 0598 } 0599 0600 /** 0601 * Finds out if the given {@code MethodDescriptor} belongs to the set of 0602 * predefined EVENT_PUBLISHER methods by convention. 0603 * <p/> 0604 * <pre> 0605 * // assuming getMethod() returns an appropriate MethodDescriptor reference 0606 * isEventPublisherMethod(getMethod("addEventPublisher")) = true 0607 * isEventPublisherMethod(getMethod("publishEvent")) = true 0608 * isEventPublisherMethod(getMethod("foo")) = false 0609 * </pre> 0610 * 0611 * @param method a Method reference 0612 * @return true if the method is an @EventPublisher method, false otherwise. 0613 */ 0614 public static boolean isEventPublisherMethod(MethodDescriptor method) { 0615 if (method == null || !isInstanceMethod(method)) return false; 0616 return EVENT_PUBLISHER_METHODS.contains(method); 0617 } 0618 0619 /** 0620 * Finds out if the given {@code Method} belongs to the set of 0621 * predefined OBSERVABLE methods by convention. 0622 * <p/> 0623 * <pre> 0624 * // assuming getMethod() returns an appropriate Method reference 0625 * isObservableMethod(getMethod("addPropertyChangeListener")) = true 0626 * isObservableMethod(getMethod("getPropertyChangeListeners")) = true 0627 * isObservableMethod(getMethod("foo")) = false 0628 * </pre> 0629 * 0630 * @param method a Method reference 0631 * @return true if the method is an Observable method, false otherwise. 0632 */ 0633 public static boolean isObservableMethod(Method method) { 0634 return isObservableMethod(MethodDescriptor.forMethod(method)); 0635 } 0636 0637 /** 0638 * Finds out if the given {@code MetaMethod} belongs to the set of 0639 * predefined OBSERVABLE methods by convention. 0640 * <p/> 0641 * <pre> 0642 * // assuming getMethod() returns an appropriate MetaMethod reference 0643 * isObservableMethod(getMethod("addPropertyChangeListener")) = true 0644 * isObservableMethod(getMethod("getPropertyChangeListeners")) = true 0645 * isObservableMethod(getMethod("foo")) = false 0646 * </pre> 0647 * 0648 * @param method a Method reference 0649 * @return true if the method is an Observable method, false otherwise. 0650 */ 0651 public static boolean isObservableMethod(MetaMethod method) { 0652 return isObservableMethod(MethodDescriptor.forMethod(method)); 0653 } 0654 0655 /** 0656 * Finds out if the given {@code MethodDescriptor} belongs to the set of 0657 * predefined OBSERVABLE methods by convention. 0658 * <p/> 0659 * <pre> 0660 * // assuming getMethod() returns an appropriate MethodDescriptor reference 0661 * isObservableMethod(getMethod("addPropertyChangeListener")) = true 0662 * isObservableMethod(getMethod("getPropertyChangeListeners")) = true 0663 * isObservableMethod(getMethod("foo")) = false 0664 * </pre> 0665 * 0666 * @param method a Method reference 0667 * @return true if the method is an Observable method, false otherwise. 0668 */ 0669 public static boolean isObservableMethod(MethodDescriptor method) { 0670 if (method == null || !isInstanceMethod(method)) return false; 0671 return OBSERVABLE_METHODS.contains(method); 0672 } 0673 0674 /** 0675 * Finds out if the given {@code Method} is an instance method, i.e, 0676 * it is public and non-static. 0677 * 0678 * @param method a Method reference 0679 * @return true if the method is an instance method, false otherwise. 0680 */ 0681 public static boolean isInstanceMethod(Method method) { 0682 return isInstanceMethod(MethodDescriptor.forMethod(method)); 0683 } 0684 0685 /** 0686 * Finds out if the given {@code MetaMethod} is an instance method, i.e, 0687 * it is public and non-static. 0688 * 0689 * @param method a MetaMethod reference 0690 * @return true if the method is an instance method, false otherwise. 0691 */ 0692 public static boolean isInstanceMethod(MetaMethod method) { 0693 return isInstanceMethod(MethodDescriptor.forMethod(method)); 0694 } 0695 0696 /** 0697 * Finds out if the given {@code MethodDescriptor} is an instance method, i.e, 0698 * it is public and non-static. 0699 * 0700 * @param method a MethodDescriptor reference 0701 * @return true if the method is an instance method, false otherwise. 0702 */ 0703 public static boolean isInstanceMethod(MethodDescriptor method) { 0704 if (method == null) return false; 0705 int modifiers = method.getModifiers(); 0706 return Modifier.isPublic(modifiers) && 0707 !Modifier.isStatic(modifiers); 0708 } 0709 0710 /** 0711 * Finds out if the given {@code Method} matches the following criteria:<ul> 0712 * <li>isInstanceMethod(method)</li> 0713 * <li>! isBasicMethod(method)</li> 0714 * <li>! isGroovyInjectedMethod(method)</li> 0715 * <li>! isThreadingMethod(method)</li> 0716 * <li>! isMvcMethod(method)</li> 0717 * <li>! isEventPublisherMethod(method)</li> 0718 * <li>! isObservableMethod(method)</li> 0719 * <li>! isGetterMethod(method)</li> 0720 * <li>! isSetterMethod(method)</li> 0721 * </ul> 0722 * 0723 * @param method a Method reference 0724 * @return true if the method matches the given criteria, false otherwise. 0725 */ 0726 public static boolean isPlainMethod(Method method) { 0727 return isPlainMethod(MethodDescriptor.forMethod(method)); 0728 } 0729 0730 /** 0731 * Finds out if the given {@code MetaMethod} matches the following criteria:<ul> 0732 * <li>isInstanceMethod(method)</li> 0733 * <li>! isBasicMethod(method)</li> 0734 * <li>! isGroovyInjectedMethod(method)</li> 0735 * <li>! isThreadingMethod(method)</li> 0736 * <li>! isMvcMethod(method)</li> 0737 * <li>! isEventPublisherMethod(method)</li> 0738 * <li>! isObservableMethod(method)</li> 0739 * <li>! isGetterMethod(method)</li> 0740 * <li>! isSetterMethod(method)</li> 0741 * </ul> 0742 * 0743 * @param method a Method reference 0744 * @return true if the method matches the given criteria, false otherwise. 0745 */ 0746 public static boolean isPlainMethod(MetaMethod method) { 0747 return isPlainMethod(MethodDescriptor.forMethod(method)); 0748 } 0749 0750 /** 0751 * Finds out if the given {@code MethodDescriptor} matches the following criteria:<ul> 0752 * <li>isInstanceMethod(method)</li> 0753 * <li>! isBasicMethod(method)</li> 0754 * <li>! isGroovyInjectedMethod(method)</li> 0755 * <li>! isThreadingMethod(method)</li> 0756 * <li>! isMvcMethod(method)</li> 0757 * <li>! isEventPublisherMethod(method)</li> 0758 * <li>! isObservableMethod(method)</li> 0759 * <li>! isGetterMethod(method)</li> 0760 * <li>! isSetterMethod(method)</li> 0761 * </ul> 0762 * 0763 * @param method a MethodDescriptor reference 0764 * @return true if the method matches the given criteria, false otherwise. 0765 */ 0766 public static boolean isPlainMethod(MethodDescriptor method) { 0767 return isInstanceMethod(method) && 0768 !isBasicMethod(method) && 0769 !isGroovyInjectedMethod(method) && 0770 !isThreadingMethod(method) && 0771 !isMvcMethod(method) && 0772 !isEventPublisherMethod(method) && 0773 !isObservableMethod(method) && 0774 !isGetterMethod(method) && 0775 !isSetterMethod(method); 0776 } 0777 0778 public static boolean isGetter(MetaProperty property) { 0779 return isGetter(property, false); 0780 } 0781 0782 public static boolean isGetter(MetaProperty property, boolean strict) { 0783 if (property == null) return false; 0784 return GETTER_PATTERN_1.matcher(property.getName()).matches() || 0785 (strict && GETTER_PATTERN_2.matcher(property.getName()).matches()); 0786 } 0787 0788 public static boolean isSetter(MetaProperty property) { 0789 if (property == null) return false; 0790 return SETTER_PATTERN.matcher(property.getName()).matches(); 0791 } 0792 0793 /** 0794 * Returns true if the specified property in the specified class is of the specified type 0795 * 0796 * @param clazz The class which contains the property 0797 * @param propertyName The property name 0798 * @param type The type to check 0799 * @return A boolean value 0800 */ 0801 public static boolean isPropertyOfType(Class<?> clazz, String propertyName, Class<?> type) { 0802 try { 0803 Class propType = getPropertyType(clazz, propertyName); 0804 return propType != null && propType.equals(type); 0805 } catch (Exception e) { 0806 return false; 0807 } 0808 } 0809 0810 /** 0811 * Instantiates a Class, wrapping any exceptions in a RuntimeException. 0812 * 0813 * @param clazz target Class for which an object will be instantiated 0814 * @return the newly instantiated object. 0815 * @throws BeanInstantiationException if an error occurs when creating the object 0816 */ 0817 public static Object instantiateClass(Class<?> clazz) { 0818 try { 0819 return clazz.newInstance(); 0820 } catch (Exception e) { 0821 throw new BeanInstantiationException("Could not create an instance of " + clazz, e); 0822 } 0823 } 0824 0825 /* 0826 public static Object instantiate(Class<?> clazz, Object arg) { 0827 return instantiate(clazz, new Object[]{arg}); 0828 } 0829 */ 0830 0831 public static Object instantiate(Class<?> clazz, Object[] args) { 0832 try { 0833 if (args == null) { 0834 args = EMPTY_OBJECT_ARRAY; 0835 } 0836 int arguments = args.length; 0837 Class[] parameterTypes = new Class[arguments]; 0838 for (int i = 0; i < arguments; i++) { 0839 parameterTypes[i] = args[i].getClass(); 0840 } 0841 return clazz.getDeclaredConstructor(parameterTypes).newInstance(args); 0842 } catch (Exception e) { 0843 throw new BeanInstantiationException("Could not create an instance of " + clazz, e); 0844 } 0845 } 0846 0847 /** 0848 * Returns the value of the specified property and type from an instance of the specified Griffon class 0849 * 0850 * @param clazz The name of the class which contains the property 0851 * @param propertyName The property name 0852 * @param propertyType The property type 0853 * @return The value of the property or null if none exists 0854 */ 0855 public static Object getPropertyValueOfNewInstance(Class<?> clazz, String propertyName, Class<?> propertyType) { 0856 // validate 0857 if (clazz == null || GriffonNameUtils.isBlank(propertyName)) 0858 return null; 0859 0860 Object instance = null; 0861 try { 0862 instance = instantiateClass(clazz); 0863 } catch (BeanInstantiationException e) { 0864 return null; 0865 } 0866 0867 return getPropertyOrStaticPropertyOrFieldValue(instance, propertyName); 0868 } 0869 0870 /** 0871 * Returns the value of the specified property and type from an instance of the specified Griffon class 0872 * 0873 * @param clazz The name of the class which contains the property 0874 * @param propertyName The property name 0875 * @return The value of the property or null if none exists 0876 */ 0877 public static Object getPropertyValueOfNewInstance(Class<?> clazz, String propertyName) { 0878 // validate 0879 if (clazz == null || GriffonNameUtils.isBlank(propertyName)) 0880 return null; 0881 0882 Object instance = null; 0883 try { 0884 instance = instantiateClass(clazz); 0885 } catch (BeanInstantiationException e) { 0886 return null; 0887 } 0888 0889 return getPropertyOrStaticPropertyOrFieldValue(instance, propertyName); 0890 } 0891 0892 /** 0893 * Retrieves a PropertyDescriptor for the specified instance and property value 0894 * 0895 * @param instance The instance 0896 * @param propertyValue The value of the property 0897 * @return The PropertyDescriptor 0898 */ 0899 public static PropertyDescriptor getPropertyDescriptorForValue(Object instance, Object propertyValue) { 0900 if (instance == null || propertyValue == null) 0901 return null; 0902 0903 PropertyDescriptor[] descriptors = getPropertyDescriptors(instance.getClass()); 0904 0905 for (int i = 0; i < descriptors.length; i++) { 0906 PropertyDescriptor pd = descriptors[i]; 0907 if (isAssignableOrConvertibleFrom(pd.getPropertyType(), propertyValue.getClass())) { 0908 Object value; 0909 try { 0910 value = getReadMethod(pd).invoke(instance, (Object[]) null); 0911 } catch (Exception e) { 0912 throw new RuntimeException("Problem calling readMethod of " + pd, e); 0913 } 0914 if (propertyValue.equals(value)) 0915 return pd; 0916 } 0917 } 0918 return null; 0919 } 0920 0921 /** 0922 * Returns the type of the given property contained within the specified class 0923 * 0924 * @param clazz The class which contains the property 0925 * @param propertyName The name of the property 0926 * @return The property type or null if none exists 0927 */ 0928 public static Class<?> getPropertyType(Class<?> clazz, String propertyName) { 0929 if (clazz == null || GriffonNameUtils.isBlank(propertyName)) 0930 return null; 0931 0932 try { 0933 PropertyDescriptor desc = getPropertyDescriptor(clazz, propertyName); 0934 if (desc != null) { 0935 return desc.getPropertyType(); 0936 } else { 0937 return null; 0938 } 0939 } catch (Exception e) { 0940 // if there are any errors in instantiating just return null for the moment 0941 return null; 0942 } 0943 } 0944 0945 /** 0946 * Retrieves all the properties of the given class for the given type 0947 * 0948 * @param clazz The class to retrieve the properties from 0949 * @param propertyType The type of the properties you wish to retrieve 0950 * @return An array of PropertyDescriptor instances 0951 */ 0952 public static PropertyDescriptor[] getPropertiesOfType(Class<?> clazz, Class<?> propertyType) { 0953 if (clazz == null || propertyType == null) 0954 return new PropertyDescriptor[0]; 0955 0956 Set properties = new HashSet(); 0957 try { 0958 PropertyDescriptor[] descriptors = getPropertyDescriptors(clazz); 0959 0960 for (int i = 0; i < descriptors.length; i++) { 0961 Class<?> currentPropertyType = descriptors[i].getPropertyType(); 0962 if (isTypeInstanceOfPropertyType(propertyType, currentPropertyType)) { 0963 properties.add(descriptors[i]); 0964 } 0965 } 0966 } catch (Exception e) { 0967 // if there are any errors in instantiating just return null for the moment 0968 return new PropertyDescriptor[0]; 0969 } 0970 return (PropertyDescriptor[]) properties.toArray(new PropertyDescriptor[properties.size()]); 0971 } 0972 0973 private static boolean isTypeInstanceOfPropertyType(Class<?> type, Class<?> propertyType) { 0974 return propertyType.isAssignableFrom(type) && !propertyType.equals(Object.class); 0975 } 0976 0977 /** 0978 * Retrieves all the properties of the given class which are assignable to the given type 0979 * 0980 * @param clazz The class to retrieve the properties from 0981 * @param propertySuperType The type of the properties you wish to retrieve 0982 * @return An array of PropertyDescriptor instances 0983 */ 0984 public static PropertyDescriptor[] getPropertiesAssignableToType(Class<?> clazz, Class<?> propertySuperType) { 0985 if (clazz == null || propertySuperType == null) return new PropertyDescriptor[0]; 0986 0987 Set properties = new HashSet(); 0988 try { 0989 PropertyDescriptor[] descriptors = getPropertyDescriptors(clazz); 0990 0991 for (int i = 0; i < descriptors.length; i++) { 0992 if (propertySuperType.isAssignableFrom(descriptors[i].getPropertyType())) { 0993 properties.add(descriptors[i]); 0994 } 0995 } 0996 } catch (Exception e) { 0997 return new PropertyDescriptor[0]; 0998 } 0999 return (PropertyDescriptor[]) properties.toArray(new PropertyDescriptor[properties.size()]); 1000 } 1001 1002 /** 1003 * Retrieves a property of the given class of the specified name and type 1004 * 1005 * @param clazz The class to retrieve the property from 1006 * @param propertyName The name of the property 1007 * @param propertyType The type of the property 1008 * @return A PropertyDescriptor instance or null if none exists 1009 */ 1010 public static PropertyDescriptor getProperty(Class<?> clazz, String propertyName, Class<?> propertyType) { 1011 if (clazz == null || propertyName == null || propertyType == null) 1012 return null; 1013 1014 try { 1015 PropertyDescriptor pd = getPropertyDescriptor(clazz, propertyName); 1016 if (pd.getPropertyType().equals(propertyType)) { 1017 return pd; 1018 } else { 1019 return null; 1020 } 1021 } catch (Exception e) { 1022 // if there are any errors in instantiating just return null for the moment 1023 return null; 1024 } 1025 } 1026 1027 /** 1028 * Convenience method for converting a collection to an Object[] 1029 * 1030 * @param c The collection 1031 * @return An object array 1032 */ 1033 public static Object[] collectionToObjectArray(Collection c) { 1034 if (c == null) return EMPTY_OBJECT_ARRAY; 1035 1036 return c.toArray(new Object[c.size()]); 1037 } 1038 1039 1040 /** 1041 * Detect if left and right types are matching types. In particular, 1042 * test if one is a primitive type and the other is the corresponding 1043 * Java wrapper type. Primitive and wrapper classes may be passed to 1044 * either arguments. 1045 * 1046 * @param leftType 1047 * @param rightType 1048 * @return true if one of the classes is a native type and the other the object representation 1049 * of the same native type 1050 */ 1051 public static boolean isMatchBetweenPrimitiveAndWrapperTypes(Class<?> leftType, Class<?> rightType) { 1052 if (leftType == null) { 1053 throw new NullPointerException("Left type is null!"); 1054 } else if (rightType == null) { 1055 throw new NullPointerException("Right type is null!"); 1056 } else { 1057 Class<?> r = (Class<?>) PRIMITIVE_TYPE_COMPATIBLE_CLASSES.get(leftType); 1058 return r == rightType; 1059 } 1060 } 1061 1062 /** 1063 * <p>Tests whether or not the left hand type is compatible with the right hand type in Groovy 1064 * terms, i.e. can the left type be assigned a value of the right hand type in Groovy.</p> 1065 * <p>This handles Java primitive type equivalence and uses isAssignableFrom for all other types, 1066 * with a bit of magic for native types and polymorphism i.e. Number assigned an int. 1067 * If either parameter is null an exception is thrown</p> 1068 * 1069 * @param leftType The type of the left hand part of a notional assignment 1070 * @param rightType The type of the right hand part of a notional assignment 1071 * @return True if values of the right hand type can be assigned in Groovy to variables of the left hand type. 1072 */ 1073 public static boolean isGroovyAssignableFrom(Class<?> leftType, Class<?> rightType) { 1074 if (leftType == null) { 1075 throw new NullPointerException("Left type is null!"); 1076 } else if (rightType == null) { 1077 throw new NullPointerException("Right type is null!"); 1078 } else if (leftType == Object.class) { 1079 return true; 1080 } else if (leftType == rightType) { 1081 return true; 1082 } else { 1083 // check for primitive type equivalence 1084 Class<?> r = (Class<?>) PRIMITIVE_TYPE_COMPATIBLE_CLASSES.get(leftType); 1085 boolean result = r == rightType; 1086 1087 if (!result) { 1088 // If no primitive <-> wrapper match, it may still be assignable 1089 // from polymorphic primitives i.e. Number -> int (AKA Integer) 1090 if (rightType.isPrimitive()) { 1091 // see if incompatible 1092 r = (Class<?>) PRIMITIVE_TYPE_COMPATIBLE_CLASSES.get(rightType); 1093 if (r != null) { 1094 result = leftType.isAssignableFrom(r); 1095 } 1096 } else { 1097 // Otherwise it may just be assignable using normal Java polymorphism 1098 result = leftType.isAssignableFrom(rightType); 1099 } 1100 } 1101 return result; 1102 } 1103 } 1104 1105 private static Method findDeclaredMethod(Class<?> clazz, String methodName, Class[] parameterTypes) { 1106 while (clazz != null) { 1107 try { 1108 Method method = clazz.getDeclaredMethod(methodName, parameterTypes); 1109 if (method != null) return method; 1110 } catch (NoSuchMethodException e) { 1111 // skip 1112 } catch (SecurityException e) { 1113 // skip 1114 } 1115 clazz = clazz.getSuperclass(); 1116 } 1117 1118 return null; 1119 } 1120 1121 /** 1122 * <p>Work out if the specified property is readable and static. Java introspection does not 1123 * recognize this concept of static properties but Groovy does. We also consider public static fields 1124 * as static properties with no getters/setters</p> 1125 * 1126 * @param clazz The class to check for static property 1127 * @param propertyName The property name 1128 * @return true if the property with name propertyName has a static getter method 1129 */ 1130 public static boolean isStaticProperty(Class<?> clazz, String propertyName) { 1131 Method getter = findDeclaredMethod(clazz, getGetterName(propertyName), null); 1132 if (getter != null) { 1133 return isPublicStatic(getter); 1134 } else { 1135 try { 1136 Field f = clazz.getDeclaredField(propertyName); 1137 if (f != null) { 1138 return isPublicStatic(f); 1139 } 1140 } catch (NoSuchFieldException ignore) { 1141 //ignore 1142 } 1143 } 1144 1145 return false; 1146 } 1147 1148 /** 1149 * Determine whether the method is declared public static 1150 * 1151 * @param m 1152 * @return True if the method is declared public static 1153 */ 1154 public static boolean isPublicStatic(Method m) { 1155 final int modifiers = m.getModifiers(); 1156 return Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers); 1157 } 1158 1159 /** 1160 * Determine whether the field is declared public static 1161 * 1162 * @param f 1163 * @return True if the field is declared public static 1164 */ 1165 public static boolean isPublicStatic(Field f) { 1166 final int modifiers = f.getModifiers(); 1167 return Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers); 1168 } 1169 1170 /** 1171 * Calculate the name for a getter method to retrieve the specified property 1172 * 1173 * @param propertyName 1174 * @return The name for the getter method for this property, if it were to exist, i.e. getConstraints 1175 */ 1176 public static String getGetterName(String propertyName) { 1177 return PROPERTY_GET_PREFIX + Character.toUpperCase(propertyName.charAt(0)) 1178 + propertyName.substring(1); 1179 } 1180 1181 /** 1182 * <p>Get a static property value, which has a public static getter or is just a public static field.</p> 1183 * 1184 * @param clazz The class to check for static property 1185 * @param name The property name 1186 * @return The value if there is one, or null if unset OR there is no such property 1187 */ 1188 public static Object getStaticPropertyValue(Class<?> clazz, String name) { 1189 Method getter = findDeclaredMethod(clazz, getGetterName(name), null); 1190 try { 1191 if (getter != null) { 1192 return getter.invoke(null, (Object[]) null); 1193 } else { 1194 Field f = clazz.getDeclaredField(name); 1195 if (f != null) { 1196 return f.get(null); 1197 } 1198 } 1199 } catch (Exception ignore) { 1200 //ignore 1201 } 1202 return null; 1203 } 1204 1205 /** 1206 * <p>Looks for a property of the reference instance with a given name.</p> 1207 * <p>If found its value is returned. We follow the Java bean conventions with augmentation for groovy support 1208 * and static fields/properties. We will therefore match, in this order: 1209 * </p> 1210 * <ol> 1211 * <li>Standard public bean property (with getter or just public field, using normal introspection) 1212 * <li>Public static property with getter method 1213 * <li>Public static field 1214 * </ol> 1215 * 1216 * @return property value or null if no property found 1217 */ 1218 public static Object getPropertyOrStaticPropertyOrFieldValue(Object obj, String name) { 1219 if (isReadable(obj, name)) { 1220 try { 1221 return getProperty(obj, name); 1222 } catch (Exception e) { 1223 throw new BeanException("Error while reading value of property/field " + name, e); 1224 } 1225 } else { 1226 // Look for public fields 1227 if (isPublicField(obj, name)) { 1228 return getFieldValue(obj, name); 1229 } 1230 1231 // Look for statics 1232 Class<?> clazz = obj.getClass(); 1233 if (isStaticProperty(clazz, name)) { 1234 return getStaticPropertyValue(clazz, name); 1235 } else { 1236 return null; 1237 } 1238 } 1239 } 1240 1241 /** 1242 * Get the value of a declared field on an object 1243 * 1244 * @param obj 1245 * @param name 1246 * @return The object value or null if there is no such field or access problems 1247 */ 1248 public static Object getFieldValue(Object obj, String name) { 1249 Class<?> clazz = obj.getClass(); 1250 Field f = null; 1251 try { 1252 f = clazz.getDeclaredField(name); 1253 return f.get(obj); 1254 } catch (Exception e) { 1255 return null; 1256 } 1257 } 1258 1259 /** 1260 * Work out if the specified object has a public field with the name supplied. 1261 * 1262 * @param obj 1263 * @param name 1264 * @return True if a public field with the name exists 1265 */ 1266 public static boolean isPublicField(Object obj, String name) { 1267 Class<?> clazz = obj.getClass(); 1268 Field f = null; 1269 try { 1270 f = clazz.getDeclaredField(name); 1271 return Modifier.isPublic(f.getModifiers()); 1272 } catch (NoSuchFieldException e) { 1273 return false; 1274 } 1275 } 1276 1277 /** 1278 * Checks whether the specified property is inherited from a super class 1279 * 1280 * @param clz The class to check 1281 * @param propertyName The property name 1282 * @return True if the property is inherited 1283 */ 1284 public static boolean isPropertyInherited(Class<?> clz, String propertyName) { 1285 if (clz == null) return false; 1286 if (GriffonNameUtils.isBlank(propertyName)) 1287 throw new IllegalArgumentException("Argument [propertyName] cannot be null or blank"); 1288 1289 Class<?> superClass = clz.getSuperclass(); 1290 1291 PropertyDescriptor pd = null; 1292 try { 1293 pd = getPropertyDescriptor(superClass, propertyName); 1294 } catch (Exception e) { 1295 throw new BeanException("Could not read property descritptor for " + propertyName + " in " + superClass, e); 1296 } 1297 if (pd != null && pd.getReadMethod() != null) { 1298 return true; 1299 } 1300 return false; 1301 } 1302 1303 /** 1304 * Creates a concrete collection for the suppied interface 1305 * 1306 * @param interfaceType The interface 1307 * @return ArrayList for List, TreeSet for SortedSet, HashSet for Set etc. 1308 */ 1309 public static Collection createConcreteCollection(Class<?> interfaceType) { 1310 Collection elements; 1311 if (interfaceType.equals(List.class)) { 1312 elements = new ArrayList(); 1313 } else if (interfaceType.equals(SortedSet.class)) { 1314 elements = new TreeSet(); 1315 } else { 1316 elements = new HashSet(); 1317 } 1318 return elements; 1319 } 1320 1321 /** 1322 * Retrieves the name of a setter for the specified property name 1323 * 1324 * @param propertyName The property name 1325 * @return The setter equivalent 1326 */ 1327 public static String getSetterName(String propertyName) { 1328 return PROPERTY_SET_PREFIX + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1); 1329 } 1330 1331 /** 1332 * Returns true if the name of the method specified and the number of arguments make it a javabean property 1333 * 1334 * @param name True if its a Javabean property 1335 * @param args The arguments 1336 * @return True if it is a javabean property method 1337 */ 1338 public static boolean isGetter(String name, Class[] args) { 1339 if (GriffonNameUtils.isBlank(name) || args == null) return false; 1340 if (args.length != 0) return false; 1341 1342 if (name.startsWith(PROPERTY_GET_PREFIX)) { 1343 name = name.substring(3); 1344 if (name.length() > 0 && Character.isUpperCase(name.charAt(0))) return true; 1345 } else if (name.startsWith(PROPERTY_IS_PREFIX)) { 1346 name = name.substring(2); 1347 if (name.length() > 0 && Character.isUpperCase(name.charAt(0))) return true; 1348 } 1349 return false; 1350 } 1351 1352 /** 1353 * Returns a property name equivalent for the given getter name or null if it is not a getter 1354 * 1355 * @param getterName The getter name 1356 * @return The property name equivalent 1357 */ 1358 public static String getPropertyForGetter(String getterName) { 1359 if (GriffonNameUtils.isBlank(getterName)) return null; 1360 1361 if (getterName.startsWith(PROPERTY_GET_PREFIX)) { 1362 String prop = getterName.substring(3); 1363 return convertPropertyName(prop); 1364 } else if (getterName.startsWith(PROPERTY_IS_PREFIX)) { 1365 String prop = getterName.substring(2); 1366 return convertPropertyName(prop); 1367 } 1368 return null; 1369 } 1370 1371 private static String convertPropertyName(String prop) { 1372 if (Character.isUpperCase(prop.charAt(0)) && Character.isUpperCase(prop.charAt(1))) { 1373 return prop; 1374 } else if (Character.isDigit(prop.charAt(0))) { 1375 return prop; 1376 } else { 1377 return Character.toLowerCase(prop.charAt(0)) + prop.substring(1); 1378 } 1379 } 1380 1381 /** 1382 * Returns a property name equivalent for the given setter name or null if it is not a getter 1383 * 1384 * @param setterName The setter name 1385 * @return The property name equivalent 1386 */ 1387 public static String getPropertyForSetter(String setterName) { 1388 if (GriffonNameUtils.isBlank(setterName)) return null; 1389 1390 if (setterName.startsWith(PROPERTY_SET_PREFIX)) { 1391 String prop = setterName.substring(3); 1392 return convertPropertyName(prop); 1393 } 1394 return null; 1395 } 1396 1397 public static boolean isSetter(String name, Class[] args) { 1398 if (GriffonNameUtils.isBlank(name) || args == null) return false; 1399 1400 if (name.startsWith(PROPERTY_SET_PREFIX)) { 1401 if (args.length != 1) return false; 1402 name = name.substring(3); 1403 if (name.length() > 0 && Character.isUpperCase(name.charAt(0))) return true; 1404 } 1405 1406 return false; 1407 } 1408 1409 public static MetaClass getExpandoMetaClass(Class<?> clazz) { 1410 MetaClassRegistry registry = GroovySystem.getMetaClassRegistry(); 1411 isTrue(registry.getMetaClassCreationHandler() instanceof ExpandoMetaClassCreationHandle, "Griffon requires an instance of [ExpandoMetaClassCreationHandle] to be set in Groovy's MetaClassRegistry!"); 1412 MetaClass mc = registry.getMetaClass(clazz); 1413 AdaptingMetaClass adapter = null; 1414 if (mc instanceof AdaptingMetaClass) { 1415 adapter = (AdaptingMetaClass) mc; 1416 mc = ((AdaptingMetaClass) mc).getAdaptee(); 1417 } 1418 1419 if (!(mc instanceof ExpandoMetaClass)) { 1420 // removes cached version 1421 registry.removeMetaClass(clazz); 1422 mc = registry.getMetaClass(clazz); 1423 if (adapter != null) { 1424 adapter.setAdaptee(mc); 1425 } 1426 } 1427 isTrue(mc instanceof ExpandoMetaClass, "BUG! Method must return an instance of [ExpandoMetaClass]!"); 1428 return mc; 1429 } 1430 1431 /** 1432 * Returns true if the specified clazz parameter is either the same as, or is a superclass or superinterface 1433 * of, the specified type parameter. Converts primitive types to compatible class automatically. 1434 * 1435 * @param clazz 1436 * @param type 1437 * @return True if the class is a taglib 1438 * @see java.lang.Class#isAssignableFrom(Class) 1439 */ 1440 public static boolean isAssignableOrConvertibleFrom(Class<?> clazz, Class<?> type) { 1441 if (type == null || clazz == null) { 1442 return false; 1443 } else if (type.isPrimitive()) { 1444 // convert primitive type to compatible class 1445 Class<?> primitiveClass = (Class<?>) PRIMITIVE_TYPE_COMPATIBLE_CLASSES.get(type); 1446 if (primitiveClass == null) { 1447 // no compatible class found for primitive type 1448 return false; 1449 } else { 1450 return clazz.isAssignableFrom(primitiveClass); 1451 } 1452 } else { 1453 return clazz.isAssignableFrom(type); 1454 } 1455 } 1456 1457 /** 1458 * Retrieves a boolean value from a Map for the given key 1459 * 1460 * @param key The key that references the boolean value 1461 * @param map The map to look in 1462 * @return A boolean value which will be false if the map is null, the map doesn't contain the key or the value is false 1463 */ 1464 public static boolean getBooleanFromMap(String key, Map map) { 1465 if (map == null) return false; 1466 if (map.containsKey(key)) { 1467 Object o = map.get(key); 1468 if (o == null) return false; 1469 else if (o instanceof Boolean) { 1470 return ((Boolean) o).booleanValue(); 1471 } else { 1472 return Boolean.valueOf(o.toString()).booleanValue(); 1473 } 1474 } 1475 return false; 1476 } 1477 1478 /** 1479 * Locates the name of a property for the given value on the target object using Groovy's meta APIs. 1480 * Note that this method uses the reference so the incorrect result could be returned for two properties 1481 * that refer to the same reference. Use with caution. 1482 * 1483 * @param target The target 1484 * @param obj The property value 1485 * @return The property name or null 1486 */ 1487 public static String findPropertyNameForValue(Object target, Object obj) { 1488 MetaClass mc = GroovySystem.getMetaClassRegistry().getMetaClass(target.getClass()); 1489 List<MetaProperty> metaProperties = mc.getProperties(); 1490 for (MetaProperty metaProperty : metaProperties) { 1491 if (isAssignableOrConvertibleFrom(metaProperty.getType(), obj.getClass())) { 1492 Object val = metaProperty.getProperty(target); 1493 if (val != null && val.equals(obj)) 1494 return metaProperty.getName(); 1495 } 1496 } 1497 return null; 1498 } 1499 1500 /** 1501 * Returns whether the specified class is either within one of the specified packages or 1502 * within a subpackage of one of the packages 1503 * 1504 * @param theClass The class 1505 * @param packageList The list of packages 1506 * @return True if it is within the list of specified packages 1507 */ 1508 public static boolean isClassBelowPackage(Class<?> theClass, List packageList) { 1509 String classPackage = theClass.getPackage().getName(); 1510 for (Object packageName : packageList) { 1511 if (packageName != null) { 1512 if (classPackage.startsWith(packageName.toString())) { 1513 return true; 1514 } 1515 } 1516 } 1517 return false; 1518 } 1519 1520 // -- The following methods and properties were copied from commons-beanutils 1521 1522 private static final Map<String, PropertyDescriptor[]> descriptorsCache = new LinkedHashMap<String, PropertyDescriptor[]>(); 1523 1524 /** 1525 * <p>Retrieve the property descriptor for the specified property of the 1526 * specified bean, or return <code>null</code> if there is no such 1527 * descriptor.</p> 1528 * This method does not resolve index, nested nor mapped properties.<p> 1529 * 1530 * @param bean Bean for which a property descriptor is requested 1531 * @param name name of the property for which a property descriptor 1532 * is requested 1533 * @return the property descriptor or null if the bean does not have 1534 * a property that matches the specified name. 1535 * @throws IllegalAccessException if the caller does not have 1536 * access to the property accessor method 1537 * @throws IllegalArgumentException if <code>bean</code> or 1538 * <code>name</code> is null 1539 * @throws InvocationTargetException if the property accessor method 1540 * throws an exception 1541 * @throws NoSuchMethodException if an accessor method for this 1542 * property cannot be found 1543 */ 1544 public static PropertyDescriptor getPropertyDescriptor(Object bean, 1545 String name) 1546 throws IllegalAccessException, InvocationTargetException, 1547 NoSuchMethodException { 1548 if (bean == null) { 1549 throw new IllegalArgumentException("No bean specified"); 1550 } 1551 if (name == null) { 1552 throw new IllegalArgumentException("No name specified for bean class '" + 1553 bean.getClass() + "'"); 1554 } 1555 1556 return getPropertyDescriptor(bean instanceof Class ? (Class<?>) bean : bean.getClass(), name); 1557 } 1558 1559 /** 1560 * <p>Retrieve the property descriptor for the specified property of the 1561 * specified class, or return <code>null</code> if there is no such 1562 * descriptor.</p> 1563 * This method does not resolve index, nested nor mapped properties.<p> 1564 * 1565 * @param clazz class for which a property descriptor is requested 1566 * @param name name of the property for which a property descriptor 1567 * is requested 1568 * @return the property descriptor or null if the bean does not have 1569 * a property that matches the specified name. 1570 * @throws IllegalAccessException if the caller does not have 1571 * access to the property accessor method 1572 * @throws IllegalArgumentException if <code>bean</code> or 1573 * <code>name</code> is null 1574 * @throws InvocationTargetException if the property accessor method 1575 * throws an exception 1576 * @throws NoSuchMethodException if an accessor method for this 1577 * property cannot be found 1578 */ 1579 public static PropertyDescriptor getPropertyDescriptor(Class<?> clazz, 1580 String name) 1581 throws IllegalAccessException, InvocationTargetException, 1582 NoSuchMethodException { 1583 if (clazz == null) { 1584 throw new IllegalArgumentException("No class specified"); 1585 } 1586 if (name == null) { 1587 throw new IllegalArgumentException("No name specified for class '" + clazz + "'"); 1588 } 1589 1590 PropertyDescriptor[] descriptors = getPropertyDescriptors(clazz); 1591 if (descriptors != null) { 1592 for (int i = 0; i < descriptors.length; i++) { 1593 if (name.equals(descriptors[i].getName())) { 1594 return (descriptors[i]); 1595 } 1596 } 1597 } 1598 1599 return null; 1600 } 1601 1602 /** 1603 * <p>Retrieve the property descriptors for the specified class, 1604 * introspecting and caching them the first time a particular bean class 1605 * is encountered.</p> 1606 * 1607 * @param beanClass Bean class for which property descriptors are requested 1608 * @return the property descriptors 1609 * @throws IllegalArgumentException if <code>beanClass</code> is null 1610 */ 1611 public static PropertyDescriptor[] getPropertyDescriptors(Class<?> beanClass) { 1612 if (beanClass == null) { 1613 throw new IllegalArgumentException("No bean class specified"); 1614 } 1615 1616 // Look up any cached descriptors for this bean class 1617 PropertyDescriptor[] descriptors = null; 1618 descriptors = (PropertyDescriptor[]) descriptorsCache.get(beanClass.getName()); 1619 if (descriptors != null) { 1620 return (descriptors); 1621 } 1622 1623 // Introspect the bean and cache the generated descriptors 1624 BeanInfo beanInfo = null; 1625 try { 1626 beanInfo = Introspector.getBeanInfo(beanClass); 1627 } catch (IntrospectionException e) { 1628 return (new PropertyDescriptor[0]); 1629 } 1630 descriptors = beanInfo.getPropertyDescriptors(); 1631 if (descriptors == null) { 1632 descriptors = new PropertyDescriptor[0]; 1633 } 1634 1635 descriptorsCache.put(beanClass.getName(), descriptors); 1636 return (descriptors); 1637 } 1638 1639 /** 1640 * <p>Return an accessible property getter method for this property, 1641 * if there is one; otherwise return <code>null</code>.</p> 1642 * 1643 * @param descriptor Property descriptor to return a getter for 1644 * @return The read method 1645 */ 1646 public static Method getReadMethod(PropertyDescriptor descriptor) { 1647 return (MethodUtils.getAccessibleMethod(descriptor.getReadMethod())); 1648 } 1649 1650 /** 1651 * <p>Return <code>true</code> if the specified property name identifies 1652 * a readable property on the specified bean; otherwise, return 1653 * <code>false</code>. 1654 * 1655 * @param bean Bean to be examined 1656 * @param name Property name to be evaluated 1657 * @return <code>true</code> if the property is readable, 1658 * otherwise <code>false</code> 1659 * @throws IllegalArgumentException if <code>bean</code> 1660 * or <code>name</code> is <code>null</code> 1661 * @since BeanUtils 1.6 1662 */ 1663 public static boolean isReadable(Object bean, String name) { 1664 // Validate method parameters 1665 if (bean == null) { 1666 throw new IllegalArgumentException("No bean specified"); 1667 } 1668 if (name == null) { 1669 throw new IllegalArgumentException("No name specified for bean class '" + 1670 bean.getClass() + "'"); 1671 } 1672 1673 try { 1674 PropertyDescriptor desc = getPropertyDescriptor(bean, name); 1675 if (desc != null) { 1676 Method readMethod = getReadMethod(bean.getClass(), desc); 1677 if (readMethod == null) { 1678 readMethod = MethodUtils.getAccessibleMethod(bean.getClass(), readMethod); 1679 } 1680 return (readMethod != null); 1681 } else { 1682 return (false); 1683 } 1684 } catch (IllegalAccessException e) { 1685 return (false); 1686 } catch (InvocationTargetException e) { 1687 return (false); 1688 } catch (NoSuchMethodException e) { 1689 return (false); 1690 } 1691 } 1692 1693 /** 1694 * Return the value of the specified property of the specified bean, 1695 * no matter which property reference format is used, with no 1696 * type conversions. 1697 * 1698 * @param bean Bean whose property is to be extracted 1699 * @param name Possibly indexed and/or nested name of the property 1700 * to be extracted 1701 * @return the property value 1702 * @throws IllegalAccessException if the caller does not have 1703 * access to the property accessor method 1704 * @throws IllegalArgumentException if <code>bean</code> or 1705 * <code>name</code> is null 1706 * @throws InvocationTargetException if the property accessor method 1707 * throws an exception 1708 * @throws NoSuchMethodException if an accessor method for this 1709 * property cannot be found 1710 */ 1711 public static Object getProperty(Object bean, String name) 1712 throws IllegalAccessException, InvocationTargetException, 1713 NoSuchMethodException { 1714 if (bean == null) { 1715 throw new IllegalArgumentException("No bean specified"); 1716 } 1717 if (name == null) { 1718 throw new IllegalArgumentException("No name specified for bean class '" + 1719 bean.getClass() + "'"); 1720 } 1721 1722 // Retrieve the property getter method for the specified property 1723 PropertyDescriptor descriptor = getPropertyDescriptor(bean, name); 1724 if (descriptor == null) { 1725 throw new NoSuchMethodException("Unknown property '" + 1726 name + "' on class '" + bean.getClass() + "'"); 1727 } 1728 Method readMethod = getReadMethod(bean.getClass(), descriptor); 1729 if (readMethod == null) { 1730 throw new NoSuchMethodException("Property '" + name + 1731 "' has no getter method in class '" + bean.getClass() + "'"); 1732 } 1733 1734 // Call the property getter and return the value 1735 Object value = readMethod.invoke(bean, EMPTY_OBJECT_ARRAY); 1736 return (value); 1737 } 1738 1739 /** 1740 * <p>Return an accessible property getter method for this property, 1741 * if there is one; otherwise return <code>null</code>.</p> 1742 * 1743 * @param clazz The class of the read method will be invoked on 1744 * @param descriptor Property descriptor to return a getter for 1745 * @return The read method 1746 */ 1747 public static Method getReadMethod(Class<?> clazz, PropertyDescriptor descriptor) { 1748 return (MethodUtils.getAccessibleMethod(clazz, descriptor.getReadMethod())); 1749 } 1750 1751 // -- The following methods and properties were copied from commons-lang 1752 1753 /** 1754 * <p>Validate that the argument condition is <code>true</code>; otherwise 1755 * throwing an exception with the specified message. This method is useful when 1756 * validating according to an arbitrary boolean expression, such as validating a 1757 * primitive number or using your own custom validation expression.</p> 1758 * <p/> 1759 * <pre> 1760 * isTrue( (i > 0), "The value must be greater than zero"); 1761 * isTrue( myObject.isOk(), "The object is not OK"); 1762 * </pre> 1763 * 1764 * @param expression the boolean expression to check 1765 * @param message the exception message if invalid 1766 * @throws IllegalArgumentException if expression is <code>false</code> 1767 */ 1768 public static void isTrue(boolean expression, String message) { 1769 if (expression) { 1770 throw new IllegalArgumentException(message); 1771 } 1772 } 1773 1774 public static Object invokeInstanceMethod(Object object, String methodName) { 1775 return invokeInstanceMethod(object, methodName, EMPTY_ARGS); 1776 } 1777 1778 public static Object invokeInstanceMethod(Object object, String methodName, Object arg) { 1779 return invokeInstanceMethod(object, methodName, new Object[]{arg}); 1780 } 1781 1782 public static Object invokeInstanceMethod(Object object, String methodName, Object... args) { 1783 try { 1784 return invokeMethod(object, methodName, args); 1785 } catch (NoSuchMethodException e) { 1786 throw new RuntimeException(e); 1787 } catch (IllegalAccessException e) { 1788 throw new RuntimeException(e); 1789 } catch (InvocationTargetException e) { 1790 Throwable cause = e.getTargetException(); 1791 if (cause instanceof RuntimeException) { 1792 throw (RuntimeException) cause; 1793 } 1794 throw new RuntimeException(e.getMessage(), cause); 1795 } 1796 } 1797 1798 public static Object invokeExactInstanceMethod(Object object, String methodName) { 1799 return invokeExactInstanceMethod(object, methodName, EMPTY_ARGS); 1800 } 1801 1802 public static Object invokeExactInstanceMethod(Object object, String methodName, Object arg) { 1803 return invokeExactInstanceMethod(object, methodName, new Object[]{arg}); 1804 } 1805 1806 public static Object invokeExactInstanceMethod(Object object, String methodName, Object... args) { 1807 try { 1808 return invokeExactMethod(object, methodName, args); 1809 } catch (NoSuchMethodException e) { 1810 throw new RuntimeException(e); 1811 } catch (IllegalAccessException e) { 1812 throw new RuntimeException(e); 1813 } catch (InvocationTargetException e) { 1814 Throwable cause = e.getTargetException(); 1815 if (cause instanceof RuntimeException) { 1816 throw (RuntimeException) cause; 1817 } 1818 throw new RuntimeException(e.getMessage(), cause); 1819 } 1820 } 1821 1822 public static Object invokeStaticMethod(Class type, String methodName) { 1823 return invokeStaticMethod(type, methodName, EMPTY_ARGS); 1824 } 1825 1826 public static Object invokeStaticMethod(Class type, String methodName, Object arg) { 1827 return invokeStaticMethod(type, methodName, new Object[]{arg}); 1828 } 1829 1830 public static Object invokeStaticMethod(Class type, String methodName, Object... args) { 1831 try { 1832 return MethodUtils.invokeStaticMethod(type, methodName, args); 1833 } catch (NoSuchMethodException e) { 1834 throw new RuntimeException(e); 1835 } catch (IllegalAccessException e) { 1836 throw new RuntimeException(e); 1837 } catch (InvocationTargetException e) { 1838 Throwable cause = e.getTargetException(); 1839 if (cause instanceof RuntimeException) { 1840 throw (RuntimeException) cause; 1841 } 1842 throw new RuntimeException(e.getMessage(), cause); 1843 } 1844 } 1845 1846 public static Object invokeExactStaticMethod(Class type, String methodName) { 1847 return invokeExactStaticMethod(type, methodName, EMPTY_ARGS); 1848 } 1849 1850 public static Object invokeExactStaticMethod(Class type, String methodName, Object arg) { 1851 return invokeExactStaticMethod(type, methodName, new Object[]{arg}); 1852 } 1853 1854 public static Object invokeExactStaticMethod(Class type, String methodName, Object... args) { 1855 try { 1856 return MethodUtils.invokeExactStaticMethod(type, methodName, args); 1857 } catch (NoSuchMethodException e) { 1858 throw new RuntimeException(e); 1859 } catch (IllegalAccessException e) { 1860 throw new RuntimeException(e); 1861 } catch (InvocationTargetException e) { 1862 Throwable cause = e.getTargetException(); 1863 if (cause instanceof RuntimeException) { 1864 throw (RuntimeException) cause; 1865 } 1866 throw new RuntimeException(e.getMessage(), cause); 1867 } 1868 } 1869 1870 private static final String EMPTY_STRING = ""; 1871 1872 /** 1873 * <p>The package separator character: <code>'&#x2e;' == {@value}</code>.</p> 1874 */ 1875 public static final char PACKAGE_SEPARATOR_CHAR = '.'; 1876 1877 /** 1878 * <p>The package separator String: <code>"&#x2e;"</code>.</p> 1879 */ 1880 public static final String PACKAGE_SEPARATOR = String.valueOf(PACKAGE_SEPARATOR_CHAR); 1881 1882 /** 1883 * <p>The inner class separator character: <code>'$' == {@value}</code>.</p> 1884 */ 1885 public static final char INNER_CLASS_SEPARATOR_CHAR = '$'; 1886 1887 /** 1888 * <p>The inner class separator String: <code>"$"</code>.</p> 1889 */ 1890 public static final String INNER_CLASS_SEPARATOR = String.valueOf(INNER_CLASS_SEPARATOR_CHAR); 1891 1892 /** 1893 * Maps a primitive class name to its corresponding abbreviation used in array class names. 1894 */ 1895 private static final Map abbreviationMap = new HashMap(); 1896 1897 /** 1898 * Maps an abbreviation used in array class names to corresponding primitive class name. 1899 */ 1900 private static final Map reverseAbbreviationMap = new HashMap(); 1901 1902 /** 1903 * Add primitive type abbreviation to maps of abbreviations. 1904 * 1905 * @param primitive Canonical name of primitive type 1906 * @param abbreviation Corresponding abbreviation of primitive type 1907 */ 1908 private static void addAbbreviation(String primitive, String abbreviation) { 1909 abbreviationMap.put(primitive, abbreviation); 1910 reverseAbbreviationMap.put(abbreviation, primitive); 1911 } 1912 1913 /** 1914 * Feed abbreviation maps 1915 */ 1916 static { 1917 addAbbreviation("int", "I"); 1918 addAbbreviation("boolean", "Z"); 1919 addAbbreviation("float", "F"); 1920 addAbbreviation("long", "J"); 1921 addAbbreviation("short", "S"); 1922 addAbbreviation("byte", "B"); 1923 addAbbreviation("double", "D"); 1924 addAbbreviation("char", "C"); 1925 } 1926 1927 // ---------------------------------------------------------------------- 1928 1929 /** 1930 * <p>Gets the class name minus the package name for an <code>Object</code>.</p> 1931 * 1932 * @param object the class to get the short name for, may be null 1933 * @param valueIfNull the value to return if null 1934 * @return the class name of the object without the package name, or the null value 1935 */ 1936 public static String getShortClassName(Object object, String valueIfNull) { 1937 if (object == null) { 1938 return valueIfNull; 1939 } 1940 return getShortClassName(object.getClass()); 1941 } 1942 1943 /** 1944 * <p>Gets the class name minus the package name from a <code>Class</code>.</p> 1945 * 1946 * @param cls the class to get the short name for. 1947 * @return the class name without the package name or an empty string 1948 */ 1949 public static String getShortClassName(Class<?> cls) { 1950 if (cls == null) { 1951 return EMPTY_STRING; 1952 } 1953 return getShortClassName(cls.getName()); 1954 } 1955 1956 /** 1957 * <p>Gets the class name minus the package name from a String.</p> 1958 * <p/> 1959 * <p>The string passed in is assumed to be a class name - it is not checked.</p> 1960 * 1961 * @param className the className to get the short name for 1962 * @return the class name of the class without the package name or an empty string 1963 */ 1964 public static String getShortClassName(String className) { 1965 if (className == null) { 1966 return EMPTY_STRING; 1967 } 1968 if (className.length() == 0) { 1969 return EMPTY_STRING; 1970 } 1971 1972 StringBuffer arrayPrefix = new StringBuffer(); 1973 1974 // Handle array encoding 1975 if (className.startsWith("[")) { 1976 while (className.charAt(0) == '[') { 1977 className = className.substring(1); 1978 arrayPrefix.append("[]"); 1979 } 1980 // Strip Object type encoding 1981 if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';') { 1982 className = className.substring(1, className.length() - 1); 1983 } 1984 } 1985 1986 if (reverseAbbreviationMap.containsKey(className)) { 1987 className = (String) reverseAbbreviationMap.get(className); 1988 } 1989 1990 int lastDotIdx = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR); 1991 int innerIdx = className.indexOf( 1992 INNER_CLASS_SEPARATOR_CHAR, lastDotIdx == -1 ? 0 : lastDotIdx + 1); 1993 String out = className.substring(lastDotIdx + 1); 1994 if (innerIdx != -1) { 1995 out = out.replace(INNER_CLASS_SEPARATOR_CHAR, PACKAGE_SEPARATOR_CHAR); 1996 } 1997 return out + arrayPrefix; 1998 } 1999 2000 // Package name 2001 // ---------------------------------------------------------------------- 2002 2003 /** 2004 * <p>Gets the package name of an <code>Object</code>.</p> 2005 * 2006 * @param object the class to get the package name for, may be null 2007 * @param valueIfNull the value to return if null 2008 * @return the package name of the object, or the null value 2009 */ 2010 public static String getPackageName(Object object, String valueIfNull) { 2011 if (object == null) { 2012 return valueIfNull; 2013 } 2014 return getPackageName(object.getClass()); 2015 } 2016 2017 /** 2018 * <p>Gets the package name of a <code>Class</code>.</p> 2019 * 2020 * @param cls the class to get the package name for, may be <code>null</code>. 2021 * @return the package name or an empty string 2022 */ 2023 public static String getPackageName(Class<?> cls) { 2024 if (cls == null) { 2025 return EMPTY_STRING; 2026 } 2027 return getPackageName(cls.getName()); 2028 } 2029 2030 /** 2031 * <p>Gets the package name from a <code>String</code>.</p> 2032 * <p/> 2033 * <p>The string passed in is assumed to be a class name - it is not checked.</p> 2034 * <p>If the class is unpackaged, return an empty string.</p> 2035 * 2036 * @param className the className to get the package name for, may be <code>null</code> 2037 * @return the package name or an empty string 2038 */ 2039 public static String getPackageName(String className) { 2040 if (className == null || className.length() == 0) { 2041 return EMPTY_STRING; 2042 } 2043 2044 // Strip array encoding 2045 while (className.charAt(0) == '[') { 2046 className = className.substring(1); 2047 } 2048 // Strip Object type encoding 2049 if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';') { 2050 className = className.substring(1); 2051 } 2052 2053 int i = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR); 2054 if (i == -1) { 2055 return EMPTY_STRING; 2056 } 2057 return className.substring(0, i); 2058 } 2059 2060 public static class MethodDescriptor implements Comparable { 2061 private final String methodName; 2062 private final String[] paramTypes; 2063 private final int hashCode; 2064 private final int modifiers; 2065 2066 private static final String[] EMPTY_CLASS_PARAMETERS = new String[0]; 2067 2068 public static MethodDescriptor forMethod(Method method) { 2069 if (method == null) return null; 2070 return new MethodDescriptor(method.getName(), method.getParameterTypes(), method.getModifiers()); 2071 } 2072 2073 public static MethodDescriptor forMethod(MetaMethod method) { 2074 if (method == null) return null; 2075 CachedClass[] types = method.getParameterTypes(); 2076 String[] parameterTypes = new String[types.length]; 2077 for (int i = 0; i < types.length; i++) { 2078 parameterTypes[i] = types[i].getTheClass().getName(); 2079 } 2080 return new MethodDescriptor(method.getName(), parameterTypes, method.getModifiers()); 2081 } 2082 2083 public MethodDescriptor(String methodName) { 2084 this(methodName, EMPTY_CLASS_PARAMETERS, Modifier.PUBLIC); 2085 } 2086 2087 public MethodDescriptor(String methodName, int modifiers) { 2088 this(methodName, EMPTY_CLASS_PARAMETERS, modifiers); 2089 } 2090 2091 public MethodDescriptor(String methodName, Class[] paramTypes) { 2092 this(methodName, paramTypes, Modifier.PUBLIC); 2093 } 2094 2095 public MethodDescriptor(String methodName, String[] paramTypes) { 2096 this(methodName, paramTypes, Modifier.PUBLIC); 2097 } 2098 2099 public MethodDescriptor(String methodName, Class[] paramTypes, int modifiers) { 2100 this.methodName = methodName; 2101 if (paramTypes == null) { 2102 this.paramTypes = EMPTY_CLASS_PARAMETERS; 2103 } else { 2104 this.paramTypes = new String[paramTypes.length]; 2105 for (int i = 0; i < paramTypes.length; i++) { 2106 this.paramTypes[i] = paramTypes[i].getName(); 2107 } 2108 } 2109 this.modifiers = modifiers; 2110 2111 this.hashCode = methodName.length() + modifiers; 2112 } 2113 2114 public MethodDescriptor(String methodName, String[] paramTypes, int modifiers) { 2115 this.methodName = methodName; 2116 this.paramTypes = paramTypes == null ? EMPTY_CLASS_PARAMETERS : paramTypes; 2117 this.modifiers = modifiers; 2118 2119 this.hashCode = methodName.length() + modifiers; 2120 } 2121 2122 public String getName() { 2123 return methodName; 2124 } 2125 2126 public String[] getParameterTypes() { 2127 return paramTypes; 2128 } 2129 2130 public int getModifiers() { 2131 return modifiers; 2132 } 2133 2134 public boolean equals(Object obj) { 2135 if (!(obj instanceof MethodDescriptor)) { 2136 return false; 2137 } 2138 MethodDescriptor md = (MethodDescriptor) obj; 2139 2140 return methodName.equals(md.methodName) && 2141 modifiers == md.modifiers && 2142 java.util.Arrays.equals(paramTypes, md.paramTypes); 2143 } 2144 2145 public int hashCode() { 2146 return hashCode; 2147 } 2148 2149 public String toString() { 2150 StringBuilder b = new StringBuilder(); 2151 b.append(Modifier.toString(modifiers)).append(" "); 2152 b.append(methodName).append("("); 2153 for (int i = 0; i < paramTypes.length; i++) { 2154 if (i != 0) b.append(", "); 2155 b.append(paramTypes[i]); 2156 } 2157 b.append(")"); 2158 return b.toString(); 2159 } 2160 2161 public int compareTo(Object obj) { 2162 if (!(obj instanceof MethodDescriptor)) { 2163 return -1; 2164 } 2165 MethodDescriptor md = (MethodDescriptor) obj; 2166 2167 int c = methodName.compareTo(md.methodName); 2168 if (c != 0) return c; 2169 c = modifiers - md.modifiers; 2170 if (c != 0) return c; 2171 c = paramTypes.length - md.paramTypes.length; 2172 if (c != 0) return c; 2173 for (int i = 0; i < paramTypes.length; i++) { 2174 c = paramTypes[i].compareTo(md.paramTypes[i]); 2175 if (c != 0) return c; 2176 } 2177 2178 return 0; 2179 } 2180 } 2181 }`