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