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 *
017 */
018package org.apache.bcel.generic;
019
020import org.apache.bcel.Const;
021import org.apache.bcel.Repository;
022import org.apache.bcel.classfile.JavaClass;
023
024/**
025 * Denotes reference such as java.lang.String.
026 *
027 */
028public class ObjectType extends ReferenceType {
029
030    private final String class_name; // Class name of type
031
032    /**
033     * @since 6.0
034     */
035    public static ObjectType getInstance(final String class_name) {
036        return new ObjectType(class_name);
037    }
038
039    /**
040     * @param class_name fully qualified class name, e.g. java.lang.String
041     */
042    public ObjectType(final String class_name) {
043        super(Const.T_REFERENCE, "L" + class_name.replace('.', '/') + ";");
044        this.class_name = class_name.replace('/', '.');
045    }
046
047
048    /** @return name of referenced class
049     */
050    public String getClassName() {
051        return class_name;
052    }
053
054
055    /** @return a hash code value for the object.
056     */
057    @Override
058    public int hashCode() {
059        return class_name.hashCode();
060    }
061
062
063    /** @return true if both type objects refer to the same class.
064     */
065    @Override
066    public boolean equals( final Object type ) {
067        return (type instanceof ObjectType)
068                ? ((ObjectType) type).class_name.equals(class_name)
069                : false;
070    }
071
072
073    /**
074     * If "this" doesn't reference a class, it references an interface
075     * or a non-existant entity.
076     * @deprecated (since 6.0) this method returns an inaccurate result
077     *   if the class or interface referenced cannot
078     *   be found: use referencesClassExact() instead
079     */
080    @Deprecated
081    public boolean referencesClass() {
082        try {
083            final JavaClass jc = Repository.lookupClass(class_name);
084            return jc.isClass();
085        } catch (final ClassNotFoundException e) {
086            return false;
087        }
088    }
089
090
091    /**
092     * If "this" doesn't reference an interface, it references a class
093     * or a non-existant entity.
094     * @deprecated (since 6.0) this method returns an inaccurate result
095     *   if the class or interface referenced cannot
096     *   be found: use referencesInterfaceExact() instead
097     */
098    @Deprecated
099    public boolean referencesInterface() {
100        try {
101            final JavaClass jc = Repository.lookupClass(class_name);
102            return !jc.isClass();
103        } catch (final ClassNotFoundException e) {
104            return false;
105        }
106    }
107
108
109    /**
110     * Return true if this type references a class,
111     * false if it references an interface.
112     * @return true if the type references a class, false if
113     *   it references an interface
114     * @throws ClassNotFoundException if the class or interface
115     *   referenced by this type can't be found
116     */
117    public boolean referencesClassExact() throws ClassNotFoundException {
118        final JavaClass jc = Repository.lookupClass(class_name);
119        return jc.isClass();
120    }
121
122
123    /**
124     * Return true if this type references an interface,
125     * false if it references a class.
126     * @return true if the type references an interface, false if
127     *   it references a class
128     * @throws ClassNotFoundException if the class or interface
129     *   referenced by this type can't be found
130     */
131    public boolean referencesInterfaceExact() throws ClassNotFoundException {
132        final JavaClass jc = Repository.lookupClass(class_name);
133        return !jc.isClass();
134    }
135
136
137    /**
138     * Return true if this type is a subclass of given ObjectType.
139     * @throws ClassNotFoundException if any of this class's superclasses
140     *  can't be found
141     */
142    public boolean subclassOf( final ObjectType superclass ) throws ClassNotFoundException {
143        if (this.referencesInterfaceExact() || superclass.referencesInterfaceExact()) {
144            return false;
145        }
146        return Repository.instanceOf(this.class_name, superclass.class_name);
147    }
148
149
150    /**
151     * Java Virtual Machine Specification edition 2, � 5.4.4 Access Control
152     * @throws ClassNotFoundException if the class referenced by this type
153     *   can't be found
154     */
155    public boolean accessibleTo( final ObjectType accessor ) throws ClassNotFoundException {
156        final JavaClass jc = Repository.lookupClass(class_name);
157        if (jc.isPublic()) {
158            return true;
159        }
160        final JavaClass acc = Repository.lookupClass(accessor.class_name);
161        return acc.getPackageName().equals(jc.getPackageName());
162    }
163}