001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.internal;
014
015import java.lang.reflect.*;
016import java.util.function.*;
017
018import org.apache.juneau.*;
019import org.apache.juneau.reflect.*;
020
021/**
022 * Class-related utility methods.
023 *
024 * <h5 class='section'>See Also:</h5><ul>
025
026 * </ul>
027 */
028public final class ClassUtils {
029
030   /**
031    * Predicate check to filter out void classes.
032    */
033   public static final Predicate<Class<?>> NOT_VOID = x -> isNotVoid(x);
034
035   /**
036    * Returns the class types for the specified arguments.
037    *
038    * @param args The objects we're getting the classes of.
039    * @return The classes of the arguments.
040    */
041   public static Class<?>[] getClasses(Object...args) {
042      Class<?>[] pt = new Class<?>[args.length];
043      for (int i = 0; i < args.length; i++)
044         pt[i] = args[i] == null ? null : args[i].getClass();
045      return pt;
046   }
047
048   /**
049    * Matches arguments to a list of parameter types.
050    *
051    * <p>
052    * Extra parameters are ignored.
053    * <br>Missing parameters are left null.
054    *
055    * @param paramTypes The parameter types.
056    * @param args The arguments to match to the parameter types.
057    * @return
058    *    An array of parameters.
059    */
060   public static Object[] getMatchingArgs(Class<?>[] paramTypes, Object... args) {
061      boolean needsShuffle = paramTypes.length != args.length;
062      if (! needsShuffle) {
063         for (int i = 0; i < paramTypes.length; i++) {
064            if (! paramTypes[i].isInstance(args[i]))
065               needsShuffle = true;
066         }
067      }
068      if (! needsShuffle)
069         return args;
070      Object[] params = new Object[paramTypes.length];
071      for (int i = 0; i < paramTypes.length; i++) {
072         ClassInfo pt = ClassInfo.of(paramTypes[i]).getWrapperInfoIfPrimitive();
073         for (int j = 0; j < args.length; j++) {
074            if (args[j] != null && pt.isParentOf(args[j].getClass())) {
075               params[i] = args[j];
076               break;
077            }
078         }
079      }
080      return params;
081   }
082
083   /**
084    * Attempts to call <code>x.setAccessible(<jk>true</jk>)</code> and quietly ignores security exceptions.
085    *
086    * @param x The constructor.
087    * @return <jk>true</jk> if call was successful.
088    */
089   public static boolean setAccessible(Constructor<?> x) {
090      try {
091         if (x != null)
092            x.setAccessible(true);
093         return true;
094      } catch (SecurityException e) {
095         return false;
096      }
097   }
098
099   /**
100    * Attempts to call <code>x.setAccessible(<jk>true</jk>)</code> and quietly ignores security exceptions.
101    *
102    * @param x The method.
103    * @return <jk>true</jk> if call was successful.
104    */
105   public static boolean setAccessible(Method x) {
106      try {
107         if (x != null)
108            x.setAccessible(true);
109         return true;
110      } catch (SecurityException e) {
111         return false;
112      }
113   }
114
115   /**
116    * Attempts to call <code>x.setAccessible(<jk>true</jk>)</code> and quietly ignores security exceptions.
117    *
118    * @param x The field.
119    * @return <jk>true</jk> if call was successful.
120    */
121   public static boolean setAccessible(Field x) {
122      try {
123         if (x != null)
124            x.setAccessible(true);
125         return true;
126      } catch (SecurityException e) {
127         return false;
128      }
129   }
130
131   /**
132    * Returns the specified type as a <c>Class</c>.
133    *
134    * <p>
135    * If it's already a <c>Class</c>, it just does a cast.
136    * <br>If it's a <c>ParameterizedType</c>, it returns the raw type.
137    *
138    * @param t The type to convert.
139    * @return The type converted to a <c>Class</c>, or <jk>null</jk> if it could not be converted.
140    */
141   public static Class<?> toClass(Type t) {
142      if (t instanceof Class)
143         return (Class<?>)t;
144      if (t instanceof ParameterizedType) {
145         ParameterizedType pt = (ParameterizedType)t;
146         // The raw type should always be a class (right?)
147         return (Class<?>)pt.getRawType();
148      }
149      return null;
150   }
151
152   /**
153    * Returns the fully-qualified class name for the specified object.
154    *
155    * @param value The object to get the class name for.
156    * @return The name of the class or <jk>null</jk> if the value was null.
157    */
158   public static String className(Object value) {
159      return value == null ? null : value instanceof Class<?> ? ((Class<?>)value).getName() : value.getClass().getName();
160   }
161
162   /**
163    * Returns the simple class name for the specified object.
164    *
165    * @param value The object to get the class name for.
166    * @return The name of the class or <jk>null</jk> if the value was null.
167    */
168   public static String simpleClassName(Object value) {
169      if (value == null)
170         return null;
171      if (value instanceof ClassInfo)
172         return ((ClassInfo)value).getSimpleName();
173      if (value instanceof ClassMeta)
174         return ((ClassMeta<?>)value).getSimpleName();
175      if (value instanceof Class)
176         return ((Class<?>)value).getSimpleName();
177      return value.getClass().getSimpleName();
178   }
179
180   /**
181    * Returns <jk>true</jk> if the specific class is <jk>null</jk> or <c><jk>void</jk>.<jk>class</jk></c> or {@link Void} or has the simple name <js>"Void</js>.
182    *
183    * @param c The class to check.
184    * @return <jk>true</jk> if the specific class is <jk>null</jk> or <c><jk>void</jk>.<jk>class</jk></c> or {@link Void} or has the simple name <js>"Void</js>.
185    */
186   @SuppressWarnings("rawtypes")
187   public static boolean isVoid(Class c) {
188      return (c == null || c == void.class || c == Void.class || c.getSimpleName().equalsIgnoreCase("void"));
189   }
190
191   /**
192    * Returns <jk>false</jk> if the specific class is <jk>null</jk> or <c><jk>void</jk>.<jk>class</jk></c> or {@link Void} or has the simple name <js>"Void</js>.
193    *
194    * @param c The class to check.
195    * @return <jk>false</jk> if the specific class is <jk>null</jk> or <c><jk>void</jk>.<jk>class</jk></c> or {@link Void} or has the simple name <js>"Void</js>.
196    */
197   @SuppressWarnings("rawtypes")
198   public static boolean isNotVoid(Class c) {
199      return ! isVoid(c);
200   }
201}