下面列出了怎么用org.objectweb.asm.ClassReader的API类实例代码及写法,或者点击链接到github查看源代码。
/**
* Gets a ClassNode based on given bytes
*
* @param bytez
* @return
*/
public static ClassNode getNode(final byte[] bytez) {
ClassReader cr = new ClassReader(bytez);
ClassNode cn = new ClassNode();
try {
cr.accept(cn, ClassReader.EXPAND_FRAMES);
} catch (Exception e) {
try {
cr.accept(cn, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG);
} catch (Exception e2) {
// e2.printStackTrace();
}
}
cr = null;
return cn;
}
@Override
public void onClassFetch(QualifiedContent content, Status status, String relativePath, byte[] bytes) throws IOException {
File outputFile = context.getRelativeFile(content);
byte[] finalBytes = bytes;
if (relativePath.endsWith(".class") && relativePath.contains("com/zane/easyrouter_generated")) {
ClassReader classReader = new ClassReader(finalBytes);
ClassWriter classWriter = new ClassWriter(0);
RenameClassVisistor classVisistor = new RenameClassVisistor(classWriter);
classReader.accept(classVisistor, 0);
if (classVisistor.isFindTarget()) {
relativePath = classVisistor.getFinalName() + ".class";
finalBytes = classWriter.toByteArray();
}
}
directoryWriter.write(outputFile, relativePath, finalBytes);
}
private static boolean isJAXRS(ArchivePath path, Asset asset) {
if (asset == null) {
return false;
}
if (asset instanceof ArchiveAsset) {
return isJAXRS(((ArchiveAsset) asset).getArchive());
}
if (!path.get().endsWith(".class")) {
return false;
}
try (InputStream in = asset.openStream()) {
ClassReader reader = new ClassReader(in);
JAXRSAnnotationSeekingClassVisitor visitor = new JAXRSAnnotationSeekingClassVisitor();
reader.accept(visitor, 0);
return visitor.isFound();
} catch (IOException ignored) {
}
return false;
}
private void scanArchive(File f) {
try (ZipFile zf = new ZipFile(f)) {
Enumeration<? extends ZipEntry> entries = zf.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
if (entry.getName().endsWith(".class")) {
ClassReader reader = new ClassReader(zf.getInputStream(entry));
ClassNode node = new ClassNode();
reader.accept(node, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
AnnotationInfo ai = new AnnotationInfo(this, node);
if (ai.hasData()) {
System.out.println("From " + entry.toString() + " got " + ai.toAnnotationString());
annotatedTypes.put(node.name, ai);
}
}
// TODO resources?
}
} catch (IOException ioe) {
throw new IllegalStateException(ioe);
}
}
private void loadJar(File file) {
try (JarFile jarFile = new JarFile(file)) {
final Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
final JarEntry jarEntry = entries.nextElement();
try (InputStream inputStream = jarFile.getInputStream(jarEntry)) {
final byte[] bytes = IOUtils.toByteArray(inputStream);
if (!jarEntry.getName().endsWith(".class")) {
this.fileMap.put(jarEntry.getName(), bytes);
continue;
}
final ClassNode classNode = new ClassNode();
final ClassReader classReader = new ClassReader(bytes);
classReader.accept(classNode, ClassReader.EXPAND_FRAMES);
this.classMap.put(classNode.name, classNode);
}
}
} catch (IOException ex) {
throw new ObfuscatorException(ex);
}
}
/**
* Try to add the class contained in the given stream to the classes map.
*
* @param name
* Entry name.
* @param is
* Stream of entry.
* @throws IOException
* Thrown if stream could not be read or if ClassNode could not be
* derived from the streamed content.
*/
protected void addClass(String name, InputStream is) {
try {
byte[] value = Streams.from(is);
ClassReader cr = new ClassReader(value);
String className = cr.getClassName();
// Add missing debug information if needed
ClassWriter cw = new ClassWriter(0);
VariableFixer fixer = new VariableFixer();
cr.accept(fixer, 0);
fixer.accept(cw);
if (fixer.isDirty())
value = cw.toByteArray();
// Put value in map
rawNodeMap.put(className, value);
} catch (Exception e) {
Logging.error("Could not parse class: " + name);
e.printStackTrace();
}
}
private static void loadAdaptedClass(File file,
Map<String, String> typeMappnigs, Map<Class<?>, byte[]> result)
throws IOException, ClassNotFoundException {
ClassWriter writer = new ClassWriter(
ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
TestClassAdapter adapter = new TestClassAdapter(writer, typeMappnigs);
InputStream in = new FileInputStream(file);
try {
new ClassReader(in).accept(adapter, ClassReader.EXPAND_FRAMES);
} finally {
try {
in.close();
} catch (IOException e) {
// Ignore.
}
}
byte[] bytes = writer.toByteArray();
String className = adapter.getClassName().replace('/', '.');
result.put(Class.forName(className), bytes); // FIXME: ClassLoader...
}
@Before
public void initializeFinder() throws Exception {
finder = new PropertyFinder();
for (Class<? extends QueryTreeNode> nodeClass : queryTreeNodes) {
try {
ClassReader reader = new ClassReader(nodeClass.getName());
reader.accept(finder, 0);
} catch (IOException e) {
throw new Exception("Could not open class to scan: " + nodeClass.getName(), e);
}
}
// Remove any base class methods here, before they get propagated down
finder.getNodes().get("com/foundationdb/sql/parser/DDLStatementNode")
.removeMethod("getRelativeName", "()Ljava/lang/String;")
.removeMethod("getFullName", "()Ljava/lang/String;");
finder.finalizeState();
// Remove any concrete class methods here, base class methods have already been propagated down
removeTemporarilyIgnoredUnused(finder);
}
public String getDebugInfo(File file) {
if (file.isFile() && file.getName().endsWith(".class")) {
try {
ClassReader cr = new ClassReader(Files.toByteArray(file));
ClassVisitor visitor = new ClassVisitor(file.getName());
cr.accept(visitor, 0);
return visitor.toString();
} catch (IOException e) {
throw new RuntimeException(e);
}
} else if (file.isDirectory()) {
List<String> children = Lists.newArrayList();
for (File child : file.listFiles()) {
String info = getDebugInfo(child);
if (!Strings.isEmpty(info))
children.add(info);
}
Collections.sort(children);
StringBuffer buf = new StringBuffer();
buf.append("// " + file.getName() + " {\n");
buf.append(" " + Joiner.on("\n\n").join(children).replace("\n", "\n ") + "\n");
buf.append("}");
return buf.toString();
}
return null;
}
public static Class<?> getClass(String className, Options options) throws ClassNotFoundException, IOException {
String classFilename = className.replace('.', '/') + ".class";
InputStream stream = FabricLauncherBase.getLauncher().getResourceAsStream(classFilename);
if (stream == null) {
throw new ClassNotFoundException("Could not find or load class " + classFilename);
}
ClassReader reader = new ClassReader(stream);
for (String s : reader.getInterfaces()) {
if (!canApplyInterface(s)) {
switch (options.getMissingSuperclassBehavior()) {
case RETURN_NULL:
stream.close();
return null;
case CRASH:
default:
stream.close();
throw new ClassNotFoundException("Could not find or load class " + s);
}
}
}
stream.close();
return FabricLauncherBase.getClass(className);
}
public static void printClassesWithTypes(Path inputJarFile, PrintWriter printWriter)
throws IOException {
Preconditions.checkState(
Files.exists(inputJarFile), "The input jar file %s does not exist.", inputJarFile);
try (ZipFile jarFile = new ZipFile(inputJarFile.toFile())) {
for (ZipEntry entry : getSortedClassEntriess(jarFile)) {
try (InputStream classStream = jarFile.getInputStream(entry)) {
printWriter.println("\nClass: " + entry.getName());
ClassReader classReader = new ClassReader(classStream);
ClassVisitor visitor = new ClassWithTypeDumper(printWriter);
classReader.accept(visitor, 0);
}
printWriter.println("\n");
}
}
}
@OnlyUsedByTests
private static PointcutClass buildAdviceClassLookAtSuperClass(String internalName)
throws IOException {
URL url =
checkNotNull(PluginDetailBuilder.class.getResource("/" + internalName + ".class"));
byte[] bytes = Resources.asByteSource(url).read();
MemberClassVisitor mcv = new MemberClassVisitor();
new ClassReader(bytes).accept(mcv, ClassReader.SKIP_CODE);
ImmutablePointcutClass pointcutClass = mcv.buildPointcutClass(bytes, false, null);
String superName = checkNotNull(mcv.superName);
if (!"java/lang/Object".equals(superName)) {
pointcutClass = ImmutablePointcutClass.builder()
.copyFrom(pointcutClass)
.addAllMethods(buildAdviceClassLookAtSuperClass(superName).methods())
.build();
}
return pointcutClass;
}
public static void viewByteCode(byte[] bytecode) {
ClassReader classReader = new ClassReader(bytecode);
ClassNode classNode = new ClassNode();
classReader.accept(classNode, 0);
final List<MethodNode> methodNodes = classNode.methods;
Printer printer = new Textifier();
TraceMethodVisitor traceMethodVisitor = new TraceMethodVisitor(printer);
for (MethodNode methodNode : methodNodes) {
InsnList insnList = methodNode.instructions;
System.out.println(methodNode.name);
for (int i = 0; i < insnList.size(); i++) {
insnList.get(i).accept(traceMethodVisitor);
StringWriter sw = new StringWriter();
printer.print(new PrintWriter(sw));
printer.getText().clear();
System.out.print(sw.toString());
}
}
}
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();
}
}
@Override
public Mutant getMutation(final MutationIdentifier id) {
final ClassContext context = new ClassContext();
context.setTargetMutation(Optional.ofNullable(id));
final Optional<byte[]> bytes = this.byteSource.getBytes(id.getClassName()
.asJavaName());
final ClassReader reader = new ClassReader(bytes.get());
final ClassWriter w = new ComputeClassWriter(this.byteSource,
this.computeCache, FrameOptions.pickFlags(bytes.get()));
final MutatingClassVisitor mca = new MutatingClassVisitor(w, context,
filterMethods(), FCollection.filter(this.mutators,
isMutatorFor(id)));
reader.accept(mca, ClassReader.EXPAND_FRAMES);
final List<MutationDetails> details = context.getMutationDetails(context
.getTargetMutation().get());
return new Mutant(details.get(0), w.toByteArray());
}
/**
* Creates a new ClassNode instances from the provided byte[]
*
* @param bytez the class file's byte[]
* @return the ClassNode instance
*/
public static ClassNode getNode(final byte[] bytez) throws Exception {
ClassReader cr = new ClassReader(bytez);
ClassNode cn = new ClassNode();
try {
cr.accept(cn, ClassReader.EXPAND_FRAMES);
} catch (Exception e) {
try {
cr.accept(cn, ClassReader.SKIP_FRAMES);
} catch (Exception e2) {
throw e2;
}
}
cr = null;
return cn;
}
private List<String> getClassDependencies(ClassRelevancyFilter filter, ClassReader reader) {
List<String> out = new LinkedList<String>();
char[] charBuffer = new char[reader.getMaxStringLength()];
for (int i = 1; i < reader.getItemCount(); i++) {
int itemOffset = reader.getItem(i);
if (itemOffset > 0 && reader.readByte(itemOffset - 1) == 7) {
// A CONSTANT_Class entry, read the class descriptor
String classDescriptor = reader.readUTF8(itemOffset, charBuffer);
Type type = Type.getObjectType(classDescriptor);
while (type.getSort() == Type.ARRAY) {
type = type.getElementType();
}
if (type.getSort() != Type.OBJECT) {
// A primitive type
continue;
}
String name = type.getClassName();
if (filter.isRelevant(name)) {
out.add(name);
}
}
}
return out;
}
private static ClassAnalyzeVisitor readClassFromJar(
ClassReader classReader, String nameWithoutTP, String nameWithTP) {
ClassAnalyzeVisitor classAnalyzeVisitor =
new ClassAnalyzeVisitor(nameWithoutTP, nameWithTP, false, false);
classReader.accept(classAnalyzeVisitor, 0);
return classAnalyzeVisitor;
}
@Test
public void testFrameAdviceStaticMethodExpanded() throws Exception {
Class<?> type = new ByteBuddy()
.redefine(FrameSample.class)
.visit(Advice.to(advice).on(named(BAR)).readerFlags(ClassReader.EXPAND_FRAMES))
.make()
.load(ClassLoadingStrategy.BOOTSTRAP_LOADER, ClassLoadingStrategy.Default.WRAPPER)
.getLoaded();
assertThat(type.getDeclaredMethod(BAR, String.class).invoke(null, FOO), is((Object) FOO));
assertThat(type.getField(COUNT).getInt(null), is((Object) count));
}
public CustomClassWriter() {
try {
reader = new ClassReader(CLASSNAME);
writer = new ClassWriter(reader, 0);
} catch (IOException ex) {
Logger.getLogger(CustomClassWriter.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static Field make() throws IOException, ClassNotFoundException, NoSuchFieldException {
ClassReader classReader = new ClassReader(InconsistentGenerics.class.getName());
ClassWriter classWriter = new ClassWriter(classReader, ClassWriter.COMPUTE_MAXS);
classReader.accept(new GenericDisintegrator(classWriter), 0);
return new ByteArrayClassLoader(ClassLoadingStrategy.BOOTSTRAP_LOADER,
Collections.singletonMap(InconsistentGenerics.class.getName(), classWriter.toByteArray()),
ByteArrayClassLoader.PersistenceHandler.MANIFEST)
.loadClass(InconsistentGenerics.class.getName()).getDeclaredField(FOO);
}
private static Thruple<Boolean, byte[], HashSet<String>> addCopyConstructorAndOffHeapMethods(byte[] inputClass, ConcurnasClassLoader loader){
//should only modify conc files, java files being called can be ingored
ClassReader origReader = new ClassReader(inputClass);
ConcClassWriter cw = new ConcClassWriter(ClassWriter.COMPUTE_MAXS|ClassWriter.COMPUTE_FRAMES, loader.getDetector());//TODO: consider removing COMPUTE_MAXS | COMPUTE_FRAMES this to make load time quicker
ClonerTransformer clonerTrans = new ClonerTransformer(cw, loader);
origReader.accept(clonerTrans, 0 );
byte[] outputCode = cw.toByteArray();
outputCode = OffHeapAugmentor.addOffHeapMethods(outputCode, loader);
String clsName = clonerTrans.theCurrentclass;
clsName = clsName.substring(1, clsName.length()-1);
outputCode = RefFieldMapper.doMapping(outputCode, clsName, loader);
/*try {
BytecodePrettyPrinter.print(outputCode, true);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} */
//TODO: add immutable annotation for use in Cloner so as to avoid unecisary cloneing
Boolean isImmutable = !clonerTrans.immutableDependsOn.isEmpty()?null:(clonerTrans.isActor || clonerTrans.isImmutable || clonerTrans.isEnum);
return new Thruple<Boolean, byte[], HashSet<String>>(isImmutable, outputCode, clonerTrans.immutableDependsOn);
}
/**
* {@inheritDoc}
* @param classLoader the class loader that loaded this class
* @param alwaysStatic whether to always load class data statically
*/
public StaticClassWriter(
ClassReader classReader, int flags, ClassLoader classLoader,
boolean alwaysStatic) {
super(classReader, flags);
this.classLoader = classLoader;
this.alwaysStatic = alwaysStatic;
}
@Test
public void ModifyClassTest() throws Exception {
// 读取的Person类的class文件
ClassReader classReader = new ClassReader("org.javamaster.b2c.bytecode.model.Person");
ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS);
ClassAdapter classAdapter = new ClassAdapter(classWriter);
classReader.accept(classAdapter, ClassReader.SKIP_DEBUG);
// 插入新方法
// Opcodes.ACC_PUBLIC:方法修饰符为public
// sayHello:方法名为sayHello
// ()V:没有入参,返回类型为void
// new String[]{"javax.validation.ValidationException"}:声明抛出ValidationException异常
MethodVisitor helloVisitor = classWriter
.visitMethod(Opcodes.ACC_PUBLIC, "sayHello", "()V", null, new String[]{"javax.validation.ValidationException"});
// 插入方法体内容,以下涉及到了虚拟机字节码指令
helloVisitor.visitCode();
// getstatic 指令:取静态字段
helloVisitor.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
// ldc 指令:取"hello world!"常量到操作数栈
helloVisitor.visitLdcInsn("hello world!");
// invokevirtual 指令: 调用实例方法println
helloVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
// return 指令: 从当前方法返回void
helloVisitor.visitInsn(Opcodes.RETURN);
helloVisitor.visitMaxs(1, 1);
helloVisitor.visitEnd();
byte[] bytes = classWriter.toByteArray();
String path = ResourceUtils.getFile("classpath:").getAbsolutePath();
File file = new File(path, "/org/javamaster/b2c/bytecode/PersonModify.class");
FileOutputStream fileOutputStream = new FileOutputStream(file);
fileOutputStream.write(bytes);
fileOutputStream.close();
}
@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 ClassNode getClassNode(String name, boolean runTransformers) throws ClassNotFoundException, IOException {
ClassReader reader = new ClassReader(getClassBytes(name, runTransformers));
ClassNode node = new ClassNode();
reader.accept(node, 0);
return node;
}
static List<Advice> mergeInstrumentationAnnotations(List<Advice> advisors, byte[] classBytes,
@Nullable ClassLoader loader, String className) {
byte[] marker = "Lorg/glowroot/agent/api/Instrumentation$".getBytes(UTF_8);
if (Bytes.indexOf(classBytes, marker) == -1) {
return advisors;
}
InstrumentationSeekerClassVisitor cv = new InstrumentationSeekerClassVisitor();
ClassReader cr = new ClassReader(classBytes);
cr.accept(cv, ClassReader.SKIP_CODE);
List<InstrumentationConfig> instrumentationConfigs = cv.getInstrumentationConfigs();
if (instrumentationConfigs.isEmpty()) {
return advisors;
}
if (loader == null) {
logger.warn("@Instrumentation annotations not currently supported in bootstrap class"
+ " loader: {}", className);
return advisors;
}
for (InstrumentationConfig instrumentationConfig : instrumentationConfigs) {
instrumentationConfig.logValidationErrorsIfAny();
}
ImmutableMap<Advice, LazyDefinedClass> newAdvisors =
AdviceGenerator.createAdvisors(instrumentationConfigs, null, false, false);
try {
ClassLoaders.defineClasses(newAdvisors.values(), loader);
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
List<Advice> mergedAdvisors = Lists.newArrayList(advisors);
mergedAdvisors.addAll(newAdvisors.keySet());
return mergedAdvisors;
}
@Override
public byte[] transform(String s, String s1, byte[] bytes) {
LogUtil.startClass("GuiEditSign (%s)", Names.guiEditSign.getName());
ClassReader reader = new ClassReader(bytes);
ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
ClassPatcher visitor = new ClassPatcher(writer);
reader.accept(visitor, 0);
LogUtil.endClass();
return writer.toByteArray();
}
private String getCommonClass(final ClassReader classReader1, final ClassReader classReader2) {
final Set<String> classHierarchy = new HashSet<String>();
classHierarchy.add(classReader1.getClassName());
classHierarchy.add(classReader2.getClassName());
String superClassInternalName1 = classReader1.getSuperName();
if (!classHierarchy.add(superClassInternalName1)) {
// find common super class.
return superClassInternalName1;
}
String superClassInternalName2 = classReader2.getSuperName();
if (!classHierarchy.add(superClassInternalName2)) {
// find common super class.
return superClassInternalName2;
}
while (superClassInternalName1 != null || superClassInternalName2 != null) {
// for each.
if (superClassInternalName1 != null) {
superClassInternalName1 = getSuperClassInternalName(superClassInternalName1);
if (superClassInternalName1 != null) {
if (!classHierarchy.add(superClassInternalName1)) {
return superClassInternalName1;
}
}
}
if (superClassInternalName2 != null) {
superClassInternalName2 = getSuperClassInternalName(superClassInternalName2);
if (superClassInternalName2 != null) {
if (!classHierarchy.add(superClassInternalName2)) {
return superClassInternalName2;
}
}
}
}
return OBJECT_CLASS_INTERNAL_NAME;
}
@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();
}