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 object from file stream. 075 * 076 * @param file Input stream. 077 * @param constantPool the constant pool. 078 */ 079 Field(final DataInput file, final ConstantPool constantPool) throws IOException, ClassFormatException { 080 super(file, constantPool); 081 } 082 083 /** 084 * Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a 085 * physical copy. 086 * 087 * @param c Source to copy. 088 */ 089 public Field(final Field c) { 090 super(c); 091 } 092 093 /** 094 * Constructs a Field. 095 * 096 * @param accessFlags Access rights of field. 097 * @param nameIndex Points to field name in constant pool. 098 * @param signatureIndex Points to encoded signature. 099 * @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}