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      */
ReferenceClassDescImpl(String descriptor)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
descriptorString()60     public String descriptorString() {
61         return descriptor;
62     }
63 
64     @Override
resolveConstantDesc(MethodHandles.Lookup lookup)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
equals(Object o)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
hashCode()103     public int hashCode() {
104         return descriptor.hashCode();
105     }
106 
107     @Override
toString()108     public String toString() {
109         return String.format("ClassDesc[%s]", displayName());
110     }
111 }
112