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.juneau.internal;
018
019import java.lang.reflect.*;
020import java.util.function.*;
021
022import org.apache.juneau.*;
023import org.apache.juneau.reflect.*;
024
025/**
026 * Class-related utility methods.
027 *
028 * <h5 class='section'>See Also:</h5><ul>
029
030 * </ul>
031 */
032public class ClassUtils {
033
034   /**
035    * Predicate check to filter out void classes.
036    */
037   public static final Predicate<Class<?>> NOT_VOID = ClassUtils::isNotVoid;
038
039   /**
040    * Returns the class types for the specified arguments.
041    *
042    * @param args The objects we're getting the classes of.
043    * @return The classes of the arguments.
044    */
045   public static Class<?>[] getClasses(Object...args) {
046      Class<?>[] pt = new Class<?>[args.length];
047      for (int i = 0; i < args.length; i++)
048         pt[i] = args[i] == null ? null : args[i].getClass();
049      return pt;
050   }
051
052   /**
053    * Matches arguments to a list of parameter types.
054    *
055    * <p>
056    * Extra parameters are ignored.
057    * <br>Missing parameters are left null.
058    *
059    * @param paramTypes The parameter types.
060    * @param args The arguments to match to the parameter types.
061    * @return
062    *    An array of parameters.
063    */
064   public static Object[] getMatchingArgs(Class<?>[] paramTypes, Object... args) {
065      boolean needsShuffle = paramTypes.length != args.length;
066      if (! needsShuffle) {
067         for (int i = 0; i < paramTypes.length; i++) {
068            if (! paramTypes[i].isInstance(args[i]))
069               needsShuffle = true;
070         }
071      }
072      if (! needsShuffle)
073         return args;
074      Object[] params = new Object[paramTypes.length];
075      for (int i = 0; i < paramTypes.length; i++) {
076         ClassInfo pt = ClassInfo.of(paramTypes[i]).getWrapperInfoIfPrimitive();
077         for (Object arg : args) {
078            if (arg != null && pt.isParentOf(arg.getClass())) {
079               params[i] = arg;
080               break;
081            }
082         }
083      }
084      return params;
085   }
086
087   /**
088    * Attempts to call <code>x.setAccessible(<jk>true</jk>)</code> and quietly ignores security exceptions.
089    *
090    * @param x The constructor.
091    * @return <jk>true</jk> if call was successful.
092    */
093   public static boolean setAccessible(Constructor<?> x) {
094      try {
095         if (x != null)
096            x.setAccessible(true);
097         return true;
098      } catch (SecurityException e) {
099         return false;
100      }
101   }
102
103   /**
104    * Attempts to call <code>x.setAccessible(<jk>true</jk>)</code> and quietly ignores security exceptions.
105    *
106    * @param x The method.
107    * @return <jk>true</jk> if call was successful.
108    */
109   public static boolean setAccessible(Method x) {
110      try {
111         if (x != null)
112            x.setAccessible(true);
113         return true;
114      } catch (SecurityException e) {
115         return false;
116      }
117   }
118
119   /**
120    * Attempts to call <code>x.setAccessible(<jk>true</jk>)</code> and quietly ignores security exceptions.
121    *
122    * @param x The field.
123    * @return <jk>true</jk> if call was successful.
124    */
125   public static boolean setAccessible(Field x) {
126      try {
127         if (x != null)
128            x.setAccessible(true);
129         return true;
130      } catch (SecurityException e) {
131         return false;
132      }
133   }
134
135   /**
136    * Returns the specified type as a <c>Class</c>.
137    *
138    * <p>
139    * If it's already a <c>Class</c>, it just does a cast.
140    * <br>If it's a <c>ParameterizedType</c>, it returns the raw type.
141    *
142    * @param t The type to convert.
143    * @return The type converted to a <c>Class</c>, or <jk>null</jk> if it could not be converted.
144    */
145   public static Class<?> toClass(Type t) {
146      if (t instanceof Class)
147         return (Class<?>)t;
148      if (t instanceof ParameterizedType) {
149         ParameterizedType pt = (ParameterizedType)t;
150         // The raw type should always be a class (right?)
151         return (Class<?>)pt.getRawType();
152      }
153      return null;
154   }
155
156   /**
157    * Returns the fully-qualified class name for the specified object.
158    *
159    * @param value The object to get the class name for.
160    * @return The name of the class or <jk>null</jk> if the value was null.
161    */
162   public static String className(Object value) {
163      return value == null ? null : value instanceof Class<?> ? ((Class<?>)value).getName() : value.getClass().getName();
164   }
165
166   /**
167    * Returns the simple class name for the specified object.
168    *
169    * @param value The object to get the class name for.
170    * @return The name of the class or <jk>null</jk> if the value was null.
171    */
172   public static String simpleClassName(Object value) {
173      if (value == null)
174         return null;
175      if (value instanceof ClassInfo)
176         return ((ClassInfo)value).getSimpleName();
177      if (value instanceof ClassMeta)
178         return ((ClassMeta<?>)value).getSimpleName();
179      if (value instanceof Class)
180         return ((Class<?>)value).getSimpleName();
181      return value.getClass().getSimpleName();
182   }
183
184   /**
185    * 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>.
186    *
187    * @param c The class to check.
188    * @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>.
189    */
190   @SuppressWarnings("rawtypes")
191   public static boolean isVoid(Class c) {
192      return (c == null || c == void.class || c == Void.class || c.getSimpleName().equalsIgnoreCase("void"));
193   }
194
195   /**
196    * 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>.
197    *
198    * @param c The class to check.
199    * @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>.
200    */
201   @SuppressWarnings("rawtypes")
202   public static boolean isNotVoid(Class c) {
203      return ! isVoid(c);
204   }
205}