ReflectionHelper.java

/*
** Module   : ReflectionHelper.java
** Abstract : utility methods to ease or replace use of J2SE reflection
**
** Copyright (c) 2007-2017, Golden Code Development Corporation.
**
** -#- -I- --Date-- --JPRM-- ----------------------------Description-----------------------------
** 001 GES 20070320   @32509 Created initial version. Includes methods
**                           for signature matching and error display.
** 002 ECF 20150715          Replace StringBuffer with StringBuilder.
*/
/*
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Affero General Public License as
** published by the Free Software Foundation, either version 3 of the
** License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU Affero General Public License for more details.
**
** You may find a copy of the GNU Affero GPL version 3 at the following
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
** 
** Additional terms under GNU Affero GPL version 3 section 7:
** 
**   Under Section 7 of the GNU Affero GPL version 3, the following additional
**   terms apply to the works covered under the License.  These additional terms
**   are non-permissive additional terms allowed under Section 7 of the GNU
**   Affero GPL version 3 and may not be removed by you.
** 
**   0. Attribution Requirement.
** 
**     You must preserve all legal notices or author attributions in the covered
**     work or Appropriate Legal Notices displayed by works containing the covered
**     work.  You may not remove from the covered work any author or developer
**     credit already included within the covered work.
** 
**   1. No License To Use Trademarks.
** 
**     This license does not grant any license or rights to use the trademarks
**     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
**     of Golden Code Development Corporation. You are not authorized to use the
**     name Golden Code, FWD, or the names of any author or contributor, for
**     publicity purposes without written authorization.
** 
**   2. No Misrepresentation of Affiliation.
** 
**     You may not represent yourself as Golden Code Development Corporation or FWD.
** 
**     You may not represent yourself for publicity purposes as associated with
**     Golden Code Development Corporation, FWD, or any author or contributor to
**     the covered work, without written authorization.
** 
**   3. No Misrepresentation of Source or Origin.
** 
**     You may not represent the covered work as solely your work.  All modified
**     versions of the covered work must be marked in a reasonable way to make it
**     clear that the modified work is not originating from Golden Code Development
**     Corporation or FWD.  All modified versions must contain the notices of
**     attribution required in this license.
*/

package com.goldencode.p2j.util;

import java.lang.reflect.*;

/**
 * Utility methods to ease or replace use of J2SE reflection.
 */
public final class ReflectionHelper
{
   /**
    * Private constructor to prevent instances of this class from being
    * created.
    */
   private ReflectionHelper()
   {
   }
   
   /**
    * Compare signatures as described by two arrays of classes and report
    * if they are equivalent. This is useful because the J2SE 1.4.x
    * reflection services <code>Class.getConstructor()</code> and
    * <code>Class.getMethod()</code> don't check for assignability so
    * a signature based on child classes won't match a compatible signature
    * that uses super classes. The J2SE implementation uses a reference
    * comparison but this method uses <code>isAssignableFrom</code>.
    * <p>
    * A quick return occurs in any case where the number of parameters in
    * the signatures are different.
    *
    * @param    possible
    *           The candidate signature list.
    * @param    actual
    *           The signature being searched for.
    *
    * @return   <code>true</code> if the signatures are compatible.           
    */
   public static boolean testSignature(Class[] possible, Class[] actual)
   {
      // if the signatures have a different number of elements, they
      // can't be compatible
      if (possible.length == actual.length)
      {
         // compare signatures
         for (int i = 0; i < possible.length; i++)
         {
            if (!possible[i].isAssignableFrom(actual[i]))
            {
               // this constructor is not a match
               return false;
            }
         }
         
         return true;
      }
      
      return false;
   }
   
   /**
    * Removes all text up to and including the last '.' in the given string
    * and returns the remaining text.  Some simple attempts are made to
    * detect if this is a J2SE signature string instead of a fully qualified
    * class or method name.  In such a case the entire text is returned.
    *
    * @param    full
    *           A fully qualified class or method name.
    *
    * @return   The simple name or the full text if no '.' qualifiers exist
    *           or if this is detected as a J2SE encoded signature string.
    */
   public static String simpleName(String full)
   {
      // try to detect if this is not a qualified class name but rather a
      // J2SE encoded signature
      if (full.indexOf(';') > 0 || full.indexOf('[') > 0)
         return full;
         
      // find the end of the fully qualified name
      int rest = full.lastIndexOf('.');
      
      return rest < 0 ? full : full.substring(rest + 1);
   }

   /**
    * Create a string representing the signature of the described method.
    * <p>
    * No modifiers are known so there will be no text like <code>public</code> 
    * or <code>static</code> in the result.
    *
    * @param    name
    *           The method name, inserted verbetim into the result.
    * @param    parms
    *           The list of parameters.  If <code>null</code> or 0 length,
    *           then there are no parameters in the signature.
    * @param    returnType
    *           The type the method returns. Use <code>null</code> to indicate
    *           that the return type is unknown or irrelevent. Use 
    *           <code>void.class</code> for a <code>void</code> return.
    *
    * @return   The signature string without any modifiers.
    */
   public static String toStringSignature(String  name,
                                          Class[] parms,
                                          Class   returnType)
   {
      StringBuilder sb = new StringBuilder();
      
      if (returnType != null)
      {
         sb.append(simpleName(returnType.getName())).append(" ");
      }
      
      sb.append(name).append("(");
      
      for (int i = 0; parms != null && i < parms.length; i++)
      {
         if (i > 0)
            sb.append(", ");
         
         sb.append(simpleName(parms[i].getName()));
      }
      
      sb.append(")");
      
      return sb.toString();
   }
}