1 /*
  2  * Copyright (c) 2018, 2020, 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 java.lang.constant;
 26 
 27 import java.lang.invoke.MethodHandles;
 28 
 29 import static java.lang.constant.ConstantUtils.dropFirstAndLastChar;
 30 import static java.lang.constant.ConstantUtils.internalToBinary;
 31 import static java.util.Objects.requireNonNull;
 32 
 33 /**
 34  * A <a href="package-summary.html#nominal">nominal descriptor</a> for a class,
 35  * interface, or array type.  A {@linkplain ReferenceClassDescImpl} corresponds to a
 36  * {@code Constant_Class_info} entry in the constant pool of a classfile.
 37  */
 38 final class ReferenceClassDescImpl implements ClassDesc {
 39     private final String descriptor;
 40 
 41     /**
 42      * Creates a {@linkplain ClassDesc} from a descriptor string for a class or
 43      * interface type
 44      *
 45      * @param descriptor a field descriptor string for a class or interface type
 46      * @throws IllegalArgumentException if the descriptor string is not a valid
 47      * field descriptor string, or does not describe a class or interface type
 48      * @jvms 4.3.2 Field Descriptors
 49      */
 50     ReferenceClassDescImpl(String descriptor) {
 51         requireNonNull(descriptor);
 52         int len = ConstantUtils.skipOverFieldSignature(descriptor, 0, descriptor.length(), false);
 53         if (len == 0 || len == 1
 54             || len != descriptor.length())
 55             throw new IllegalArgumentException(String.format("not a valid reference type descriptor: %s", descriptor));
 56         this.descriptor = descriptor;
 57     }
 58 
 59     @Override
 60     public String descriptorString() {
 61         return descriptor;
 62     }
 63 
 64     @Override
 65     public Class<?> resolveConstantDesc(MethodHandles.Lookup lookup)
 66             throws ReflectiveOperationException {
 67         ClassDesc c = this;
 68         int depth = ConstantUtils.arrayDepth(descriptorString());
 69         for (int i=0; i<depth; i++)
 70             c = c.componentType();
 71 
 72         if (c.isPrimitive())
 73             return lookup.findClass(descriptorString());
 74         else {
 75             Class<?> clazz = lookup.findClass(internalToBinary(dropFirstAndLastChar(c.descriptorString())));
 76             for (int i = 0; i < depth; i++)
 77                 clazz = clazz.arrayType();
 78             return clazz;
 79         }
 80     }
 81 
 82     /**
 83      * Returns {@code true} if this {@linkplain ReferenceClassDescImpl} is
 84      * equal to another {@linkplain ReferenceClassDescImpl}.  Equality is
 85      * determined by the two class descriptors having equal class descriptor
 86      * strings.
 87      *
 88      * @param o the {@code ClassDesc} to compare to this
 89      *       {@code ClassDesc}
 90      * @return {@code true} if the specified {@code ClassDesc}
 91      *      is equal to this {@code ClassDesc}.
 92      */
 93     @Override
 94     public boolean equals(Object o) {
 95         if (this == o) return true;
 96         if (o == null || getClass() != o.getClass()) return false;
 97 
 98         ClassDesc constant = (ClassDesc) o;
 99         return descriptor.equals(constant.descriptorString());
100     }
101 
102     @Override
103     public int hashCode() {
104         return descriptor.hashCode();
105     }
106 
107     @Override
108     public String toString() {
109         return String.format("ClassDesc[%s]", displayName());
110     }
111 }