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 */ 019 020package org.apache.bcel.classfile; 021 022import java.io.DataInput; 023import java.io.DataOutputStream; 024import java.io.IOException; 025 026import org.apache.bcel.Const; 027 028/** 029 * This class represents an entry in the provides table of the Module attribute. Each entry describes a service 030 * implementation that the parent module provides. 031 * 032 * @see Module 033 * @since 6.4.0 034 */ 035public final class ModuleProvides implements Cloneable, Node { 036 037 private static String getImplementationClassNameAtIndex(final ConstantPool constantPool, final int index, final boolean compactClassName) { 038 final String className = constantPool.getConstantString(index, Const.CONSTANT_Class); 039 if (compactClassName) { 040 return Utility.compactClassName(className, false); 041 } 042 return className; 043 } 044 private final int providesIndex; // points to CONSTANT_Class_info 045 private final int providesWithCount; 046 047 private final int[] providesWithIndex; // points to CONSTANT_Class_info 048 049 /** 050 * Constructs object from file stream. 051 * 052 * @param file Input stream 053 * @throws IOException if an I/O Exception occurs in readUnsignedShort 054 */ 055 ModuleProvides(final DataInput file) throws IOException { 056 providesIndex = file.readUnsignedShort(); 057 providesWithCount = file.readUnsignedShort(); 058 providesWithIndex = new int[providesWithCount]; 059 for (int i = 0; i < providesWithCount; i++) { 060 providesWithIndex[i] = file.readUnsignedShort(); 061 } 062 } 063 064 /** 065 * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. 066 * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects. 067 * 068 * @param v Visitor object 069 */ 070 @Override 071 public void accept(final Visitor v) { 072 v.visitModuleProvides(this); 073 } 074 075 /** 076 * @return deep copy of this object 077 */ 078 public ModuleProvides copy() { 079 try { 080 return (ModuleProvides) clone(); 081 } catch (final CloneNotSupportedException e) { 082 // TODO should this throw? 083 } 084 return null; 085 } 086 087 /** 088 * Dump table entry to file stream in binary format. 089 * 090 * @param file Output file stream 091 * @throws IOException if an I/O Exception occurs in writeShort 092 */ 093 public void dump(final DataOutputStream file) throws IOException { 094 file.writeShort(providesIndex); 095 file.writeShort(providesWithCount); 096 for (final int entry : providesWithIndex) { 097 file.writeShort(entry); 098 } 099 } 100 101 /** 102 * Gets the array of implementation class names for this ModuleProvides. 103 * @param constantPool Array of constants usually obtained from the ClassFile object 104 * @param compactClassName false for original constant pool value, true to replace '/' with '.' 105 * @return array of implementation class names 106 * @since 6.10.0 107 */ 108 public String[] getImplementationClassNames(final ConstantPool constantPool, final boolean compactClassName) { 109 final String[] implementationClassNames = new String[providesWithCount]; 110 for (int i = 0; i < providesWithCount; i++) { 111 implementationClassNames[i] = getImplementationClassNameAtIndex(constantPool, providesWithIndex[i], compactClassName); 112 } 113 return implementationClassNames; 114 } 115 116 /** 117 * Gets the interface name for this ModuleProvides. 118 * @param constantPool Array of constants usually obtained from the ClassFile object 119 * @return interface name 120 * @since 6.10.0 121 */ 122 public String getInterfaceName(final ConstantPool constantPool) { 123 return constantPool.constantToString(providesIndex, Const.CONSTANT_Class); 124 } 125 126 /** 127 * @return String representation 128 */ 129 @Override 130 public String toString() { 131 return "provides(" + providesIndex + ", " + providesWithCount + ", ...)"; 132 } 133 134 /** 135 * @return Resolved string representation 136 */ 137 public String toString(final ConstantPool constantPool) { 138 final StringBuilder buf = new StringBuilder(); 139 final String interfaceName = getInterfaceName(constantPool); 140 buf.append(interfaceName); 141 buf.append(", with(").append(providesWithCount).append("):\n"); 142 for (final int index : providesWithIndex) { 143 final String className = getImplementationClassNameAtIndex(constantPool, index, true); 144 buf.append(" ").append(className).append("\n"); 145 } 146 return buf.substring(0, buf.length() - 1); // remove the last newline 147 } 148}