下面列出了怎么用org.objectweb.asm.ClassWriter的API类实例代码及写法,或者点击链接到github查看源代码。
@Override
public byte[] transform(String name, String transformedName, byte[] bytes) {
if (bytes == null) {
return null;
}
// check for any inner classes of NetworkManager. It differes between mc versions
if (transformedName.startsWith("net.minecraft.network.NetworkManager$")) {
try {
ClassReader classReader = new ClassReader(bytes);
ClassWriter classWriter = new ClassWriter(classReader, ClassWriter.COMPUTE_FRAMES);
ClassVisitor classVisitor = new NetworkManagerInnerVisitor(classWriter);
classReader.accept(classVisitor, ClassReader.SKIP_FRAMES);
return classWriter.toByteArray();
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
return bytes;
}
@Override
protected byte[] transform(final String className,
final Class<?> classBeingRedefined,
final ProtectionDomain protectionDomain,
final byte[] classBytes) throws IllegalClassFormatException {
if (!Objects.equal(className, monitorClassName)) {
return null;
}
LOG.info("monitor class: {}", className);
Lock lock = classFileBuffer.getLock();
lock.lock();
try {
final ClassReader classReader = new ClassReader(classFileBuffer.getClassBuffer(classBeingRedefined, classBytes));
final ClassWriter classWriter = new ClassWriter(computeFlag(classReader));
final ClassVisitor classVisitor = new MonitorClassVisitor(new CheckClassAdapter(classWriter), methodName, methodDesc);
classReader.accept(classVisitor, ClassReader.EXPAND_FRAMES);
byte[] bytes = classWriter.toByteArray();
classFileBuffer.setClassBuffer(classBeingRedefined, bytes);
return bytes;
} finally {
lock.unlock();
}
}
private static byte[] convertClass(ZipFile file, ZipEntry entry) throws IOException {
try (InputStream content = file.getInputStream(entry)) {
ClassReader reader = new ClassReader(content);
ClassWriter writer = new ClassWriter(0);
ClassVisitor converter =
new ClassVisitor(Opcodes.ASM5, writer) {
@Override
public MethodVisitor visitMethod(
int access, String name, String desc, String signature, String[] exceptions) {
if (name.startsWith("lambda$") && (access & Opcodes.ACC_SYNTHETIC) == 0) {
access |= Opcodes.ACC_SYNTHETIC;
}
return super.visitMethod(access, name, desc, signature, exceptions);
}
};
reader.accept(converter, 0);
return writer.toByteArray();
}
}
private <T> Class<? extends T> createMarkerCls(Class<T> superClass, int key) {
final ClassWriter writer = new ClassWriter(0);
final String superCls = Type.getInternalName(superClass);
writer.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC, superCls + "$marker_" + key, null, superCls, interfaces);
final MethodVisitor mv = writer.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC, "getMarkerValue", "()I", null, null);
mv.visitCode();
mv.visitLdcInsn(key);
mv.visitInsn(Opcodes.IRETURN);
mv.visitMaxs(1, 1);
mv.visitEnd();
writer.visitEnd();
@SuppressWarnings("unchecked")
final Class<? extends T> cls = (Class<? extends T>)loader.define(writer.toByteArray());
return cls;
}
@NonNull
private static byte[] getFixedClass(
@NonNull InputStream originalFile, @NonNull URLClassLoader classLoader)
throws IOException {
byte[] bytes = ByteStreams.toByteArray(originalFile);
try {
ClassReader classReader = new ClassReader(bytes);
ClassWriter classWriter = new AtlasFixStackFramesTransform.FixFramesVisitor(ClassWriter.COMPUTE_FRAMES, classLoader);
classReader.accept(classWriter, ClassReader.SKIP_FRAMES);
return classWriter.toByteArray();
} catch (Throwable t) {
// we could not fix it, just copy the original and log the exception
logger.verbose(t.getMessage());
return bytes;
}
}
@Override
protected void handleClazz(JarFile jarFile, JarOutputStream jos, JarEntry ze, String pathName) {
// logger.log(pathName);
if (reMapping.containsKey(pathName.substring(0, pathName.length() - 6))) {
logger.info("[ClazzReplacer] remove class " + pathName + " form " + jarFile);
return;
}
try {
InputStream in = jarFile.getInputStream(ze);
ClassReader cr = new ClassReader(in);
ClassWriter cw = new ClassWriter(0);
RemappingClassAdapter remappingClassAdapter = new RemappingClassAdapter(cw, new SimpleRemapper(reMapping));
cr.accept(remappingClassAdapter, ClassReader.EXPAND_FRAMES);
InputStream inputStream = new ByteArrayInputStream(cw.toByteArray());
copyStreamToJar(inputStream, jos, pathName, ze.getTime());
} catch (Throwable e) {
System.err.println("[ClazzReplacer] rewrite error > " + pathName);
justCopy(jarFile, jos, ze, pathName);
}
}
private static byte[] getAvmPackageClassBytes() {
ClassWriter classWriter = new ClassWriter(0);
MethodVisitor methodVisitor;
classWriter.visit(V10, ACC_PUBLIC | ACC_SUPER, "avm/Main", null, "java/lang/Object", null);
classWriter.visitSource("Main.java", null);
{
methodVisitor = classWriter.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
methodVisitor.visitCode();
Label label0 = new Label();
methodVisitor.visitLabel(label0);
methodVisitor.visitLineNumber(3, label0);
methodVisitor.visitVarInsn(ALOAD, 0);
methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
methodVisitor.visitInsn(RETURN);
methodVisitor.visitMaxs(1, 1);
methodVisitor.visitEnd();
}
classWriter.visitEnd();
return classWriter.toByteArray();
}
@Test
public void testSmallTarget() throws Exception {
String targetTestName = ClassRenameVisitorTestTarget.class.getName();
byte[] targetTestBytes = Utilities.loadRequiredResourceAsBytes(Utilities.fulllyQualifiedNameToInternalName(targetTestName) + ".class");
String newName = "THE_NEW_CLASS";
byte[] renamedBytes = new ClassToolchain.Builder(targetTestBytes, PARSING_OPTIONS)
.addNextVisitor(new ClassRenameVisitor(newName))
.addWriter(new ClassWriter(WRITING_OPTIONS))
.build()
.runAndGetBytecode();
Class<?> original = SingleLoader.loadClass(targetTestName, targetTestBytes);
runOnClass(original);
Class<?> rename = SingleLoader.loadClass(newName, renamedBytes);
runOnClass(rename);
}
private void saveJar(JarOutputStream jarOutputStream) throws IOException {
for (ClassNode classNode : this.classMap.values()) {
final JarEntry jarEntry = new JarEntry(classNode.name + ".class");
final ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS);
jarOutputStream.putNextEntry(jarEntry);
classNode.accept(classWriter);
jarOutputStream.write(classWriter.toByteArray());
jarOutputStream.closeEntry();
}
for (Map.Entry<String, byte[]> entry : this.fileMap.entrySet()) {
jarOutputStream.putNextEntry(new JarEntry(entry.getKey()));
jarOutputStream.write(entry.getValue());
jarOutputStream.closeEntry();
}
}
/**
* Not called for built-in types
* @param type the type to generate
* @return the bytecode for that type
*/
byte[] createJCas_TypeCoverClass(TypeImpl type) {
this.type = type;
typeJavaDescriptor = type.getJavaDescriptor();
typeJavaClassName = type.getName().replace('.', '/') + "_Type";
cn = new ClassNode(ASM5); // java 8
cn.version = JAVA_CLASS_VERSION;
cn.access = ACC_PUBLIC + ACC_SUPER;
cn.name = typeJavaClassName;
cn.superName = type.getSuperType().getName().replace('.', '/') + "_Type";
// TODO
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
cn.accept(cw);
return cw.toByteArray();
}
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
if (probes.containsKey(className)) {
try {
ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS);
TimingVisitor visitor = new TimingVisitor(classWriter, probes.get(className));
ClassReader reader = new ClassReader(classfileBuffer);
reader.accept(visitor, 0);
return classWriter.toByteArray();
} catch (Throwable t) {
Logger.getLogger(getClass().getName()).log(Level.SEVERE,
"Failed to instrument " + probes.get(className), t);
return classfileBuffer;
}
} else {
// Use the byte code as is...
return null;
}
}
public static byte[] create(String name, String path) throws IOException {
ClassReader reader = new ClassReader(basicClassBytes());
String slashName = name.replace('.', '/');
ClassWriter writer = new ClassWriter(0);
Remapper remapper = new Remapper() {
@Override
public String map(String typeName) {
if (typeName.equals("org/wildfly/swarm/jaxrs/runtime/DefaultApplication")) {
return slashName;
}
return super.map(typeName);
}
};
ClassRemapper adapter = new ClassRemapper(writer, remapper);
reader.accept(adapter, 0);
AnnotationVisitor ann = writer.visitAnnotation("Ljavax/ws/rs/ApplicationPath;", true);
ann.visit("value", path);
ann.visitEnd();
writer.visitEnd();
return writer.toByteArray();
}
public static void rewriteDataBinderMapper(File dir, String fromName, String toName,
File Clazz) throws IOException {
FileInputStream fileInputStream = new FileInputStream(Clazz);
ClassReader in1 = new ClassReader(fileInputStream);
ClassWriter cw = new ClassWriter(0);
Set<String> renames = new HashSet<String>();
renames.add(fromName);
in1.accept(new ClassRenamer(cw, renames, toName), 8);
File destClass = new File(dir, toName + ".class");
destClass.getParentFile().mkdirs();
FileOutputStream fileOutputStream = new FileOutputStream(destClass);
fileOutputStream.write(cw.toByteArray());
IOUtils.closeQuietly(fileOutputStream);
IOUtils.closeQuietly(fileInputStream);
}
public static byte[] remapClass(byte[] resource, String nameFrom, String nameTo) {
ClassReader reader = new ClassReader(resource);
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
ClassVisitor visitor = new RemappingClassAdapter(writer, new Remapper() {
@Override
public String map(String from) {
if (from.equals(nameFrom)) {
return nameTo;
}
return from;
}
});
reader.accept(visitor, ClassReader.EXPAND_FRAMES);
return writer.toByteArray();
}
private static void visitConstructor(ClassWriter cw) {
MethodVisitor mv;
mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
mv.visitCode();
Label l0 = new Label();
mv.visitLabel(l0);
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
Label l1 = new Label();
mv.visitLabel(l1);
mv.visitInsn(RETURN);
Label l2 = new Label();
mv.visitLabel(l2);
mv.visitMaxs(1, 1);
mv.visitEnd();
}
public byte[] transform(byte[] original, Collection<String> retransformClasses) {
ClassReader reader = new ClassReader(original);
ClassWriter writer = new OfflineClassWriter(classHierarchy, reader, ClassWriter.COMPUTE_FRAMES);
ContinuableClassVisitor visitor = new ContinuableClassVisitor(
writer, /* BytecodeDebugUtils.decorateClassVisitor(cw, true, * System.err) -- DUMP*/
classHierarchy,
cciResolver,
original
);
cciResolver.reset(retransformClasses);
try {
reader.accept(visitor, ClassReader.SKIP_FRAMES);
} catch (StopException ex) {
// Preliminary stop visiting non-continuable class
return null;
}
if (visitor.skipEnchancing()) {
return null;
}
byte[] bytecode = writer.toByteArray();
// BytecodeDebugUtils.dumpClass(bytecode);
return bytecode;
}
private static byte[] instrument(final byte[] classFile, String classFileName, String encoding)
throws IllegalArgumentException {
ClassReader cr = new ClassReader(classFile);
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
ClassVisitor cv = new AndroidClassVisitor(cw, encoding);
if (!cr.getClassName().equals(classFileName)) {
throw new IllegalArgumentException("Class name does not match path");
}
cr.accept(cv, ClassReader.SKIP_DEBUG);
return cw.toByteArray();
}
@Override
protected byte[] transform(final String className,
final Class<?> classBeingRedefined,
final ProtectionDomain protectionDomain,
final byte[] classBytes)
throws IllegalClassFormatException {
if (!Objects.equals(className, debugClassName)) {
return null;
}
LOG.info("debug class: {}", className);
Lock lock = classFileBuffer.getLock();
lock.lock();
try {
final ClassReader classReader = new ClassReader(classFileBuffer.getClassBuffer(classBeingRedefined, classBytes));
final ClassMetadata classMetadata = new ClassMetadata();
classReader.accept(new MetadataCollector(classMetadata), ClassReader.SKIP_FRAMES);
final ClassWriter classWriter = new ClassWriter(computeFlag(classReader));
final ClassVisitor classVisitor = new DebuggerClassVisitor(new CheckClassAdapter(classWriter), source, classMetadata);
classReader.accept(classVisitor, ClassReader.SKIP_FRAMES);
byte[] bytes = classWriter.toByteArray();
classFileBuffer.setClassBuffer(classBeingRedefined, bytes);
return bytes;
} finally {
lock.unlock();
}
}
public InsertMethodBodyAdapter(ClassWriter cw, String className, Map<String, Boolean> methodInstructionTypeMap) {
super(Opcodes.ASM5, cw);
this.classWriter = cw;
this.className = className;
this.methodInstructionTypeMap = methodInstructionTypeMap;
//insert the field
classWriter.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, Constants.INSERT_FIELD_NAME, Type.getDescriptor(ChangeQuickRedirect.class), null, null);
}
@Override
public byte[] transform(String s, String s1, byte[] bytes) {
LogUtil.startClass("GuiOptions (%s)", Names.guiOptions.getName());
ClassReader reader = new ClassReader(bytes);
ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_MAXS);
ClassPatcher visitor = new ClassPatcher(writer);
reader.accept(visitor, 0);
LogUtil.endClass();
return writer.toByteArray();
}
private void addGetterSetter(ClassPair classPair, String className, String classStr, String keyClassType, String valueClassType, ClassWriter cw) {
MethodVisitor getKey = cw.visitMethod(ACC_PUBLIC, "getKey", "()" + keyClassType, null, null);
getKey.visitCode();
getKey.visitVarInsn(ALOAD, 0);
getKey.visitFieldInsn(GETFIELD, className, "key", keyClassType);
getKey.visitInsn(Type.getType(classPair.keyClass).getOpcode(IRETURN));
getKey.visitMaxs(1, 1);
getKey.visitEnd();
MethodVisitor getValue = cw.visitMethod(ACC_PUBLIC, "getValue", "()" + valueClassType, null, null);
getValue.visitCode();
getValue.visitVarInsn(ALOAD, 0);
getValue.visitFieldInsn(GETFIELD, className, "value", valueClassType);
getValue.visitInsn(Type.getType(classPair.valueClass).getOpcode(IRETURN));
getValue.visitMaxs(1, 1);
getValue.visitEnd();
MethodVisitor setKey = cw.visitMethod(ACC_PUBLIC, "setKey", "(" + keyClassType + ")V", null, null);
setKey.visitCode();
setKey.visitVarInsn(ALOAD, 0);
setKey.visitVarInsn(ALOAD, 1);
setKey.visitTypeInsn(CHECKCAST, Type.getInternalName(classPair.keyClass));
setKey.visitFieldInsn(PUTFIELD, classStr, "key", keyClassType);
setKey.visitInsn(RETURN);
setKey.visitMaxs(2, 2);
setKey.visitEnd();
MethodVisitor setValue = cw.visitMethod(ACC_PUBLIC, "setValue", "(" + valueClassType + ")V", null, null);
setValue.visitCode();
setValue.visitVarInsn(ALOAD, 0);
setValue.visitVarInsn(ALOAD, 1);
setValue.visitTypeInsn(CHECKCAST, Type.getInternalName(classPair.valueClass));
setValue.visitFieldInsn(PUTFIELD, classStr, "value", valueClassType);
setValue.visitInsn(RETURN);
setValue.visitMaxs(2, 2);
setValue.visitEnd();
}
private static void addOnAfterMethodTimerOnly(ClassWriter cw) {
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "onAfter",
"(Lorg/glowroot/agent/plugin/api/Timer;)V", null, null);
visitAnnotation(mv, "Lorg/glowroot/agent/plugin/api/weaving/OnAfter;");
checkNotNull(mv.visitParameterAnnotation(0,
"Lorg/glowroot/agent/plugin/api/weaving/BindTraveler;", true)).visitEnd();
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKEINTERFACE, "org/glowroot/agent/plugin/api/Timer", "stop", "()V",
true);
mv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
@Override
public byte[] transform(String s, String s1, byte[] bytes) {
LogUtil.startClass("GuiIngameForge (%s)", Names.guiIngameForge.getName());
ClassReader reader = new ClassReader(bytes);
ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_MAXS);
ClassPatcher visitor = new ClassPatcher(writer);
reader.accept(visitor, 0);
LogUtil.endClass();
return writer.toByteArray();
}
private static byte[] createNoopClass(String className, int instructionCount) {
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
writer.visit(Opcodes.V10, Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER, className, null, "java/lang/Object", new String[0]);
MethodVisitor method = writer.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "main", "()[B", null, null);
for (int i = 0; i < (instructionCount - 2); ++i) {
method.visitInsn(Opcodes.NOP);
}
method.visitInsn(Opcodes.ACONST_NULL);
method.visitInsn(Opcodes.ARETURN);
method.visitMaxs(0, 0);
method.visitEnd();
writer.visitEnd();
return writer.toByteArray();
}
public Map<String, byte[]> getGeneratedClasses() {
Map<String, byte[]> result = new HashMap<String, byte[]>();
for (ClassNode classNode : newClasses) {
ClassWriter cw = new ComputeClassWriter(ClassWriter.COMPUTE_FRAMES, resourceLoader);
classNode.accept(cw);
result.put(classNode.name, cw.toByteArray());
}
return result;
}
public static Map<String, byte[]> stripClinitFromClasses(Map<String, byte[]> transformedClasses){
Map<String, byte[]> immortalClasses = new HashMap<>();
for (Map.Entry<String, byte[]> elt : transformedClasses.entrySet()) {
String className = elt.getKey();
byte[] transformedClass = elt.getValue();
byte[] immortalClass = new ClassToolchain.Builder(transformedClass, 0)
.addNextVisitor(new ClinitStrippingVisitor())
.addWriter(new ClassWriter(0))
.build()
.runAndGetBytecode();
immortalClasses.put(className, immortalClass);
}
return immortalClasses;
}
@Override
public byte[] transform(String s, String s1, byte[] bytes) {
LogUtil.startClass("Minecraft (%s)", Names.minecraft.getName());
ClassReader reader = new ClassReader(bytes);
ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_MAXS);
ClassPatcher visitor = new ClassPatcher(writer);
reader.accept(visitor, 0);
LogUtil.endClass();
return writer.toByteArray();
}
@Override
public byte[] installTrace(byte[] javaClassBytecode) throws IOException {
if (trace == null)
return null;
SourceRelativeURI associatedPath = trace.getAssociatedSrcRelativePath();
if (associatedPath == null)
return null;
ClassReader reader = new ClassReader(javaClassBytecode);
ClassWriter writer = new ClassWriter(0);
String sourceFileName = associatedPath.getURI().lastSegment();
int[] target2source = getTargetToSourceLineMapping(trace);
XtextClassAdapter adapter = new XtextClassAdapter(writer, sourceFileName, target2source, hideSyntheticVariables);
reader.accept(adapter, 0);
return writer.toByteArray();
}
@Override
public byte[] transform(String s, String s1, byte[] bytes) {
LogUtil.startClass("GuiGameOver (%s)", Names.guiGameOver.getName());
ClassReader reader = new ClassReader(bytes);
ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_MAXS);
ClassPatcher visitor = new ClassPatcher(writer);
reader.accept(visitor, 0);
LogUtil.endClass();
return writer.toByteArray();
}
private static Map<String, byte[]> toByteCode(List<ClassNode> classes) {
Map<String, byte[]> out = new LinkedHashMap<>();
for (ClassNode n : classes) {
ClassWriter cw = new ClassWriter(0);
n.accept(cw);
out.put(n.name, cw.toByteArray());
}
return out;
}