1 /*
2 * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
3 */
4 /*
5 * Licensed to the Apache Software Foundation (ASF) under one or more
6 * contributor license agreements. See the NOTICE file distributed with
7 * this work for additional information regarding copyright ownership.
8 * The ASF licenses this file to You under the Apache License, Version 2.0
9 * (the "License"); you may not use this file except in compliance with
10 * the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20 package com.sun.org.apache.bcel.internal.classfile;
21
22 import java.io.ByteArrayOutputStream;
23 import java.io.DataOutputStream;
24 import java.io.File;
25 import java.io.FileOutputStream;
26 import java.io.IOException;
27 import java.io.OutputStream;
28 import java.util.ArrayList;
29 import java.util.Objects;
30 import java.util.StringTokenizer;
31 import java.util.List;
32 import java.util.Set;
33 import java.util.TreeSet;
34
35 import com.sun.org.apache.bcel.internal.Const;
36 import com.sun.org.apache.bcel.internal.generic.Type;
37 import com.sun.org.apache.bcel.internal.util.BCELComparator;
38 import com.sun.org.apache.bcel.internal.util.ClassQueue;
39 import com.sun.org.apache.bcel.internal.util.SyntheticRepository;
40
41 /**
42 * Represents a Java class, i.e., the data structures, constant pool, fields,
43 * methods and commands contained in a Java .class file. See <a
44 * href="http://docs.oracle.com/javase/specs/">JVM specification</a> for
45 * details. The intent of this class is to represent a parsed or otherwise
46 * existing class file. Those interested in programatically generating classes
47 * should see the <a href="../generic/ClassGen.html">ClassGen</a> class.
48
49 * @version $Id$
50 * @see com.sun.org.apache.bcel.internal.generic.ClassGen
51 * @LastModified: Jun 2019
52 */
53 public class JavaClass extends AccessFlags implements Cloneable, Node, Comparable<JavaClass> {
54
55 private String file_name;
56 private String package_name;
57 private String source_file_name = "<Unknown>";
58 private int class_name_index;
59 private int superclass_name_index;
60 private String class_name;
61 private String superclass_name;
62 private int major;
63 private int minor; // Compiler version
64 private ConstantPool constant_pool; // Constant pool
65 private int[] interfaces; // implemented interfaces
66 private String[] interface_names;
67 private Field[] fields; // Fields, i.e., variables of class
68 private Method[] methods; // methods defined in the class
69 private Attribute[] attributes; // attributes defined in the class
70 private AnnotationEntry[] annotations; // annotations defined on the class
71 private byte source = HEAP; // Generated in memory
72 private boolean isAnonymous = false;
73 private boolean isNested = false;
74 private boolean computedNestedTypeStatus = false;
75 public static final byte HEAP = 1;
76 public static final byte FILE = 2;
77 public static final byte ZIP = 3;
78
79 private static BCELComparator bcelComparator = new BCELComparator() {
80
81 @Override
82 public boolean equals( final Object o1, final Object o2 ) {
83 final JavaClass THIS = (JavaClass) o1;
84 final JavaClass THAT = (JavaClass) o2;
85 return Objects.equals(THIS.getClassName(), THAT.getClassName());
86 }
87
88
89 @Override
90 public int hashCode( final Object o ) {
91 final JavaClass THIS = (JavaClass) o;
92 return THIS.getClassName().hashCode();
93 }
94 };
95 /**
96 * In cases where we go ahead and create something,
97 * use the default SyntheticRepository, because we
201 final String file_name, final int major, final int minor, final int access_flags,
202 final ConstantPool constant_pool, final int[] interfaces, final Field[] fields,
203 final Method[] methods, final Attribute[] attributes) {
204 this(class_name_index, superclass_name_index, file_name, major, minor, access_flags,
205 constant_pool, interfaces, fields, methods, attributes, HEAP);
206 }
207
208
209 /**
210 * Called by objects that are traversing the nodes of the tree implicitely
211 * defined by the contents of a Java class. I.e., the hierarchy of methods,
212 * fields, attributes, etc. spawns a tree of objects.
213 *
214 * @param v Visitor object
215 */
216 @Override
217 public void accept( final Visitor v ) {
218 v.visitJavaClass(this);
219 }
220
221 /**
222 * Dump class to a file.
223 *
224 * @param file Output file
225 * @throws IOException
226 */
227 public void dump(final File file) throws IOException {
228 final String parent = file.getParent();
229 if (parent != null) {
230 final File dir = new File(parent);
231 if (!dir.mkdirs()) { // either was not created or already existed
232 if (!dir.isDirectory()) {
233 throw new IOException("Could not create the directory " + dir);
234 }
235 }
236 }
237 try (DataOutputStream dos = new DataOutputStream(new FileOutputStream(file))) {
238 dump(dos);
239 }
240 }
589 */
590 @Override
591 public String toString() {
592 String access = Utility.accessToString(super.getAccessFlags(), true);
593 access = access.isEmpty() ? "" : (access + " ");
594 final StringBuilder buf = new StringBuilder(128);
595 buf.append(access).append(Utility.classOrInterface(super.getAccessFlags())).append(" ").append(
596 class_name).append(" extends ").append(
597 Utility.compactClassName(superclass_name, false)).append('\n');
598 final int size = interfaces.length;
599 if (size > 0) {
600 buf.append("implements\t\t");
601 for (int i = 0; i < size; i++) {
602 buf.append(interface_names[i]);
603 if (i < size - 1) {
604 buf.append(", ");
605 }
606 }
607 buf.append('\n');
608 }
609 buf.append("filename\t\t").append(file_name).append('\n');
610 buf.append("compiled from\t\t").append(source_file_name).append('\n');
611 buf.append("compiler version\t").append(major).append(".").append(minor).append('\n');
612 buf.append("access flags\t\t").append(super.getAccessFlags()).append('\n');
613 buf.append("constant pool\t\t").append(constant_pool.getLength()).append(" entries\n");
614 buf.append("ACC_SUPER flag\t\t").append(isSuper()).append("\n");
615 if (attributes.length > 0) {
616 buf.append("\nAttribute(s):\n");
617 for (final Attribute attribute : attributes) {
618 buf.append(indent(attribute));
619 }
620 }
621 final AnnotationEntry[] annotations = getAnnotationEntries();
622 if (annotations!=null && annotations.length>0) {
623 buf.append("\nAnnotation(s):\n");
624 for (final AnnotationEntry annotation : annotations) {
625 buf.append(indent(annotation));
626 }
627 }
628 if (fields.length > 0) {
629 buf.append("\n").append(fields.length).append(" fields:\n");
699
700 /**
701 * @since 6.0
702 */
703 public final boolean isNested() {
704 computeNestedTypeStatus();
705 return this.isNested;
706 }
707
708 private void computeNestedTypeStatus() {
709 if (computedNestedTypeStatus) {
710 return;
711 }
712 for (final Attribute attribute : this.attributes) {
713 if (attribute instanceof InnerClasses) {
714 final InnerClass[] innerClasses = ((InnerClasses) attribute).getInnerClasses();
715 for (final InnerClass innerClasse : innerClasses) {
716 boolean innerClassAttributeRefersToMe = false;
717 String inner_class_name = constant_pool.getConstantString(innerClasse.getInnerClassIndex(),
718 Const.CONSTANT_Class);
719 inner_class_name = Utility.compactClassName(inner_class_name);
720 if (inner_class_name.equals(getClassName())) {
721 innerClassAttributeRefersToMe = true;
722 }
723 if (innerClassAttributeRefersToMe) {
724 this.isNested = true;
725 if (innerClasse.getInnerNameIndex() == 0) {
726 this.isAnonymous = true;
727 }
728 }
729 }
730 }
731 }
732 this.computedNestedTypeStatus = true;
733 }
734
735
736 /** @return returns either HEAP (generated), FILE, or ZIP
737 */
738 public final byte getSource() {
739 return source;
740 }
741
742
743 /********************* New repository functionality *********************/
744 /**
745 * Gets the ClassRepository which holds its definition. By default
746 * this is the same as SyntheticRepository.getInstance();
747 */
748 public com.sun.org.apache.bcel.internal.util.Repository getRepository() {
749 return repository;
750 }
751
752
753 /**
754 * Sets the ClassRepository which loaded the JavaClass.
755 * Should be called immediately after parsing is done.
756 */
757 public void setRepository(final com.sun.org.apache.bcel.internal.util.Repository repository) {
758 this.repository = repository;
759 }
760
761
762 /** Equivalent to runtime "instanceof" operator.
763 *
764 * @return true if this JavaClass is derived from the super class
765 * @throws ClassNotFoundException if superclasses or superinterfaces
766 * of this object can't be found
767 */
768 public final boolean instanceOf( final JavaClass super_class ) throws ClassNotFoundException {
769 if (this.equals(super_class)) {
770 return true;
771 }
772 final JavaClass[] super_classes = getSuperClasses();
773 for (final JavaClass super_classe : super_classes) {
774 if (super_classe.equals(super_class)) {
775 return true;
776 }
777 }
|
1 /*
2 * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
3 */
4 /*
5 * Licensed to the Apache Software Foundation (ASF) under one or more
6 * contributor license agreements. See the NOTICE file distributed with
7 * this work for additional information regarding copyright ownership.
8 * The ASF licenses this file to You under the Apache License, Version 2.0
9 * (the "License"); you may not use this file except in compliance with
10 * the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20 package com.sun.org.apache.bcel.internal.classfile;
21
22 import java.io.ByteArrayOutputStream;
23 import java.io.DataOutputStream;
24 import java.io.File;
25 import java.io.FileOutputStream;
26 import java.io.IOException;
27 import java.io.OutputStream;
28 import java.util.ArrayList;
29 import java.util.Objects;
30 import java.util.StringTokenizer;
31 import java.util.List;
32 import java.util.Set;
33 import java.util.TreeSet;
34
35 import com.sun.org.apache.bcel.internal.Const;
36 import com.sun.org.apache.bcel.internal.generic.Type;
37 import com.sun.org.apache.bcel.internal.util.BCELComparator;
38 import com.sun.org.apache.bcel.internal.util.ClassQueue;
39 import com.sun.org.apache.bcel.internal.util.SyntheticRepository;
40
41 /**
42 * Represents a Java class, i.e., the data structures, constant pool,
43 * fields, methods and commands contained in a Java .class file.
44 * See <a href="http://docs.oracle.com/javase/specs/">JVM specification</a> for details.
45 * The intent of this class is to represent a parsed or otherwise existing
46 * class file. Those interested in programatically generating classes
47 * should see the <a href="../generic/ClassGen.html">ClassGen</a> class.
48
49 * @see com.sun.org.apache.bcel.internal.generic.ClassGen
50 * @LastModified: Jan 2020
51 */
52 public class JavaClass extends AccessFlags implements Cloneable, Node, Comparable<JavaClass> {
53
54 private String file_name;
55 private String package_name;
56 private String source_file_name = "<Unknown>";
57 private int class_name_index;
58 private int superclass_name_index;
59 private String class_name;
60 private String superclass_name;
61 private int major;
62 private int minor; // Compiler version
63 private ConstantPool constant_pool; // Constant pool
64 private int[] interfaces; // implemented interfaces
65 private String[] interface_names;
66 private Field[] fields; // Fields, i.e., variables of class
67 private Method[] methods; // methods defined in the class
68 private Attribute[] attributes; // attributes defined in the class
69 private AnnotationEntry[] annotations; // annotations defined on the class
70 private byte source = HEAP; // Generated in memory
71 private boolean isAnonymous = false;
72 private boolean isNested = false;
73 private boolean computedNestedTypeStatus = false;
74 public static final byte HEAP = 1;
75 public static final byte FILE = 2;
76 public static final byte ZIP = 3;
77 private static final boolean debug = false;
78
79 private static BCELComparator bcelComparator = new BCELComparator() {
80
81 @Override
82 public boolean equals( final Object o1, final Object o2 ) {
83 final JavaClass THIS = (JavaClass) o1;
84 final JavaClass THAT = (JavaClass) o2;
85 return Objects.equals(THIS.getClassName(), THAT.getClassName());
86 }
87
88
89 @Override
90 public int hashCode( final Object o ) {
91 final JavaClass THIS = (JavaClass) o;
92 return THIS.getClassName().hashCode();
93 }
94 };
95 /**
96 * In cases where we go ahead and create something,
97 * use the default SyntheticRepository, because we
201 final String file_name, final int major, final int minor, final int access_flags,
202 final ConstantPool constant_pool, final int[] interfaces, final Field[] fields,
203 final Method[] methods, final Attribute[] attributes) {
204 this(class_name_index, superclass_name_index, file_name, major, minor, access_flags,
205 constant_pool, interfaces, fields, methods, attributes, HEAP);
206 }
207
208
209 /**
210 * Called by objects that are traversing the nodes of the tree implicitely
211 * defined by the contents of a Java class. I.e., the hierarchy of methods,
212 * fields, attributes, etc. spawns a tree of objects.
213 *
214 * @param v Visitor object
215 */
216 @Override
217 public void accept( final Visitor v ) {
218 v.visitJavaClass(this);
219 }
220
221
222 /* Print debug information depending on `JavaClass.debug'
223 */
224 static void Debug( final String str ) {
225 if (debug) {
226 System.out.println(str);
227 }
228 }
229
230
231 /**
232 * Dump class to a file.
233 *
234 * @param file Output file
235 * @throws IOException
236 */
237 public void dump(final File file) throws IOException {
238 final String parent = file.getParent();
239 if (parent != null) {
240 final File dir = new File(parent);
241 if (!dir.mkdirs()) { // either was not created or already existed
242 if (!dir.isDirectory()) {
243 throw new IOException("Could not create the directory " + dir);
244 }
245 }
246 }
247 try (DataOutputStream dos = new DataOutputStream(new FileOutputStream(file))) {
248 dump(dos);
249 }
250 }
599 */
600 @Override
601 public String toString() {
602 String access = Utility.accessToString(super.getAccessFlags(), true);
603 access = access.isEmpty() ? "" : (access + " ");
604 final StringBuilder buf = new StringBuilder(128);
605 buf.append(access).append(Utility.classOrInterface(super.getAccessFlags())).append(" ").append(
606 class_name).append(" extends ").append(
607 Utility.compactClassName(superclass_name, false)).append('\n');
608 final int size = interfaces.length;
609 if (size > 0) {
610 buf.append("implements\t\t");
611 for (int i = 0; i < size; i++) {
612 buf.append(interface_names[i]);
613 if (i < size - 1) {
614 buf.append(", ");
615 }
616 }
617 buf.append('\n');
618 }
619 buf.append("file name\t\t").append(file_name).append('\n');
620 buf.append("compiled from\t\t").append(source_file_name).append('\n');
621 buf.append("compiler version\t").append(major).append(".").append(minor).append('\n');
622 buf.append("access flags\t\t").append(super.getAccessFlags()).append('\n');
623 buf.append("constant pool\t\t").append(constant_pool.getLength()).append(" entries\n");
624 buf.append("ACC_SUPER flag\t\t").append(isSuper()).append("\n");
625 if (attributes.length > 0) {
626 buf.append("\nAttribute(s):\n");
627 for (final Attribute attribute : attributes) {
628 buf.append(indent(attribute));
629 }
630 }
631 final AnnotationEntry[] annotations = getAnnotationEntries();
632 if (annotations!=null && annotations.length>0) {
633 buf.append("\nAnnotation(s):\n");
634 for (final AnnotationEntry annotation : annotations) {
635 buf.append(indent(annotation));
636 }
637 }
638 if (fields.length > 0) {
639 buf.append("\n").append(fields.length).append(" fields:\n");
709
710 /**
711 * @since 6.0
712 */
713 public final boolean isNested() {
714 computeNestedTypeStatus();
715 return this.isNested;
716 }
717
718 private void computeNestedTypeStatus() {
719 if (computedNestedTypeStatus) {
720 return;
721 }
722 for (final Attribute attribute : this.attributes) {
723 if (attribute instanceof InnerClasses) {
724 final InnerClass[] innerClasses = ((InnerClasses) attribute).getInnerClasses();
725 for (final InnerClass innerClasse : innerClasses) {
726 boolean innerClassAttributeRefersToMe = false;
727 String inner_class_name = constant_pool.getConstantString(innerClasse.getInnerClassIndex(),
728 Const.CONSTANT_Class);
729 inner_class_name = Utility.compactClassName(inner_class_name, false);
730 if (inner_class_name.equals(getClassName())) {
731 innerClassAttributeRefersToMe = true;
732 }
733 if (innerClassAttributeRefersToMe) {
734 this.isNested = true;
735 if (innerClasse.getInnerNameIndex() == 0) {
736 this.isAnonymous = true;
737 }
738 }
739 }
740 }
741 }
742 this.computedNestedTypeStatus = true;
743 }
744
745
746 /** @return returns either HEAP (generated), FILE, or ZIP
747 */
748 public final byte getSource() {
749 return source;
750 }
751
752
753 /********************* New repository functionality *********************/
754 /**
755 * Gets the ClassRepository which holds its definition. By default
756 * this is the same as SyntheticRepository.getInstance();
757 */
758 public com.sun.org.apache.bcel.internal.util.Repository getRepository() {
759 return repository;
760 }
761
762
763 /**
764 * Sets the ClassRepository which loaded the JavaClass.
765 * Should be called immediately after parsing is done.
766 */
767 public void setRepository( final com.sun.org.apache.bcel.internal.util.Repository repository ) { // TODO make protected?
768 this.repository = repository;
769 }
770
771
772 /** Equivalent to runtime "instanceof" operator.
773 *
774 * @return true if this JavaClass is derived from the super class
775 * @throws ClassNotFoundException if superclasses or superinterfaces
776 * of this object can't be found
777 */
778 public final boolean instanceOf( final JavaClass super_class ) throws ClassNotFoundException {
779 if (this.equals(super_class)) {
780 return true;
781 }
782 final JavaClass[] super_classes = getSuperClasses();
783 for (final JavaClass super_classe : super_classes) {
784 if (super_classe.equals(super_class)) {
785 return true;
786 }
787 }
|