Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.springsource.loaded.ClassRenamer Maven / Gradle / Ivy
/*
* Copyright 2010-2012 VMware and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springsource.loaded;
import java.util.HashMap;
import java.util.Map;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Handle;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
/**
* Modify a class by changing it from one name to another. References to other types can also be changed. Basically used
* in the test suite.
*
* @author Andy Clement
* @since 0.5.0
*/
public class ClassRenamer {
/**
* Rename a type - changing it to specified new name (which should be the dotted form of the name). Retargets are an
* optional sequence of retargets to also perform during the rename. Retargets take the form of "a.b:a.c" which will
* change all references to a.b to a.c.
*
* @param dottedNewName dotted name, e.g. com.foo.Bar
* @param classbytes the bytecode for the class to be renamed
* @param retargets retarget rules for references, of the form "a.b:b.a","c.d:d.c"
* @return bytecode for the modified class
*/
public static byte[] rename(String dottedNewName, byte[] classbytes, String... retargets) {
ClassReader fileReader = new ClassReader(classbytes);
RenameAdapter renameAdapter = new RenameAdapter(dottedNewName, retargets);
fileReader.accept(renameAdapter, 0);
byte[] renamed = renameAdapter.getBytes();
return renamed;
}
static class RenameAdapter extends ClassVisitor implements Opcodes {
private ClassWriter cw;
private String oldname;
private String newname;
private Map retargets = new HashMap();
public RenameAdapter(String newname, String[] retargets) {
super(ASM5, new ClassWriter(0));
cw = (ClassWriter) cv;
this.newname = newname.replace('.', '/');
if (retargets != null) {
for (String retarget : retargets) {
int i = retarget.indexOf(":");
this.retargets.put(retarget.substring(0, i).replace('.', '/'),
retarget.substring(i + 1).replace('.', '/'));
}
}
}
public byte[] getBytes() {
return cw.toByteArray();
}
private String retargetIfNecessary(String string) {
String value = retargets.get(string);
return value == null ? string : value;
}
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
oldname = name;
if (superName != null) {
superName = retargetIfNecessary(superName);
}
if (interfaces != null) {
for (int i = 0; i < interfaces.length; i++) {
interfaces[i] = retargetIfNecessary(interfaces[i]);
}
}
super.visit(version, access, newname, signature, superName, interfaces);
}
@Override
public void visitInnerClass(String name, String outername, String innerName, int access) {
super.visitInnerClass(renameRetargetIfNecessary(name), renameRetargetIfNecessary(outername),
renameRetargetIfNecessary(innerName), access);
}
private String renameRetargetIfNecessary(String string) {
String value = retargets.get(string);
if (value != null) {
return value;
}
if (string != null && string.indexOf(oldname) != -1) {
return string.replace(oldname, newname);
}
return string;
}
@Override
public MethodVisitor visitMethod(int flags, String name, String descriptor, String signature,
String[] exceptions) {
if (descriptor.indexOf(oldname) != -1) {
descriptor = descriptor.replace(oldname, newname);
}
else {
if (descriptor.indexOf(oldname) != -1) {
descriptor = descriptor.replace(oldname, newname);
}
for (String s : retargets.keySet()) {
if (descriptor.indexOf(s) != -1) {
descriptor = descriptor.replace(s, retargets.get(s));
}
}
}
MethodVisitor mv = super.visitMethod(flags, name, descriptor, signature, exceptions);
return new RenameMethodAdapter(mv, oldname, newname);
}
@Override
public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
if (desc.indexOf(oldname) != -1) {
desc = desc.replace(oldname, newname);
}
else {
for (String s : retargets.keySet()) {
if (desc.indexOf(s) != -1) {
desc = desc.replace(s, retargets.get(s));
}
}
}
return super.visitField(access, name, desc, signature, value);
}
class RenameMethodAdapter extends MethodVisitor implements Opcodes {
String oldname;
String newname;
public RenameMethodAdapter(MethodVisitor mv, String oldname, String newname) {
super(ASM5, mv);
this.oldname = oldname;
this.newname = newname;
}
public void visitFieldInsn(int opcode, String owner, String name, String desc) {
if (owner.equals(oldname)) {
owner = newname;
}
else {
String retarget = retargets.get(owner);
if (retarget != null) {
owner = retarget;
}
}
if (desc.indexOf(oldname) != -1) {
desc = desc.replace(oldname, newname);
}
else {
desc = checkIfShouldBeRewritten(desc);
}
mv.visitFieldInsn(opcode, owner, name, desc);
}
public void visitTypeInsn(int opcode, String type) {
if (type.equals(oldname)) {
type = newname;
}
else {
String retarget = retargets.get(type);
if (retarget != null) {
type = retarget;
}
else {
if (type.startsWith("[")) {
if (type.indexOf(oldname) != -1) {
type = type.replaceFirst(oldname, newname);
}
}
}
}
mv.visitTypeInsn(opcode, type);
}
@Override
public void visitLdcInsn(Object obj) {
// System.out.println("Possibly remapping "+obj);
if (obj instanceof Type) {
Type t = (Type) obj;
String s = t.getInternalName();
String retarget = retargets.get(s);
if (retarget != null) {
mv.visitLdcInsn(Type.getObjectType(retarget));
}
else {
mv.visitLdcInsn(obj);
}
}
else if (obj instanceof String) {
String s = (String) obj;
String retarget = retargets.get(s.replace('.', '/'));
if (retarget != null) {
mv.visitLdcInsn(retarget.replace('/', '.'));
}
else {
String oldnameDotted = oldname.replace('/', '.');
if (s.equals(oldnameDotted)) {
String nname = newname.replace('/', '.');
mv.visitLdcInsn(nname);
return;
}
else if (s.startsWith("[")) {
// might be array of oldname
if (s.indexOf(oldnameDotted) != -1) {
mv.visitLdcInsn(s.replaceFirst(oldnameDotted, newname.replace('/', '.')));
return;
}
}
mv.visitLdcInsn(obj);
}
}
else {
mv.visitLdcInsn(obj);
}
}
private String toString(Handle bsm) {
return "[" + bsm.getTag() + "]" + bsm.getOwner() + "." + bsm.getName() + bsm.getDesc();
}
private String toString(Object[] os) {
StringBuilder buf = new StringBuilder();
if (os != null) {
buf.append("[");
for (int i = 0; i < os.length; i++) {
if (i > 0)
buf.append(",");
buf.append(os[i]);
}
buf.append("]");
}
else {
return "null";
}
return buf.toString();
}
private Handle retargetHandle(Handle oldHandle) {
int tag = oldHandle.getTag();
String owner = oldHandle.getOwner();
String name = oldHandle.getName();
String desc = oldHandle.getDesc();
// System.out.println("handle: owner: "+owner);
// System.out.println("handle: name: "+name);
// System.out.println("handle: desc: "+desc);
owner = renameRetargetIfNecessary(owner);
desc = renameRetargetIfNecessary(desc);
Handle newHandle = new Handle(tag, owner, name, desc);
return newHandle;
}
@Override
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) {
// Example:
// visitInvokeDynamicInsn(name=m,desc=()Lbasic/LambdaA2$Foo;,
// bsm=[6]java/lang/invoke/LambdaMetafactory.metafactory(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;,
// bsmArgs=[()I,basic/LambdaA2.lambda$run$1()I (6),()I])
desc = renameRetargetIfNecessary(desc);
if (bsmArgs[1] instanceof Handle) {
bsmArgs[1] = retargetHandle((Handle) bsmArgs[1]);
}
mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
}
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
if (owner.equals(oldname)) {
owner = newname;
}
else {
owner = retargetIfNecessary(owner);
}
if (desc.indexOf(oldname) != -1) {
desc = desc.replace(oldname, newname);
}
else {
desc = checkIfShouldBeRewritten(desc);
}
mv.visitMethodInsn(opcode, owner, name, desc, itf);
}
private String checkIfShouldBeRewritten(String desc) {
for (String s : retargets.keySet()) {
if (desc.indexOf(s) != -1) {
desc = desc.replace(s, retargets.get(s));
}
}
return desc;
}
}
}
}