1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * https://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 package org.apache.bcel.classfile;
20
21 import java.io.DataInput;
22 import java.io.IOException;
23 import java.util.Objects;
24
25 import org.apache.bcel.Const;
26 import org.apache.bcel.generic.Type;
27 import org.apache.bcel.util.BCELComparator;
28
29 /**
30 * This class represents the field info structure, i.e., the representation for a variable in the class. See JVM
31 * specification for details.
32 */
33 public final class Field extends FieldOrMethod {
34
35 /**
36 * Empty array constant.
37 *
38 * @since 6.6.0
39 */
40 public static final Field[] EMPTY_ARRAY = {};
41
42 private static BCELComparator<Field> bcelComparator = new BCELComparator<Field>() {
43
44 @Override
45 public boolean equals(final Field a, final Field b) {
46 return a == b || a != null && b != null && Objects.equals(a.getName(), b.getName()) && Objects.equals(a.getSignature(), b.getSignature());
47 }
48
49 @Override
50 public int hashCode(final Field o) {
51 return o != null ? Objects.hash(o.getSignature(), o.getName()) : 0;
52 }
53 };
54
55 /**
56 * @return Comparison strategy object.
57 */
58 public static BCELComparator<Field> getComparator() {
59 return bcelComparator;
60 }
61
62 /**
63 * @param comparator Comparison strategy object.
64 */
65 public static void setComparator(final BCELComparator<Field> comparator) {
66 bcelComparator = comparator;
67 }
68
69 /**
70 * Constructs object from file stream.
71 *
72 * @param file Input stream.
73 */
74 Field(final DataInput file, final ConstantPool constantPool) throws IOException, ClassFormatException {
75 super(file, constantPool);
76 }
77
78 /**
79 * Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a
80 * physical copy.
81 *
82 * @param c Source to copy.
83 */
84 public Field(final Field c) {
85 super(c);
86 }
87
88 /**
89 * @param accessFlags Access rights of field
90 * @param nameIndex Points to field name in constant pool
91 * @param signatureIndex Points to encoded signature
92 * @param attributes Collection of attributes
93 * @param constantPool Array of constants
94 */
95 public Field(final int accessFlags, final int nameIndex, final int signatureIndex, final Attribute[] attributes, final ConstantPool constantPool) {
96 super(accessFlags, nameIndex, signatureIndex, attributes, constantPool);
97 }
98
99 /**
100 * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
101 * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
102 *
103 * @param v Visitor object
104 */
105 @Override
106 public void accept(final Visitor v) {
107 v.visitField(this);
108 }
109
110 /**
111 * @return deep copy of this field
112 */
113 public Field copy(final ConstantPool constantPool) {
114 return (Field) copy_(constantPool);
115 }
116
117 /**
118 * Return value as defined by given BCELComparator strategy. By default two Field objects are said to be equal when
119 * their names and signatures are equal.
120 *
121 * @see Object#equals(Object)
122 */
123 @Override
124 public boolean equals(final Object obj) {
125 return obj instanceof Field && bcelComparator.equals(this, (Field) obj);
126 }
127
128 /**
129 * @return constant value associated with this field (may be null)
130 */
131 public ConstantValue getConstantValue() {
132 for (final Attribute attribute : super.getAttributes()) {
133 if (attribute.getTag() == Const.ATTR_CONSTANT_VALUE) {
134 return (ConstantValue) attribute;
135 }
136 }
137 return null;
138 }
139
140 /**
141 * See https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.2.2
142 *
143 * @return type of field
144 */
145 public Type getType() {
146 return Type.getType(getSignature());
147 }
148
149 /**
150 * Return value as defined by given BCELComparator strategy. By default return the hash code of the field's name XOR
151 * signature.
152 *
153 * @see Object#hashCode()
154 */
155 @Override
156 public int hashCode() {
157 return bcelComparator.hashCode(this);
158 }
159
160 /**
161 * Return string representation close to declaration format, for example: 'public static final short MAX = 100'.
162 *
163 * @return String representation of field, including the signature.
164 */
165 @Override
166 public String toString() {
167 // Get names from constant pool
168 String access = Utility.accessToString(super.getAccessFlags());
169 access = access.isEmpty() ? "" : access + " ";
170 final String signature = Utility.signatureToString(getSignature());
171 final String name = getName();
172 final StringBuilder buf = new StringBuilder(64); // CHECKSTYLE IGNORE MagicNumber
173 buf.append(access).append(signature).append(" ").append(name);
174 final ConstantValue cv = getConstantValue();
175 if (cv != null) {
176 buf.append(" = ").append(cv);
177 }
178 for (final Attribute attribute : super.getAttributes()) {
179 if (!(attribute instanceof ConstantValue)) {
180 buf.append(" [").append(attribute).append("]");
181 }
182 }
183 return buf.toString();
184 }
185 }