BytecodeReader.java
/*-
* #%L
* io.earcam.instrumental.module.jpms
* %%
* Copyright (C) 2018 earcam
* %%
* SPDX-License-Identifier: (BSD-3-Clause OR EPL-1.0 OR Apache-2.0 OR MIT)
*
* You <b>must</b> choose to accept, in full - any individual or combination of
* the following licenses:
* <ul>
* <li><a href="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</a></li>
* <li><a href="https://www.eclipse.org/legal/epl-v10.html">EPL-1.0</a></li>
* <li><a href="https://www.apache.org/licenses/LICENSE-2.0">Apache-2.0</a></li>
* <li><a href="https://opensource.org/licenses/MIT">MIT</a></li>
* </ul>
* #L%
*/
package io.earcam.instrumental.module.jpms;
import static org.objectweb.asm.Opcodes.ASM6;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import javax.annotation.WillNotClose;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ModuleVisitor;
final class BytecodeReader extends ModuleVisitor {
private final ModuleInfoBuilder module;
/**
* <p>
* Constructor for BytecodeReader.
* </p>
*
* @param module a {@link io.earcam.instrumental.module.jpms.ModuleInfoBuilder} object.
*/
public BytecodeReader(ModuleInfoBuilder module)
{
super(ASM6);
this.module = module;
}
static ModuleInfo read(byte[] bytecode)
{
return read(new ClassReader(bytecode));
}
static ModuleInfo read(@WillNotClose InputStream bytecode) throws IOException
{
return read(new ClassReader(bytecode));
}
static ModuleInfo read(ClassReader reader)
{
ModuleInfoBuilder module = new DefaultModuleInfo();
BytecodeReader visitor = new BytecodeReader(module);
ClassVisitor classVisitor = new ClassVisitor(ASM6) {
@Override
public ModuleVisitor visitModule(String name, int access, String version)
{
module.named(name).withAccess(access).versioned(version);
return visitor;
}
};
reader.accept(classVisitor, 0);
return module.construct();
}
@Override
public void visitExport(String paquet, int access, String... modules)
{
module.exporting(externalName(paquet), access, modules);
}
private String externalName(String paquet)
{
return paquet.replace('/', '.');
}
@Override
public void visitMainClass(String mainClass)
{
module.launching(externalName(mainClass));
}
@Override
public void visitOpen(String paquet, int access, String... modules)
{
module.opening(externalName(paquet), access, modules);
}
@Override
public void visitPackage(String paquet)
{
module.packaging(externalName(paquet));
}
@Override
public void visitProvide(String service, String... providers)
{
module.providing(externalName(service), externalNames(providers));
}
private String[] externalNames(String[] internalNames)
{
return Arrays.stream(internalNames)
.map(this::externalName)
.toArray(s -> new String[s]);
}
@Override
public void visitRequire(String moduleName, int access, String version)
{
module.requiring(moduleName, access, version);
}
@Override
public void visitUse(String service)
{
module.using(externalName(service));
}
}