001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.camel.util;
018
019import java.io.IOException;
020import java.io.InputStream;
021import java.lang.annotation.Annotation;
022import java.lang.reflect.AnnotatedElement;
023import java.lang.reflect.Array;
024import java.lang.reflect.Constructor;
025import java.lang.reflect.Field;
026import java.lang.reflect.Method;
027import java.lang.reflect.Modifier;
028import java.net.URL;
029import java.nio.charset.Charset;
030import java.util.ArrayList;
031import java.util.Arrays;
032import java.util.Collection;
033import java.util.Collections;
034import java.util.Enumeration;
035import java.util.Iterator;
036import java.util.List;
037import java.util.Locale;
038import java.util.Map;
039import java.util.Objects;
040import java.util.Optional;
041import java.util.function.Consumer;
042import java.util.function.Supplier;
043
044import org.w3c.dom.Node;
045import org.w3c.dom.NodeList;
046
047import org.slf4j.Logger;
048import org.slf4j.LoggerFactory;
049
050/**
051 * A number of useful helper methods for working with Objects
052 */
053public final class ObjectHelper {
054
055    private static final Logger LOG = LoggerFactory.getLogger(ObjectHelper.class);
056
057    /**
058     * Utility classes should not have a public constructor.
059     */
060    private ObjectHelper() {
061    }
062
063    /**
064     * A helper method for comparing objects for equality while handling nulls
065     */
066    public static boolean equal(Object a, Object b) {
067        return equal(a, b, false);
068    }
069
070    /**
071     * A helper method for comparing objects for equality while handling case insensitivity
072     */
073    public static boolean equalIgnoreCase(Object a, Object b) {
074        return equal(a, b, true);
075    }
076
077    /**
078     * A helper method for comparing objects for equality while handling nulls
079     */
080    public static boolean equal(final Object a, final Object b, final boolean ignoreCase) {
081        if (a == b) {
082            return true;
083        }
084
085        if (a == null || b == null) {
086            return false;
087        }
088
089        if (ignoreCase) {
090            if (a instanceof String && b instanceof String) {
091                return ((String) a).equalsIgnoreCase((String) b);
092            }
093        }
094
095        if (a.getClass().isArray() && b.getClass().isArray()) {
096            // uses array based equals
097            return Objects.deepEquals(a, b);
098        } else {
099            // use regular equals
100            return a.equals(b);
101        }
102    }
103
104    /**
105     * A helper method for comparing byte arrays for equality while handling nulls
106     */
107    public static boolean equalByteArray(byte[] a, byte[] b) {
108        return Arrays.equals(a, b);
109    }
110
111    /**
112     * Returns true if the given object is equal to any of the expected value
113     */
114    public static boolean isEqualToAny(Object object, Object... values) {
115        for (Object value : values) {
116            if (equal(object, value)) {
117                return true;
118            }
119        }
120        return false;
121    }
122
123    public static Boolean toBoolean(Object value) {
124        if (value instanceof Boolean) {
125            return (Boolean) value;
126        }
127        if (value instanceof byte[]) {
128            String str = new String((byte[]) value);
129            if ("true".equalsIgnoreCase(str) || "false".equalsIgnoreCase(str)) {
130                return Boolean.valueOf(str);
131            }
132        }
133        if (value instanceof String) {
134            // we only want to accept true or false as accepted values
135            String str = (String) value;
136            if ("true".equalsIgnoreCase(str) || "false".equalsIgnoreCase(str)) {
137                return Boolean.valueOf(str);
138            }
139        }
140        if (value instanceof Integer) {
141            return (Integer) value > 0 ? Boolean.TRUE : Boolean.FALSE;
142        }
143        return null;
144    }
145
146    /**
147     * Asserts whether the value is <b>not</b> <tt>null</tt>
148     *
149     * @param  value                    the value to test
150     * @param  name                     the key that resolved the value
151     * @return                          the passed {@code value} as is
152     * @throws IllegalArgumentException is thrown if assertion fails
153     */
154    public static <T> T notNull(T value, String name) {
155        if (value == null) {
156            throw new IllegalArgumentException(name + " must be specified");
157        }
158
159        return value;
160    }
161
162    /**
163     * Asserts whether the value is <b>not</b> <tt>null</tt>
164     *
165     * @param  value                    the value to test
166     * @param  on                       additional description to indicate where this problem occurred (appended as
167     *                                  toString())
168     * @param  name                     the key that resolved the value
169     * @return                          the passed {@code value} as is
170     * @throws IllegalArgumentException is thrown if assertion fails
171     */
172    public static <T> T notNull(T value, String name, Object on) {
173        if (on == null) {
174            notNull(value, name);
175        } else if (value == null) {
176            throw new IllegalArgumentException(name + " must be specified on: " + on);
177        }
178
179        return value;
180    }
181
182    /**
183     * Tests whether the value is <tt>null</tt> or an empty string or an empty collection/map.
184     *
185     * @param  value the value, if its a String it will be tested for text length as well
186     * @return       true if empty
187     */
188    public static boolean isEmpty(String value) {
189        return value == null || value.trim().isEmpty();
190    }
191
192    /**
193     * Tests whether the value is <tt>null</tt> or an an empty collection
194     *
195     * @param  value the value to test
196     * @return       true if empty
197     */
198    public static boolean isEmpty(Collection<?> value) {
199        return value == null || value.isEmpty();
200    }
201
202    /**
203     * Tests whether the value is <tt>null</tt> or an an empty map
204     *
205     * @param  value the value to test
206     * @return       true if empty
207     */
208    public static boolean isEmpty(Map<?, ?> value) {
209        return value == null || value.isEmpty();
210    }
211
212    /**
213     * Tests whether the value is <tt>null</tt>, an empty string or an empty collection/map.
214     *
215     * @param  value the value, if its a String it will be tested for text length as well
216     * @return       true if empty
217     */
218    public static <T> boolean isEmpty(T value) {
219        if (value == null) {
220            return true;
221        } else if (value instanceof String) {
222            return isEmpty((String) value);
223        } else if (value instanceof Collection) {
224            return isEmpty((Collection<?>) value);
225        } else if (value instanceof Map) {
226            return isEmpty((Map<?, ?>) value);
227        } else {
228            return false;
229        }
230    }
231
232    /**
233     * Tests whether the value is <b>not</b> <tt>null</tt>, an empty string or an empty collection/map.
234     *
235     * @param  value the value, if its a String it will be tested for text length as well
236     * @return       true if <b>not</b> empty
237     */
238    public static <T> boolean isNotEmpty(T value) {
239        return !isEmpty(value);
240    }
241
242    /**
243     * Tests whether the value is <b>not</b> <tt>null</tt> or an empty string
244     *
245     * @param  value the value, if its a String it will be tested for text length as well
246     * @return       true if <b>not</b> empty
247     */
248    public static boolean isNotEmpty(String value) {
249        return !isEmpty(value);
250    }
251
252    /**
253     * Tests whether the value is <tt>null</tt> or an an empty collection
254     *
255     * @param  value the value to test
256     * @return       true if empty
257     */
258    public static boolean isNotEmpty(Collection<?> value) {
259        return !isEmpty(value);
260    }
261
262    /**
263     * Tests whether the value is <tt>null</tt> or an an empty map
264     *
265     * @param  value the value to test
266     * @return       true if empty
267     */
268    public static boolean isNotEmpty(Map<?, ?> value) {
269        return !isEmpty(value);
270    }
271
272    /**
273     * Returns the first non null object <tt>null</tt>.
274     *
275     * @param  values the values
276     * @return        an Optional
277     */
278    public static Optional<Object> firstNotNull(Object... values) {
279        for (Object value : values) {
280            if (value != null) {
281                return Optional.of(value);
282            }
283        }
284
285        return Optional.empty();
286    }
287
288    /**
289     * Tests whether the value is <tt>null</tt>, an empty string, an empty collection or a map
290     *
291     * @param value    the value, if its a String it will be tested for text length as well
292     * @param supplier the supplier, the supplier to be used to get a value if value is null
293     */
294    public static <T> T supplyIfEmpty(T value, Supplier<T> supplier) {
295        org.apache.camel.util.ObjectHelper.notNull(supplier, "Supplier");
296        if (isNotEmpty(value)) {
297            return value;
298        }
299
300        return supplier.get();
301    }
302
303    /**
304     * Tests whether the value is <b>not</b> <tt>null</tt>, an empty string, an empty collection or a map
305     *
306     * @param value    the value, if its a String it will be tested for text length as well
307     * @param consumer the consumer, the operation to be executed against value if not empty
308     */
309    public static <T> void ifNotEmpty(T value, Consumer<T> consumer) {
310        if (isNotEmpty(value)) {
311            consumer.accept(value);
312        }
313    }
314
315    /**
316     * Returns the predicate matching boolean on a {@link List} result set where if the first element is a boolean its
317     * value is used otherwise this method returns true if the collection is not empty
318     *
319     * @return <tt>true</tt> if the first element is a boolean and its value is true or if the list is non empty
320     */
321    public static boolean matches(List<?> list) {
322        if (!list.isEmpty()) {
323            Object value = list.get(0);
324            if (value instanceof Boolean) {
325                return (Boolean) value;
326            } else {
327                // lets assume non-empty results are true
328                return true;
329            }
330        }
331        return false;
332    }
333
334    /**
335     * A helper method to access a system property, catching any security exceptions
336     *
337     * @param  name         the name of the system property required
338     * @param  defaultValue the default value to use if the property is not available or a security exception prevents
339     *                      access
340     * @return              the system property value or the default value if the property is not available or security
341     *                      does not allow its access
342     */
343    public static String getSystemProperty(String name, String defaultValue) {
344        try {
345            return System.getProperty(name, defaultValue);
346        } catch (Exception e) {
347            LOG.debug("Caught security exception accessing system property: {}. Will use default value: {}",
348                    name, defaultValue, e);
349
350            return defaultValue;
351        }
352    }
353
354    /**
355     * A helper method to access a boolean system property, catching any security exceptions
356     *
357     * @param  name         the name of the system property required
358     * @param  defaultValue the default value to use if the property is not available or a security exception prevents
359     *                      access
360     * @return              the boolean representation of the system property value or the default value if the property
361     *                      is not available or security does not allow its access
362     */
363    public static boolean getSystemProperty(String name, Boolean defaultValue) {
364        String result = getSystemProperty(name, defaultValue.toString());
365        return Boolean.parseBoolean(result);
366    }
367
368    /**
369     * Returns the type name of the given type or null if the type variable is null
370     */
371    public static String name(Class<?> type) {
372        return type != null ? type.getName() : null;
373    }
374
375    /**
376     * Returns the type name of the given value
377     */
378    public static String className(Object value) {
379        return name(value != null ? value.getClass() : null);
380    }
381
382    /**
383     * Returns the canonical type name of the given value
384     */
385    public static String classCanonicalName(Object value) {
386        if (value != null) {
387            return value.getClass().getCanonicalName();
388        } else {
389            return null;
390        }
391    }
392
393    /**
394     * Attempts to load the given class name using the thread context class loader or the class loader used to load this
395     * class
396     *
397     * @param  name the name of the class to load
398     * @return      the class or <tt>null</tt> if it could not be loaded
399     */
400    public static Class<?> loadClass(String name) {
401        return loadClass(name, ObjectHelper.class.getClassLoader());
402    }
403
404    /**
405     * Attempts to load the given class name using the thread context class loader or the given class loader
406     *
407     * @param  name   the name of the class to load
408     * @param  loader the class loader to use after the thread context class loader
409     * @return        the class or <tt>null</tt> if it could not be loaded
410     */
411    public static Class<?> loadClass(String name, ClassLoader loader) {
412        return loadClass(name, loader, false);
413    }
414
415    /**
416     * Attempts to load the given class name using the thread context class loader or the given class loader
417     *
418     * @param  name       the name of the class to load
419     * @param  loader     the class loader to use after the thread context class loader
420     * @param  needToWarn when <tt>true</tt> logs a warning when a class with the given name could not be loaded
421     * @return            the class or <tt>null</tt> if it could not be loaded
422     */
423    public static Class<?> loadClass(String name, ClassLoader loader, boolean needToWarn) {
424        // must clean the name so its pure java name, eg removing \n or whatever people can do in the Spring XML
425        name = StringHelper.normalizeClassName(name);
426        if (org.apache.camel.util.ObjectHelper.isEmpty(name)) {
427            return null;
428        }
429
430        boolean array = false;
431
432        // Try simple type first
433        Class<?> clazz = loadSimpleType(name);
434        if (clazz == null) {
435            // special for array as we need to load the class and then after that instantiate an array class type
436            if (name.endsWith("[]")) {
437                name = name.substring(0, name.length() - 2);
438                array = true;
439            }
440        }
441
442        if (clazz == null) {
443            // try context class loader
444            clazz = doLoadClass(name, Thread.currentThread().getContextClassLoader());
445        }
446        if (clazz == null) {
447            // then the provided loader
448            clazz = doLoadClass(name, loader);
449        }
450        if (clazz == null) {
451            // and fallback to the loader the loaded the ObjectHelper class
452            clazz = doLoadClass(name, ObjectHelper.class.getClassLoader());
453        }
454        if (clazz != null && array) {
455            Object arr = Array.newInstance(clazz, 0);
456            clazz = arr.getClass();
457        }
458
459        if (clazz == null) {
460            if (needToWarn) {
461                LOG.warn("Cannot find class: {}", name);
462            } else {
463                LOG.debug("Cannot find class: {}", name);
464            }
465        }
466
467        return clazz;
468    }
469
470    /**
471     * Load a simple type
472     *
473     * @param  name the name of the class to load
474     * @return      the class or <tt>null</tt> if it could not be loaded
475     */
476    //CHECKSTYLE:OFF
477    public static Class<?> loadSimpleType(String name) {
478        // special for byte[] or Object[] as its common to use
479        if ("java.lang.byte[]".equals(name) || "byte[]".equals(name)) {
480            return byte[].class;
481        } else if ("java.lang.Byte[]".equals(name) || "Byte[]".equals(name)) {
482            return Byte[].class;
483        } else if ("java.lang.Object[]".equals(name) || "Object[]".equals(name)) {
484            return Object[].class;
485        } else if ("java.lang.String[]".equals(name) || "String[]".equals(name)) {
486            return String[].class;
487            // and these is common as well
488        } else if ("java.lang.String".equals(name) || "String".equals(name)) {
489            return String.class;
490        } else if ("java.lang.Boolean".equals(name) || "Boolean".equals(name)) {
491            return Boolean.class;
492        } else if ("boolean".equals(name)) {
493            return boolean.class;
494        } else if ("java.lang.Integer".equals(name) || "Integer".equals(name)) {
495            return Integer.class;
496        } else if ("int".equals(name)) {
497            return int.class;
498        } else if ("java.lang.Long".equals(name) || "Long".equals(name)) {
499            return Long.class;
500        } else if ("long".equals(name)) {
501            return long.class;
502        } else if ("java.lang.Short".equals(name) || "Short".equals(name)) {
503            return Short.class;
504        } else if ("short".equals(name)) {
505            return short.class;
506        } else if ("java.lang.Byte".equals(name) || "Byte".equals(name)) {
507            return Byte.class;
508        } else if ("byte".equals(name)) {
509            return byte.class;
510        } else if ("java.lang.Float".equals(name) || "Float".equals(name)) {
511            return Float.class;
512        } else if ("float".equals(name)) {
513            return float.class;
514        } else if ("java.lang.Double".equals(name) || "Double".equals(name)) {
515            return Double.class;
516        } else if ("double".equals(name)) {
517            return double.class;
518        } else if ("java.lang.Character".equals(name) || "Character".equals(name)) {
519            return Character.class;
520        } else if ("char".equals(name)) {
521            return char.class;
522        }
523        return null;
524    }
525    //CHECKSTYLE:ON
526
527    /**
528     * Loads the given class with the provided classloader (may be null). Will ignore any class not found and return
529     * null.
530     *
531     * @param  name   the name of the class to load
532     * @param  loader a provided loader (may be null)
533     * @return        the class, or null if it could not be loaded
534     */
535    private static Class<?> doLoadClass(String name, ClassLoader loader) {
536        StringHelper.notEmpty(name, "name");
537        if (loader == null) {
538            return null;
539        }
540
541        try {
542            LOG.trace("Loading class: {} using classloader: {}", name, loader);
543            return loader.loadClass(name);
544        } catch (ClassNotFoundException e) {
545            if (LOG.isTraceEnabled()) {
546                LOG.trace("Cannot load class: {} using classloader: {}", name, loader, e);
547            }
548        }
549
550        return null;
551    }
552
553    /**
554     * Attempts to load the given resource as a stream using the thread context class loader or the class loader used to
555     * load this class
556     *
557     * @param  name the name of the resource to load
558     * @return      the stream or null if it could not be loaded
559     */
560    public static InputStream loadResourceAsStream(String name) {
561        return loadResourceAsStream(name, null);
562    }
563
564    /**
565     * Attempts to load the given resource as a stream using first the given class loader, then the thread context class
566     * loader and finally the class loader used to load this class
567     *
568     * @param  name   the name of the resource to load
569     * @param  loader optional classloader to attempt first
570     * @return        the stream or null if it could not be loaded
571     */
572    public static InputStream loadResourceAsStream(String name, ClassLoader loader) {
573        try {
574            URL res = loadResourceAsURL(name, loader);
575            return res != null ? res.openStream() : null;
576        } catch (IOException e) {
577            return null;
578        }
579    }
580
581    /**
582     * Attempts to load the given resource as a stream using the thread context class loader or the class loader used to
583     * load this class
584     *
585     * @param  name the name of the resource to load
586     * @return      the stream or null if it could not be loaded
587     */
588    public static URL loadResourceAsURL(String name) {
589        return loadResourceAsURL(name, null);
590    }
591
592    /**
593     * Attempts to load the given resource as a stream using the thread context class loader or the class loader used to
594     * load this class
595     *
596     * @param  name   the name of the resource to load
597     * @param  loader optional classloader to attempt first
598     * @return        the stream or null if it could not be loaded
599     */
600    public static URL loadResourceAsURL(String name, ClassLoader loader) {
601
602        URL url = null;
603        String resolvedName = resolveUriPath(name);
604
605        // #1 First, try the given class loader
606
607        if (loader != null) {
608            url = loader.getResource(resolvedName);
609            if (url != null) {
610                return url;
611            }
612        }
613
614        // #2 Next, is the TCCL
615
616        ClassLoader tccl = Thread.currentThread().getContextClassLoader();
617        if (tccl != null) {
618
619            url = tccl.getResource(resolvedName);
620            if (url != null) {
621                return url;
622            }
623
624            // #3 The TCCL may be able to see camel-core, but not META-INF resources
625
626            try {
627
628                Class<?> clazz = tccl.loadClass("org.apache.camel.impl.DefaultCamelContext");
629                url = clazz.getClassLoader().getResource(resolvedName);
630                if (url != null) {
631                    return url;
632                }
633
634            } catch (ClassNotFoundException e) {
635                // ignore
636            }
637        }
638
639        // #4 Last, for the unlikely case that stuff can be loaded from camel-util
640
641        url = ObjectHelper.class.getClassLoader().getResource(resolvedName);
642        if (url != null) {
643            return url;
644        }
645
646        url = ObjectHelper.class.getResource(resolvedName);
647        return url;
648    }
649
650    /**
651     * Attempts to load the given resources from the given package name using the thread context class loader or the
652     * class loader used to load this class
653     *
654     * @param  uri the name of the package to load its resources
655     * @return     the URLs for the resources or null if it could not be loaded
656     */
657    public static Enumeration<URL> loadResourcesAsURL(String uri) {
658        return loadResourcesAsURL(uri, null);
659    }
660
661    /**
662     * Attempts to load the given resources from the given package name using the thread context class loader or the
663     * class loader used to load this class
664     *
665     * @param  uri    the name of the package to load its resources
666     * @param  loader optional classloader to attempt first
667     * @return        the URLs for the resources or null if it could not be loaded
668     */
669    public static Enumeration<URL> loadResourcesAsURL(String uri, ClassLoader loader) {
670
671        Enumeration<URL> res = null;
672
673        // #1 First, try the given class loader
674
675        if (loader != null) {
676            try {
677                res = loader.getResources(uri);
678                if (res != null) {
679                    return res;
680                }
681            } catch (IOException e) {
682                // ignore
683            }
684        }
685
686        // #2 Next, is the TCCL
687
688        ClassLoader tccl = Thread.currentThread().getContextClassLoader();
689        if (tccl != null) {
690
691            try {
692                res = tccl.getResources(uri);
693                if (res != null) {
694                    return res;
695                }
696            } catch (IOException e1) {
697                // ignore
698            }
699
700            // #3 The TCCL may be able to see camel-core, but not META-INF resources
701
702            try {
703
704                Class<?> clazz = tccl.loadClass("org.apache.camel.impl.DefaultCamelContext");
705                res = clazz.getClassLoader().getResources(uri);
706                if (res != null) {
707                    return res;
708                }
709
710            } catch (ClassNotFoundException | IOException e) {
711                // ignore
712            }
713        }
714
715        // #4 Last, for the unlikely case that stuff can be loaded from camel-util
716
717        try {
718            res = ObjectHelper.class.getClassLoader().getResources(uri);
719        } catch (IOException e) {
720            // ignore
721        }
722
723        return res;
724    }
725
726    /**
727     * Helper operation used to remove relative path notation from resources. Most critical for resources on the
728     * Classpath as resource loaders will not resolve the relative paths correctly.
729     *
730     * @param  name the name of the resource to load
731     * @return      the modified or unmodified string if there were no changes
732     */
733    private static String resolveUriPath(String name) {
734        // compact the path and use / as separator as that's used for loading resources on the classpath
735        return FileUtil.compactPath(name, '/');
736    }
737
738    /**
739     * Tests whether the target method overrides the source method.
740     * <p/>
741     * Tests whether they have the same name, return type, and parameter list.
742     *
743     * @param  source the source method
744     * @param  target the target method
745     * @return        <tt>true</tt> if it override, <tt>false</tt> otherwise
746     */
747    public static boolean isOverridingMethod(Method source, Method target) {
748        return isOverridingMethod(source, target, true);
749    }
750
751    /**
752     * Tests whether the target method overrides the source method.
753     * <p/>
754     * Tests whether they have the same name, return type, and parameter list.
755     *
756     * @param  source the source method
757     * @param  target the target method
758     * @param  exact  <tt>true</tt> if the override must be exact same types, <tt>false</tt> if the types should be
759     *                assignable
760     * @return        <tt>true</tt> if it override, <tt>false</tt> otherwise
761     */
762    public static boolean isOverridingMethod(Method source, Method target, boolean exact) {
763        return isOverridingMethod(target.getDeclaringClass(), source, target, exact);
764    }
765
766    /**
767     * Tests whether the target method overrides the source method from the inheriting class.
768     * <p/>
769     * Tests whether they have the same name, return type, and parameter list.
770     *
771     * @param  inheritingClass the class inheriting the target method overriding the source method
772     * @param  source          the source method
773     * @param  target          the target method
774     * @param  exact           <tt>true</tt> if the override must be exact same types, <tt>false</tt> if the types
775     *                         should be assignable
776     * @return                 <tt>true</tt> if it override, <tt>false</tt> otherwise
777     */
778    public static boolean isOverridingMethod(Class<?> inheritingClass, Method source, Method target, boolean exact) {
779
780        if (source.equals(target)) {
781            return true;
782        } else if (target.getDeclaringClass().isAssignableFrom(source.getDeclaringClass())) {
783            return false;
784        } else if (!source.getDeclaringClass().isAssignableFrom(inheritingClass)
785                || !target.getDeclaringClass().isAssignableFrom(inheritingClass)) {
786            return false;
787        }
788
789        if (!source.getName().equals(target.getName())) {
790            return false;
791        }
792
793        if (exact) {
794            if (!source.getReturnType().equals(target.getReturnType())) {
795                return false;
796            }
797        } else {
798            if (!source.getReturnType().isAssignableFrom(target.getReturnType())) {
799                boolean b1 = source.isBridge();
800                boolean b2 = target.isBridge();
801                // must not be bridge methods
802                if (!b1 && !b2) {
803                    return false;
804                }
805            }
806        }
807
808        // must have same number of parameter types
809        if (source.getParameterCount() != target.getParameterCount()) {
810            return false;
811        }
812
813        Class<?>[] sourceTypes = source.getParameterTypes();
814        Class<?>[] targetTypes = target.getParameterTypes();
815        // test if parameter types is the same as well
816        for (int i = 0; i < source.getParameterCount(); i++) {
817            if (exact) {
818                if (!(sourceTypes[i].equals(targetTypes[i]))) {
819                    return false;
820                }
821            } else {
822                if (!(sourceTypes[i].isAssignableFrom(targetTypes[i]))) {
823                    boolean b1 = source.isBridge();
824                    boolean b2 = target.isBridge();
825                    // must not be bridge methods
826                    if (!b1 && !b2) {
827                        return false;
828                    }
829                }
830            }
831        }
832
833        // the have same name, return type and parameter list, so its overriding
834        return true;
835    }
836
837    /**
838     * Returns a list of methods which are annotated with the given annotation
839     *
840     * @param  type           the type to reflect on
841     * @param  annotationType the annotation type
842     * @return                a list of the methods found
843     */
844    public static List<Method> findMethodsWithAnnotation(
845            Class<?> type,
846            Class<? extends Annotation> annotationType) {
847        return findMethodsWithAnnotation(type, annotationType, false);
848    }
849
850    /**
851     * Returns a list of methods which are annotated with the given annotation
852     *
853     * @param  type                 the type to reflect on
854     * @param  annotationType       the annotation type
855     * @param  checkMetaAnnotations check for meta annotations
856     * @return                      a list of the methods found
857     */
858    public static List<Method> findMethodsWithAnnotation(
859            Class<?> type,
860            Class<? extends Annotation> annotationType,
861            boolean checkMetaAnnotations) {
862        List<Method> answer = new ArrayList<>();
863        do {
864            Method[] methods = type.getDeclaredMethods();
865            for (Method method : methods) {
866                if (hasAnnotation(method, annotationType, checkMetaAnnotations)) {
867                    answer.add(method);
868                }
869            }
870            type = type.getSuperclass();
871        } while (type != null);
872        return answer;
873    }
874
875    /**
876     * Checks if a Class or Method are annotated with the given annotation
877     *
878     * @param  elem                 the Class or Method to reflect on
879     * @param  annotationType       the annotation type
880     * @param  checkMetaAnnotations check for meta annotations
881     * @return                      true if annotations is present
882     */
883    public static boolean hasAnnotation(
884            AnnotatedElement elem, Class<? extends Annotation> annotationType,
885            boolean checkMetaAnnotations) {
886        if (elem.isAnnotationPresent(annotationType)) {
887            return true;
888        }
889        if (checkMetaAnnotations) {
890            for (Annotation a : elem.getAnnotations()) {
891                for (Annotation meta : a.annotationType().getAnnotations()) {
892                    if (meta.annotationType().getName().equals(annotationType.getName())) {
893                        return true;
894                    }
895                }
896            }
897        }
898        return false;
899    }
900
901    /**
902     * Turns the given object arrays into a meaningful string
903     *
904     * @param  objects an array of objects or null
905     * @return         a meaningful string
906     */
907    public static String asString(Object[] objects) {
908        if (objects == null) {
909            return "null";
910        } else {
911            StringBuilder buffer = new StringBuilder("{");
912            int counter = 0;
913            for (Object object : objects) {
914                if (counter++ > 0) {
915                    buffer.append(", ");
916                }
917                String text = (object == null) ? "null" : object.toString();
918                buffer.append(text);
919            }
920            buffer.append("}");
921            return buffer.toString();
922        }
923    }
924
925    /**
926     * Returns true if a class is assignable from another class like the {@link Class#isAssignableFrom(Class)} method
927     * but which also includes coercion between primitive types to deal with Java 5 primitive type wrapping
928     */
929    public static boolean isAssignableFrom(Class<?> a, Class<?> b) {
930        a = convertPrimitiveTypeToWrapperType(a);
931        b = convertPrimitiveTypeToWrapperType(b);
932        return a.isAssignableFrom(b);
933    }
934
935    /**
936     * Returns if the given {@code clazz} type is a Java primitive array type.
937     *
938     * @param  clazz the Java type to be checked
939     * @return       {@code true} if the given type is a Java primitive array type
940     */
941    public static boolean isPrimitiveArrayType(Class<?> clazz) {
942        if (clazz != null && clazz.isArray()) {
943            return clazz.getComponentType().isPrimitive();
944        }
945        return false;
946    }
947
948    /**
949     * Checks if the given class has a subclass (extends or implements)
950     * 
951     * @param clazz    the class
952     * @param subClass the subclass (class or interface)
953     */
954    public static boolean isSubclass(Class<?> clazz, Class<?> subClass) {
955        if (clazz == subClass) {
956            return true;
957        }
958        if (clazz == null || subClass == null) {
959            return false;
960        }
961        for (Class<?> aClass = clazz; aClass != null; aClass = aClass.getSuperclass()) {
962            if (aClass == subClass) {
963                return true;
964            }
965            if (subClass.isInterface()) {
966                Class<?>[] interfaces = aClass.getInterfaces();
967                for (Class<?> anInterface : interfaces) {
968                    if (isSubclass(anInterface, subClass)) {
969                        return true;
970                    }
971                }
972            }
973        }
974        return false;
975    }
976
977    /**
978     * Used by camel-bean
979     */
980    public static int arrayLength(Object[] pojo) {
981        return pojo.length;
982    }
983
984    /**
985     * Converts primitive types such as int to its wrapper type like {@link Integer}
986     */
987    public static Class<?> convertPrimitiveTypeToWrapperType(Class<?> type) {
988        Class<?> rc = type;
989        if (type.isPrimitive()) {
990            if (type == int.class) {
991                rc = Integer.class;
992            } else if (type == long.class) {
993                rc = Long.class;
994            } else if (type == double.class) {
995                rc = Double.class;
996            } else if (type == float.class) {
997                rc = Float.class;
998            } else if (type == short.class) {
999                rc = Short.class;
1000            } else if (type == byte.class) {
1001                rc = Byte.class;
1002            } else if (type == boolean.class) {
1003                rc = Boolean.class;
1004            } else if (type == char.class) {
1005                rc = Character.class;
1006            }
1007        }
1008        return rc;
1009    }
1010
1011    /**
1012     * Converts wrapper type like {@link Integer} to its primitive type, i.e. int.
1013     */
1014    public static Class<?> convertWrapperTypeToPrimitiveType(Class<?> type) {
1015        Class<?> rc = type;
1016        if (type == Integer.class) {
1017            rc = int.class;
1018        } else if (type == Long.class) {
1019            rc = long.class;
1020        } else if (type == Double.class) {
1021            rc = double.class;
1022        } else if (type == Float.class) {
1023            rc = float.class;
1024        } else if (type == Short.class) {
1025            rc = short.class;
1026        } else if (type == Byte.class) {
1027            rc = byte.class;
1028        } else if (type == Boolean.class) {
1029            rc = boolean.class;
1030        } else if (type == Character.class) {
1031            rc = char.class;
1032        }
1033        return rc;
1034    }
1035
1036    /**
1037     * Helper method to return the default character set name
1038     */
1039    public static String getDefaultCharacterSet() {
1040        return Charset.defaultCharset().name();
1041    }
1042
1043    /**
1044     * Returns the Java Bean property name of the given method, if it is a setter
1045     */
1046    public static String getPropertyName(Method method) {
1047        String propertyName = method.getName();
1048        if (propertyName.startsWith("set") && method.getParameterCount() == 1) {
1049            propertyName = propertyName.substring(3, 4).toLowerCase(Locale.ENGLISH) + propertyName.substring(4);
1050        }
1051        return propertyName;
1052    }
1053
1054    /**
1055     * Returns true if the given collection of annotations matches the given type
1056     */
1057    public static boolean hasAnnotation(Annotation[] annotations, Class<?> type) {
1058        for (Annotation annotation : annotations) {
1059            if (type.isInstance(annotation)) {
1060                return true;
1061            }
1062        }
1063        return false;
1064    }
1065
1066    /**
1067     * Gets the annotation from the given instance.
1068     *
1069     * @param  instance the instance
1070     * @param  type     the annotation
1071     * @return          the annotation, or <tt>null</tt> if the instance does not have the given annotation
1072     */
1073    public static <A extends java.lang.annotation.Annotation> A getAnnotation(Object instance, Class<A> type) {
1074        return instance.getClass().getAnnotation(type);
1075    }
1076
1077    /**
1078     * Converts the given value to the required type or throw a meaningful exception
1079     */
1080    @SuppressWarnings("unchecked")
1081    public static <T> T cast(Class<T> toType, Object value) {
1082        if (toType == boolean.class) {
1083            return (T) cast(Boolean.class, value);
1084        } else if (toType.isPrimitive()) {
1085            Class<?> newType = convertPrimitiveTypeToWrapperType(toType);
1086            if (newType != toType) {
1087                return (T) cast(newType, value);
1088            }
1089        }
1090        try {
1091            return toType.cast(value);
1092        } catch (ClassCastException e) {
1093            throw new IllegalArgumentException(
1094                    "Failed to convert: "
1095                                               + value + " to type: " + toType.getName() + " due to: " + e,
1096                    e);
1097        }
1098    }
1099
1100    /**
1101     * Does the given class have a default public no-arg constructor.
1102     */
1103    public static boolean hasDefaultPublicNoArgConstructor(Class<?> type) {
1104        // getConstructors() returns only public constructors
1105        for (Constructor<?> ctr : type.getConstructors()) {
1106            if (ctr.getParameterCount() == 0) {
1107                return true;
1108            }
1109        }
1110        return false;
1111    }
1112
1113    /**
1114     * Does the given class have a default no-arg constructor (public or inherited).
1115     */
1116    public static boolean hasDefaultNoArgConstructor(Class<?> type) {
1117        if (hasDefaultPublicNoArgConstructor(type)) {
1118            return true;
1119        }
1120        for (Constructor<?> ctr : type.getDeclaredConstructors()) {
1121            if (!Modifier.isPrivate(ctr.getModifiers()) && ctr.getParameterCount() == 0) {
1122                return true;
1123            }
1124        }
1125        return false;
1126    }
1127
1128    /**
1129     * Returns the type of the given object or null if the value is null
1130     */
1131    public static Object type(Object bean) {
1132        return bean != null ? bean.getClass() : null;
1133    }
1134
1135    /**
1136     * Evaluate the value as a predicate which attempts to convert the value to a boolean otherwise true is returned if
1137     * the value is not null
1138     */
1139    public static boolean evaluateValuePredicate(Object value) {
1140        if (value instanceof Boolean) {
1141            return (Boolean) value;
1142        } else if (value instanceof String) {
1143            String str = ((String) value).trim();
1144            if (str.isEmpty()) {
1145                return false;
1146            } else if ("true".equalsIgnoreCase(str)) {
1147                return true;
1148            } else if ("false".equalsIgnoreCase(str)) {
1149                return false;
1150            }
1151        } else if (value instanceof NodeList) {
1152            // is it an empty dom with empty attributes
1153            if (value instanceof Node && ((Node) value).hasAttributes()) {
1154                return true;
1155            }
1156            NodeList list = (NodeList) value;
1157            return list.getLength() > 0;
1158        } else if (value instanceof Collection) {
1159            // is it an empty collection
1160            return !((Collection<?>) value).isEmpty();
1161        }
1162        return value != null;
1163    }
1164
1165    /**
1166     * Creates an Iterable to walk the exception from the bottom up (the last caused by going upwards to the root
1167     * exception).
1168     *
1169     * @see              java.lang.Iterable
1170     * @param  exception the exception
1171     * @return           the Iterable
1172     */
1173    public static Iterable<Throwable> createExceptionIterable(Throwable exception) {
1174        List<Throwable> throwables = new ArrayList<>();
1175
1176        Throwable current = exception;
1177        // spool to the bottom of the caused by tree
1178        while (current != null) {
1179            throwables.add(current);
1180            current = current.getCause();
1181        }
1182        Collections.reverse(throwables);
1183
1184        return throwables;
1185    }
1186
1187    /**
1188     * Creates an Iterator to walk the exception from the bottom up (the last caused by going upwards to the root
1189     * exception).
1190     *
1191     * @see              Iterator
1192     * @param  exception the exception
1193     * @return           the Iterator
1194     */
1195    public static Iterator<Throwable> createExceptionIterator(Throwable exception) {
1196        return createExceptionIterable(exception).iterator();
1197    }
1198
1199    /**
1200     * Retrieves the given exception type from the exception.
1201     * <p/>
1202     * Is used to get the caused exception that typically have been wrapped in some sort of Camel wrapper exception
1203     * <p/>
1204     * The strategy is to look in the exception hierarchy to find the first given cause that matches the type. Will
1205     * start from the bottom (the real cause) and walk upwards.
1206     *
1207     * @param  type      the exception type wanted to retrieve
1208     * @param  exception the caused exception
1209     * @return           the exception found (or <tt>null</tt> if not found in the exception hierarchy)
1210     */
1211    public static <T> T getException(Class<T> type, Throwable exception) {
1212        if (exception == null) {
1213            return null;
1214        }
1215
1216        //check the suppressed exception first
1217        for (Throwable throwable : exception.getSuppressed()) {
1218            if (type.isInstance(throwable)) {
1219                return type.cast(throwable);
1220            }
1221        }
1222
1223        // walk the hierarchy and look for it
1224        for (final Throwable throwable : createExceptionIterable(exception)) {
1225            if (type.isInstance(throwable)) {
1226                return type.cast(throwable);
1227            }
1228        }
1229
1230        // not found
1231        return null;
1232    }
1233
1234    public static String getIdentityHashCode(Object object) {
1235        return "0x" + Integer.toHexString(System.identityHashCode(object));
1236    }
1237
1238    /**
1239     * Lookup the constant field on the given class with the given name
1240     *
1241     * @param  clazz the class
1242     * @param  name  the name of the field to lookup
1243     * @return       the value of the constant field, or <tt>null</tt> if not found
1244     */
1245    public static String lookupConstantFieldValue(Class<?> clazz, String name) {
1246        if (clazz == null) {
1247            return null;
1248        }
1249
1250        // remove leading dots
1251        if (name.startsWith(".")) {
1252            name = name.substring(1);
1253        }
1254
1255        for (Field field : clazz.getFields()) {
1256            if (field.getName().equals(name)) {
1257                try {
1258                    Object v = field.get(null);
1259                    return v.toString();
1260                } catch (IllegalAccessException e) {
1261                    // ignore
1262                    return null;
1263                }
1264            }
1265        }
1266
1267        return null;
1268    }
1269
1270    /**
1271     * Is the given value a numeric NaN type
1272     *
1273     * @param  value the value
1274     * @return       <tt>true</tt> if its a {@link Float#NaN} or {@link Double#NaN}.
1275     */
1276    public static boolean isNaN(Object value) {
1277        return value instanceof Float && ((Float) value).isNaN()
1278                || value instanceof Double && ((Double) value).isNaN();
1279    }
1280
1281    /**
1282     * Wraps the caused exception in a {@link RuntimeException} if its not already such an exception.
1283     *
1284     * @param      e the caused exception
1285     * @return       the wrapper exception
1286     * @deprecated   Use {@link org.apache.camel.RuntimeCamelException#wrapRuntimeCamelException} instead
1287     */
1288    @Deprecated
1289    public static RuntimeException wrapRuntimeCamelException(Throwable e) {
1290        try {
1291            Class<? extends RuntimeException> clazz = (Class) Class.forName("org.apache.camel.RuntimeException");
1292            if (clazz.isInstance(e)) {
1293                // don't double wrap
1294                return clazz.cast(e);
1295            } else {
1296                return clazz.getConstructor(Throwable.class).newInstance(e);
1297            }
1298        } catch (Throwable t) {
1299            // ignore
1300        }
1301        if (e instanceof RuntimeException) {
1302            // don't double wrap
1303            return (RuntimeException) e;
1304        } else {
1305            return new RuntimeException(e);
1306        }
1307    }
1308
1309    /**
1310     * Turns the input array to a list of objects.
1311     * 
1312     * @param  objects an array of objects or null
1313     * @return         an object list
1314     */
1315    public static List<Object> asList(Object[] objects) {
1316        return objects != null ? Arrays.asList(objects) : Collections.emptyList();
1317    }
1318
1319    /**
1320     * Adds the value to the list at the given index
1321     */
1322    public static void addListByIndex(List<Object> list, int idx, Object value) {
1323        if (idx < list.size()) {
1324            list.set(idx, value);
1325        } else if (idx == list.size()) {
1326            list.add(value);
1327        } else {
1328            // If the list implementation is based on an array, we
1329            // can increase tha capacity to the required value to
1330            // avoid potential re-allocation when invoking List::add.
1331            //
1332            // Note that ArrayList is the default List impl that
1333            // is automatically created if the property is null.
1334            if (list instanceof ArrayList) {
1335                ((ArrayList<?>) list).ensureCapacity(idx + 1);
1336            }
1337            while (list.size() < idx) {
1338                list.add(null);
1339            }
1340            list.add(idx, value);
1341        }
1342    }
1343
1344}