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