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, i.e., 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 * @return Comparison strategy object. 057 */ 058 public static BCELComparator<Field> getComparator() { 059 return bcelComparator; 060 } 061 062 /** 063 * @param comparator Comparison strategy object. 064 */ 065 public static void setComparator(final BCELComparator<Field> comparator) { 066 bcelComparator = comparator; 067 } 068 069 /** 070 * Constructs object from file stream. 071 * 072 * @param file Input stream. 073 */ 074 Field(final DataInput file, final ConstantPool constantPool) throws IOException, ClassFormatException { 075 super(file, constantPool); 076 } 077 078 /** 079 * Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a 080 * physical copy. 081 * 082 * @param c Source to copy. 083 */ 084 public Field(final Field c) { 085 super(c); 086 } 087 088 /** 089 * @param accessFlags Access rights of field 090 * @param nameIndex Points to field name in constant pool 091 * @param signatureIndex Points to encoded signature 092 * @param attributes Collection of attributes 093 * @param constantPool Array of constants 094 */ 095 public Field(final int accessFlags, final int nameIndex, final int signatureIndex, final Attribute[] attributes, final ConstantPool constantPool) { 096 super(accessFlags, nameIndex, signatureIndex, attributes, constantPool); 097 } 098 099 /** 100 * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. 101 * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects. 102 * 103 * @param v Visitor object 104 */ 105 @Override 106 public void accept(final Visitor v) { 107 v.visitField(this); 108 } 109 110 /** 111 * @return deep copy of this field 112 */ 113 public Field copy(final ConstantPool constantPool) { 114 return (Field) copy_(constantPool); 115 } 116 117 /** 118 * Return value as defined by given BCELComparator strategy. By default two Field objects are said to be equal when 119 * their names and signatures are equal. 120 * 121 * @see Object#equals(Object) 122 */ 123 @Override 124 public boolean equals(final Object obj) { 125 return obj instanceof Field && bcelComparator.equals(this, (Field) obj); 126 } 127 128 /** 129 * @return constant value associated with this field (may be null) 130 */ 131 public ConstantValue getConstantValue() { 132 for (final Attribute attribute : super.getAttributes()) { 133 if (attribute.getTag() == Const.ATTR_CONSTANT_VALUE) { 134 return (ConstantValue) attribute; 135 } 136 } 137 return null; 138 } 139 140 /** 141 * See https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.2.2 142 * 143 * @return type of field 144 */ 145 public Type getType() { 146 return Type.getType(getSignature()); 147 } 148 149 /** 150 * Return value as defined by given BCELComparator strategy. By default return the hash code of the field's name XOR 151 * signature. 152 * 153 * @see Object#hashCode() 154 */ 155 @Override 156 public int hashCode() { 157 return bcelComparator.hashCode(this); 158 } 159 160 /** 161 * Return string representation close to declaration format, for example: 'public static final short MAX = 100'. 162 * 163 * @return String representation of field, including the signature. 164 */ 165 @Override 166 public String toString() { 167 // Get names from constant pool 168 String access = Utility.accessToString(super.getAccessFlags()); 169 access = access.isEmpty() ? "" : access + " "; 170 final String signature = Utility.signatureToString(getSignature()); 171 final String name = getName(); 172 final StringBuilder buf = new StringBuilder(64); // CHECKSTYLE IGNORE MagicNumber 173 buf.append(access).append(signature).append(" ").append(name); 174 final ConstantValue cv = getConstantValue(); 175 if (cv != null) { 176 buf.append(" = ").append(cv); 177 } 178 for (final Attribute attribute : super.getAttributes()) { 179 if (!(attribute instanceof ConstantValue)) { 180 buf.append(" [").append(attribute).append("]"); 181 } 182 } 183 return buf.toString(); 184 } 185}