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