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