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