001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   https://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.bcel.generic;
020
021import org.apache.bcel.Const;
022import org.apache.bcel.Repository;
023import org.apache.bcel.classfile.JavaClass;
024import org.apache.bcel.classfile.Utility;
025
026/**
027 * Denotes reference such as {@link String}.
028 */
029public class ObjectType extends ReferenceType {
030
031    /**
032     * Gets a new instance.
033     *
034     * @param className fully qualified class name, for example {@link String}.
035     * @return A new instance.
036     * @since 6.0
037     */
038    public static ObjectType getInstance(final String className) {
039        return new ObjectType(className);
040    }
041
042    private final String className; // Class name of type
043
044    /**
045     * Constructs a new instance.
046     *
047     * @param className fully qualified class name, for example {@link String}.
048     */
049    public ObjectType(final String className) {
050        super(Const.T_REFERENCE, "L" + Utility.packageToPath(className) + ";");
051        this.className = Utility.pathToPackage(className);
052    }
053
054    /**
055     * Java Virtual Machine Specification edition 2, 5.4.4 Access Control.
056     *
057     * @param accessor The accessing type.
058     * @return true if accessible.
059     * @throws ClassNotFoundException Thrown if the class referenced by this type can't be found.
060     */
061    public boolean accessibleTo(final ObjectType accessor) throws ClassNotFoundException {
062        final JavaClass jc = Repository.lookupClass(className);
063        if (jc.isPublic()) {
064            return true;
065        }
066        final JavaClass acc = Repository.lookupClass(accessor.className);
067        return acc.getPackageName().equals(jc.getPackageName());
068    }
069
070    /**
071     * @return true if both type objects refer to the same class.
072     */
073    @Override
074    public boolean equals(final Object type) {
075        return type instanceof ObjectType && ((ObjectType) type).className.equals(className);
076    }
077
078    /**
079     * Gets the name of the referenced class.
080     *
081     * @return name of referenced class.
082     */
083    @Override
084    public String getClassName() {
085        return className;
086    }
087
088    /**
089     * Gets the hash code.
090     *
091     * @return A hash code value for the object.
092     */
093    @Override
094    public int hashCode() {
095        return className.hashCode();
096    }
097
098    /**
099     * If "this" doesn't reference a class, it references an interface or a nonexistent entity.
100     *
101     * @return true if it references a class, false otherwise.
102     * @deprecated (since 6.0) this method returns an inaccurate result if the class or interface referenced cannot be
103     *             found: use referencesClassExact() instead
104     */
105    @Deprecated
106    public boolean referencesClass() {
107        try {
108            return Repository.lookupClass(className).isClass();
109        } catch (final ClassNotFoundException e) {
110            return false;
111        }
112    }
113
114    /**
115     * Return true if this type references a class, false if it references an interface.
116     *
117     * @return true if the type references a class, false if it references an interface.
118     * @throws ClassNotFoundException Thrown if the class or interface referenced by this type can't be found
119     */
120    public boolean referencesClassExact() throws ClassNotFoundException {
121        return Repository.lookupClass(className).isClass();
122    }
123
124    /**
125     * If "this" doesn't reference an interface, it references a class or a nonexistent entity.
126     *
127     * @return true if it references an interface, false otherwise.
128     * @deprecated (since 6.0) this method returns an inaccurate result if the class or interface referenced cannot be
129     *             found: use referencesInterfaceExact() instead
130     */
131    @Deprecated
132    public boolean referencesInterface() {
133        try {
134            return !Repository.lookupClass(className).isClass();
135        } catch (final ClassNotFoundException e) {
136            return false;
137        }
138    }
139
140    /**
141     * Return true if this type references an interface, false if it references a class.
142     *
143     * @return true if the type references an interface, false if it references a class.
144     * @throws ClassNotFoundException Thrown if the class or interface referenced by this type can't be found
145     */
146    public boolean referencesInterfaceExact() throws ClassNotFoundException {
147        return !Repository.lookupClass(className).isClass();
148    }
149
150    /**
151     * Return true if this type is a subclass of given ObjectType.
152     *
153     * @param superclass The superclass to check against.
154     * @return true if this is a subclass.
155     * @throws ClassNotFoundException Thrown if any of this class's superclasses can't be found.
156     */
157    public boolean subclassOf(final ObjectType superclass) throws ClassNotFoundException {
158        if (referencesInterfaceExact() || superclass.referencesInterfaceExact()) {
159            return false;
160        }
161        return Repository.instanceOf(this.className, superclass.className);
162    }
163
164    /**
165     * Return the string representation of this type.
166     *
167     * @return the string representation of this type.
168     * @since 6.14.0
169     */
170    @Override
171    public String toString() {
172        return className;
173    }
174}