001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.bcel.classfile; 018 019import java.io.DataInput; 020import java.io.IOException; 021import java.util.Objects; 022 023import org.apache.bcel.Const; 024import org.apache.bcel.generic.Type; 025import org.apache.bcel.util.BCELComparator; 026 027/** 028 * This class represents the field info structure, i.e., the representation for a variable in the class. See JVM 029 * specification for details. 030 */ 031public final class Field extends FieldOrMethod { 032 033 /** 034 * Empty array constant. 035 * 036 * @since 6.6.0 037 */ 038 public static final Field[] EMPTY_ARRAY = {}; 039 040 private static BCELComparator<Field> bcelComparator = new BCELComparator<Field>() { 041 042 @Override 043 public boolean equals(final Field a, final Field b) { 044 return a == b || a != null && b != null && Objects.equals(a.getName(), b.getName()) && Objects.equals(a.getSignature(), b.getSignature()); 045 } 046 047 @Override 048 public int hashCode(final Field o) { 049 return o != null ? Objects.hash(o.getSignature(), o.getName()) : 0; 050 } 051 }; 052 053 /** 054 * @return Comparison strategy object. 055 */ 056 public static BCELComparator<Field> getComparator() { 057 return bcelComparator; 058 } 059 060 /** 061 * @param comparator Comparison strategy object. 062 */ 063 public static void setComparator(final BCELComparator<Field> comparator) { 064 bcelComparator = comparator; 065 } 066 067 /** 068 * Constructs object from file stream. 069 * 070 * @param file Input stream. 071 */ 072 Field(final DataInput file, final ConstantPool constantPool) throws IOException, ClassFormatException { 073 super(file, constantPool); 074 } 075 076 /** 077 * Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a 078 * physical copy. 079 * 080 * @param c Source to copy. 081 */ 082 public Field(final Field c) { 083 super(c); 084 } 085 086 /** 087 * @param accessFlags Access rights of field 088 * @param nameIndex Points to field name in constant pool 089 * @param signatureIndex Points to encoded signature 090 * @param attributes Collection of attributes 091 * @param constantPool Array of constants 092 */ 093 public Field(final int accessFlags, final int nameIndex, final int signatureIndex, final Attribute[] attributes, final ConstantPool constantPool) { 094 super(accessFlags, nameIndex, signatureIndex, attributes, constantPool); 095 } 096 097 /** 098 * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. 099 * 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}