GriffonClassUtils.java
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 != 0return 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 != 0return 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 == nullreturn 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 == nullreturn 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 == nullreturn 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 == nullreturn 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 == nullreturn 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 != nullreturn 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 == nullreturn 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(01).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 == nullreturn false;
1784         if (args.length != 0return false;
1785 
1786         if (name.startsWith(PROPERTY_GET_PREFIX)) {
1787             name = name.substring(3);
1788             if (name.length() && Character.isUpperCase(name.charAt(0))) return true;
1789         else if (name.startsWith(PROPERTY_IS_PREFIX)) {
1790             name = name.substring(2);
1791             if (name.length() && 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 == nullreturn false;
1843 
1844         if (name.startsWith(PROPERTY_SET_PREFIX)) {
1845             if (args.length != 1return false;
1846             name = name.substring(3);
1847             if (name.length() && 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 = (AdaptingMetaClassmc;
1860             mc = ((AdaptingMetaClassmc).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 == nullreturn false;
1910         if (map.containsKey(key)) {
1911             Object o = map.get(key);
1912             if (o == nullreturn false;
1913             else if (instanceof Boolean) {
1914                 return ((Booleano).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 (RuntimeExceptioncause;
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 (RuntimeExceptioncause;
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 (RuntimeExceptioncause;
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 (RuntimeExceptioncause;
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>'&#x2e;' == {@value}</code>.</p>
2383      */
2384     public static final char PACKAGE_SEPARATOR_CHAR = '.';
2385 
2386     /**
2387      <p>The package separator String: <code>"&#x2e;"</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 = (StringreverseAbbreviationMap.get(className);
2497         }
2498 
2499         int lastDotIdx = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR);
2500         int innerIdx = className.indexOf(
2501                 INNER_CLASS_SEPARATOR_CHAR, lastDotIdx == -: 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 == nullreturn null;
2579             return new MethodDescriptor(method.getName(), method.getParameterTypes(), method.getModifiers());
2580         }
2581 
2582         public static MethodDescriptor forMethod(MetaMethod method) {
2583             if (method == nullreturn 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 = (MethodDescriptorobj;
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 != 0b.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 = (MethodDescriptorobj;
2675 
2676             int c = methodName.compareTo(md.methodName);
2677             if (c != 0return c;
2678             c = modifiers - md.modifiers;
2679             if (c != 0return c;
2680             c = paramTypes.length - md.paramTypes.length;
2681             if (c != 0return c;
2682             for (int i = 0; i < paramTypes.length; i++) {
2683                 c = paramTypes[i].compareTo(md.paramTypes[i]);
2684                 if (c != 0return c;
2685             }
2686 
2687             return 0;
2688         }
2689     }
2690 }