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