001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * https://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.bcel.classfile; 020 021import java.io.DataInput; 022import java.io.IOException; 023import java.util.Objects; 024 025import org.apache.bcel.Const; 026import org.apache.bcel.generic.Type; 027import org.apache.bcel.util.BCELComparator; 028 029/** 030 * This class represents the field info structure, that is, the representation for a variable in the class. See JVM 031 * specification for details. 032 */ 033public final class Field extends FieldOrMethod { 034 035 /** 036 * Empty array constant. 037 * 038 * @since 6.6.0 039 */ 040 public static final Field[] EMPTY_ARRAY = {}; 041 042 private static BCELComparator<Field> bcelComparator = new BCELComparator<Field>() { 043 044 @Override 045 public boolean equals(final Field a, final Field b) { 046 return a == b || a != null && b != null && Objects.equals(a.getName(), b.getName()) && Objects.equals(a.getSignature(), b.getSignature()); 047 } 048 049 @Override 050 public int hashCode(final Field o) { 051 return o != null ? Objects.hash(o.getSignature(), o.getName()) : 0; 052 } 053 }; 054 055 /** 056 * Gets the comparison strategy object. 057 * 058 * @return Comparison strategy object. 059 */ 060 public static BCELComparator<Field> getComparator() { 061 return bcelComparator; 062 } 063 064 /** 065 * Sets the comparison strategy object. 066 * 067 * @param comparator Comparison strategy object. 068 */ 069 public static void setComparator(final BCELComparator<Field> comparator) { 070 bcelComparator = comparator; 071 } 072 073 /** 074 * Constructs a Field from a data input using standard Code headers. 075 * 076 * @param file Input stream. 077 * @param constantPool The constant pool. 078 * @throws IOException Thrown if an I/O error occurs. 079 * @throws ClassFormatException Thrown if the field or one of its attributes is malformed. 080 */ 081 Field(final DataInput file, final ConstantPool constantPool) throws IOException, ClassFormatException { 082 this(file, constantPool, false); 083 } 084 085 /** 086 * Constructs a Field from a data input using the selected Code header layout. 087 * 088 * @param file Input stream. 089 * @param constantPool The constant pool. 090 * @param compactCodeHeader Whether to read any Code attributes encountered with compact four-byte headers ({@code true}) 091 * or standard eight-byte headers ({@code false}). 092 * @throws IOException Thrown if an I/O error occurs. 093 * @throws ClassFormatException Thrown if the field or one of its attributes is malformed. 094 * @see Attribute#readAttribute(DataInput, ConstantPool, boolean) 095 */ 096 Field(final DataInput file, final ConstantPool constantPool, final boolean compactCodeHeader) throws IOException { 097 super(file, constantPool, compactCodeHeader); 098 } 099 100 /** 101 * Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a 102 * physical copy. 103 * 104 * @param c Source to copy. 105 */ 106 public Field(final Field c) { 107 super(c); 108 } 109 110 /** 111 * Constructs a Field. 112 * 113 * @param accessFlags Access rights of field. 114 * @param nameIndex Points to field name in constant pool. 115 * @param signatureIndex Points to encoded signature. 116 * @param attributes Collection of attributes. 117 * @param constantPool Array of constants. 118 */ 119 public Field(final int accessFlags, final int nameIndex, final int signatureIndex, final Attribute[] attributes, final ConstantPool constantPool) { 120 super(accessFlags, nameIndex, signatureIndex, attributes, constantPool); 121 } 122 123 /** 124 * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. 125 * That is, the hierarchy of methods, fields, attributes, and other elements forms a tree of objects. 126 * 127 * @param v Visitor object. 128 */ 129 @Override 130 public void accept(final Visitor v) { 131 v.visitField(this); 132 } 133 134 /** 135 * Creates a deep copy of this field. 136 * 137 * @param constantPool The constant pool. 138 * @return deep copy of this field. 139 */ 140 public Field copy(final ConstantPool constantPool) { 141 return (Field) copy_(constantPool); 142 } 143 144 /** 145 * Return value as defined by given BCELComparator strategy. By default two Field objects are said to be equal when 146 * their names and signatures are equal. 147 * 148 * @see Object#equals(Object) 149 */ 150 @Override 151 public boolean equals(final Object obj) { 152 return obj instanceof Field && bcelComparator.equals(this, (Field) obj); 153 } 154 155 /** 156 * Gets the constant value associated with this field. 157 * 158 * @return constant value associated with this field (may be null). 159 */ 160 public ConstantValue getConstantValue() { 161 for (final Attribute attribute : super.getAttributes()) { 162 if (attribute.getTag() == Const.ATTR_CONSTANT_VALUE) { 163 return (ConstantValue) attribute; 164 } 165 } 166 return null; 167 } 168 169 /** 170 * Gets the field type. 171 * 172 * See https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.2.2 173 * 174 * @return type of field. 175 */ 176 public Type getType() { 177 return Type.getType(getSignature()); 178 } 179 180 /** 181 * Return value as defined by given BCELComparator strategy. By default return the hash code of the field's name XOR 182 * signature. 183 * 184 * @see Object#hashCode() 185 */ 186 @Override 187 public int hashCode() { 188 return bcelComparator.hashCode(this); 189 } 190 191 /** 192 * Return string representation close to declaration format, for example: 'public static final short MAX = 100'. 193 * 194 * @return String representation of field, including the signature. 195 */ 196 @Override 197 public String toString() { 198 // Get names from constant pool 199 String access = Utility.accessToString(super.getAccessFlags()); 200 access = access.isEmpty() ? "" : access + " "; 201 final String signature = Utility.signatureToString(getSignature()); 202 final String name = getName(); 203 final StringBuilder buf = new StringBuilder(64); // CHECKSTYLE IGNORE MagicNumber 204 buf.append(access).append(signature).append(" ").append(name); 205 final ConstantValue cv = getConstantValue(); 206 if (cv != null) { 207 buf.append(" = ").append(cv); 208 } 209 for (final Attribute attribute : super.getAttributes()) { 210 if (!(attribute instanceof ConstantValue)) { 211 buf.append(" [").append(attribute).append("]"); 212 } 213 } 214 return buf.toString(); 215 } 216}