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