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.DataOutputStream; 023import java.io.IOException; 024 025import org.apache.bcel.Const; 026import org.apache.bcel.util.Args; 027 028/** 029 * Record component info from a record. Instances from this class maps 030 * every component from a given record. 031 * 032 * @see <a href="https://docs.oracle.com/javase/specs/jvms/se14/preview/specs/records-jvms.html#jvms-4.7.30"> 033 * The Java Virtual Machine Specification, Java SE 14 Edition, Records (preview)</a> 034 * @since 6.9.0 035 */ 036public class RecordComponentInfo implements Node { 037 038 private final int index; 039 private final int descriptorIndex; 040 private final Attribute[] attributes; 041 private final ConstantPool constantPool; 042 043 /** 044 * Constructs a new instance from an input stream. 045 * 046 * @param input Input stream. 047 * @param constantPool Array of constants. 048 * @throws IOException Thrown if an I/O error occurs. 049 */ 050 public RecordComponentInfo(final DataInput input, final ConstantPool constantPool) throws IOException { 051 this.index = input.readUnsignedShort(); 052 this.descriptorIndex = input.readUnsignedShort(); 053 final int attributesCount = input.readUnsignedShort(); 054 this.attributes = new Attribute[attributesCount]; 055 for (int j = 0; j < attributesCount; j++) { 056 attributes[j] = Attribute.readAttribute(input, constantPool); 057 } 058 this.constantPool = constantPool; 059 } 060 061 @Override 062 public void accept(final Visitor v) { 063 v.visitRecordComponent(this); 064 } 065 066 /** 067 * Dumps contents into a file stream in binary format. 068 * 069 * @param file Output file stream. 070 * @throws IOException Thrown if an I/O error occurs. 071 */ 072 public void dump(final DataOutputStream file) throws IOException { 073 file.writeShort(index); 074 file.writeShort(descriptorIndex); 075 file.writeShort(Args.requireU2(attributes.length, "attributes.length")); 076 for (final Attribute attribute : attributes) { 077 attribute.dump(file); 078 } 079 } 080 081 /** 082 * Gets the attribute for the given tag if present, or null if absent. 083 * 084 * @param <T> The attribute type. 085 * @param tag The attribute tag. 086 * @return Attribute for given tag, null if not found. 087 * Refer to {@link org.apache.bcel.Const#ATTR_UNKNOWN} constants named ATTR_* for possible values. 088 * @since 6.13.0 089 */ 090 @SuppressWarnings("unchecked") 091 public final <T extends Attribute> T getAttribute(final byte tag) { 092 for (final Attribute attribute : getAttributes()) { 093 if (attribute.getTag() == tag) { 094 return (T) attribute; 095 } 096 } 097 return null; 098 } 099 100 /** 101 * Gets all attributes. 102 * 103 * @return all attributes. 104 */ 105 public Attribute[] getAttributes() { 106 return attributes; 107 } 108 109 /** 110 * Gets the constant pool. 111 * 112 * @return Constant pool. 113 */ 114 public ConstantPool getConstantPool() { 115 return constantPool; 116 } 117 118 /** 119 * Gets the description index. 120 * 121 * @return index in constant pool of this record component descriptor. 122 */ 123 public int getDescriptorIndex() { 124 return descriptorIndex; 125 } 126 127 /** 128 * Gets the name index. 129 * 130 * @return index in constant pool of this record component name. 131 */ 132 public int getIndex() { 133 return index; 134 } 135 136 /** 137 * Converts this instance to a String suitable for debugging. 138 * 139 * @return A String suitable for debugging. 140 */ 141 @Override 142 public String toString() { 143 final StringBuilder buf = new StringBuilder(); 144 buf.append("RecordComponentInfo("); 145 buf.append(constantPool.getConstantString(index, Const.CONSTANT_Utf8)); 146 buf.append(","); 147 buf.append(constantPool.getConstantString(descriptorIndex, Const.CONSTANT_Utf8)); 148 buf.append(","); 149 buf.append(attributes.length); 150 buf.append("):\n"); 151 for (final Attribute attribute : attributes) { 152 buf.append(" ").append(attribute.toString()).append("\n"); 153 } 154 return buf.substring(0, buf.length() - 1); // remove the last newline 155 } 156 157}