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