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, that is, 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 * Gets the comparison strategy object.
57 *
58 * @return Comparison strategy object.
59 */
60 public static BCELComparator<Field> getComparator() {
61 return bcelComparator;
62 }
63
64 /**
65 * Sets the comparison strategy object.
66 *
67 * @param comparator Comparison strategy object.
68 */
69 public static void setComparator(final BCELComparator<Field> comparator) {
70 bcelComparator = comparator;
71 }
72
73 /**
74 * Constructs object from file stream.
75 *
76 * @param file Input stream.
77 * @param constantPool the constant pool.
78 */
79 Field(final DataInput file, final ConstantPool constantPool) throws IOException, ClassFormatException {
80 super(file, constantPool);
81 }
82
83 /**
84 * Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a
85 * physical copy.
86 *
87 * @param c Source to copy.
88 */
89 public Field(final Field c) {
90 super(c);
91 }
92
93 /**
94 * Constructs a Field.
95 *
96 * @param accessFlags Access rights of field.
97 * @param nameIndex Points to field name in constant pool.
98 * @param signatureIndex Points to encoded signature.
99 * @param attributes Collection of attributes.
100 * @param constantPool Array of constants.
101 */
102 public Field(final int accessFlags, final int nameIndex, final int signatureIndex, final Attribute[] attributes, final ConstantPool constantPool) {
103 super(accessFlags, nameIndex, signatureIndex, attributes, constantPool);
104 }
105
106 /**
107 * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
108 * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
109 *
110 * @param v Visitor object.
111 */
112 @Override
113 public void accept(final Visitor v) {
114 v.visitField(this);
115 }
116
117 /**
118 * Creates a deep copy of this field.
119 *
120 * @param constantPool the constant pool.
121 * @return deep copy of this field.
122 */
123 public Field copy(final ConstantPool constantPool) {
124 return (Field) copy_(constantPool);
125 }
126
127 /**
128 * Return value as defined by given BCELComparator strategy. By default two Field objects are said to be equal when
129 * their names and signatures are equal.
130 *
131 * @see Object#equals(Object)
132 */
133 @Override
134 public boolean equals(final Object obj) {
135 return obj instanceof Field && bcelComparator.equals(this, (Field) obj);
136 }
137
138 /**
139 * Gets the constant value associated with this field.
140 *
141 * @return constant value associated with this field (may be null).
142 */
143 public ConstantValue getConstantValue() {
144 for (final Attribute attribute : super.getAttributes()) {
145 if (attribute.getTag() == Const.ATTR_CONSTANT_VALUE) {
146 return (ConstantValue) attribute;
147 }
148 }
149 return null;
150 }
151
152 /**
153 * See https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.2.2
154 *
155 * @return type of field.
156 */
157 public Type getType() {
158 return Type.getType(getSignature());
159 }
160
161 /**
162 * Return value as defined by given BCELComparator strategy. By default return the hash code of the field's name XOR
163 * signature.
164 *
165 * @see Object#hashCode()
166 */
167 @Override
168 public int hashCode() {
169 return bcelComparator.hashCode(this);
170 }
171
172 /**
173 * Return string representation close to declaration format, for example: 'public static final short MAX = 100'.
174 *
175 * @return String representation of field, including the signature.
176 */
177 @Override
178 public String toString() {
179 // Get names from constant pool
180 String access = Utility.accessToString(super.getAccessFlags());
181 access = access.isEmpty() ? "" : access + " ";
182 final String signature = Utility.signatureToString(getSignature());
183 final String name = getName();
184 final StringBuilder buf = new StringBuilder(64); // CHECKSTYLE IGNORE MagicNumber
185 buf.append(access).append(signature).append(" ").append(name);
186 final ConstantValue cv = getConstantValue();
187 if (cv != null) {
188 buf.append(" = ").append(cv);
189 }
190 for (final Attribute attribute : super.getAttributes()) {
191 if (!(attribute instanceof ConstantValue)) {
192 buf.append(" [").append(attribute).append("]");
193 }
194 }
195 return buf.toString();
196 }
197 }