1 /*
   2  * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package com.sun.beans.finder;
  26 
  27 /**
  28  * This class is designed to be a key of a cache
  29  * of constructors or methods.
  30  *
  31  * @since 1.7
  32  *
  33  * @author Sergey A. Malenkov
  34  */
  35 final class Signature {
  36     private final Class<?> type;
  37     private final String name;
  38     private final Class<?>[] args;
  39 
  40     private volatile int code;
  41 
  42     /**
  43      * Constructs signature for constructor.
  44      *
  45      * @param type  the class that contains constructor
  46      * @param args  the types of constructor's parameters
  47      */
  48     Signature(Class<?> type, Class<?>[] args) {
  49         this(type, null, args);
  50     }
  51 
  52     /**
  53      * Constructs signature for method.
  54      *
  55      * @param type  the class that contains method
  56      * @param name  the name of the method
  57      * @param args  the types of method's parameters
  58      */
  59     Signature(Class<?> type, String name, Class<?>[] args) {
  60         this.type = type;
  61         this.name = name;
  62         this.args = args;
  63     }
  64 
  65     /**
  66      * Indicates whether some other object is "equal to" this one.
  67      *
  68      * @param object  the reference object with which to compare
  69      * @return {@code true} if this object is the same as the
  70      *         {@code object} argument, {@code false} otherwise
  71      * @see #hashCode()
  72      */
  73     @Override
  74     public boolean equals(Object object) {
  75         if (this == object) {
  76             return true;
  77         }
  78         if (object instanceof Signature) {
  79             Signature signature = (Signature) object;
  80             return isEqual(signature.type, this.type)
  81                 && isEqual(signature.name, this.name)
  82                 && isEqual(signature.args, this.args);
  83         }
  84         return false;
  85     }
  86 
  87     /**
  88      * Indicates whether some object is "equal to" another one.
  89      * This method supports {@code null} values.
  90      *
  91      * @param obj1  the first reference object that will compared
  92      * @param obj2  the second reference object that will compared
  93      * @return {@code true} if first object is the same as the second object,
  94      *         {@code false} otherwise
  95      */
  96     private static boolean isEqual(Object obj1, Object obj2) {
  97         return (obj1 == null)
  98                 ? obj2 == null
  99                 : obj1.equals(obj2);
 100     }
 101 
 102     /**
 103      * Indicates whether some array is "equal to" another one.
 104      * This method supports {@code null} values.
 105      *
 106      * @param args1 the first reference array that will compared
 107      * @param args2 the second reference array that will compared
 108      * @return {@code true} if first array is the same as the second array,
 109      *         {@code false} otherwise
 110      */
 111     private static boolean isEqual(Class<?>[] args1, Class<?>[] args2) {
 112         if ((args1 == null) || (args2 == null)) {
 113             return args1 == args2;
 114         }
 115         if (args1.length != args2.length) {
 116             return false;
 117         }
 118         for (int i = 0; i < args1.length; i++) {
 119             if (!isEqual(args1[i], args2[i])) {
 120                 return false;
 121             }
 122         }
 123         return true;
 124     }
 125 
 126     /**
 127      * Returns a hash code value for the object.
 128      * This method is supported for the benefit of hashtables
 129      * such as {@link java.util.HashMap} or {@link java.util.HashSet}.
 130      * Hash code computed using algorithm
 131      * suggested in Effective Java, Item 8.
 132      *
 133      * @return a hash code value for this object
 134      * @see #equals(Object)
 135      */
 136     @Override
 137     public int hashCode() {
 138         if (this.code == 0) {
 139             int code = 17;
 140             code = addHashCode(code, this.type);
 141             code = addHashCode(code, this.name);
 142 
 143             if (this.args != null) {
 144                 for (Class<?> arg : this.args) {
 145                     code = addHashCode(code, arg);
 146                 }
 147             }
 148             this.code = code;
 149         }
 150         return this.code;
 151     }
 152 
 153     /**
 154      * Adds hash code value if specified object.
 155      * This is a part of the algorithm
 156      * suggested in Effective Java, Item 8.
 157      *
 158      * @param code    current hash code value
 159      * @param object  object that updates hash code value
 160      * @return updated hash code value
 161      * @see #hashCode()
 162      */
 163     private static int addHashCode(int code, Object object) {
 164         code *= 37;
 165         return (object != null)
 166                 ? code + object.hashCode()
 167                 : code;
 168     }
 169 }