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