- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
假设我有一个简单的
class C$Manipulatables{
public Wrapper get(long v, String f){
if(v == 0){
return new Wrapper(0);
}else{
throw new RuntimeException("unacceptable: v not found");
}
}
}
我现在想在 C$Manipulatables
中重新定义 get
,s.t.上面写着
class C$Manipulatables{
public Wrapper get(long v, String f){
if(v == 1){ return null; }
if(v == 0){
return new Wrapper(0);
}else{
throw new RuntimeException("unacceptable: v not found");
}
}
}
如果我尝试使用新值,这将触发空指针异常,但没关系 - 现在我只想确认新代码已加载。
我们使用 ASM 添加代码(我将在这篇文章的底部添加完整的可复制粘贴代码,所以我只是放大相关部分,在这里):
class AddingMethodVisitor extends MethodVisitor implements Opcodes{
int v;
public AddingMethodVisitor(int v, int api, MethodVisitor mv) {
super(api, mv);
this.v = v;
}
@Override
public void visitCode() {
super.visitCode();
mv.visitVarInsn(LLOAD, 1); //arg 1 of method is version number
/*if arg1 == the new version*/
mv.visitLdcInsn(v);
Label lSkip = new Label();
mv.visitInsn(LCMP);
mv.visitJumpInsn(IFNE, lSkip);
mv.visitInsn(ACONST_NULL);
mv.visitInsn(ARETURN);
/*else*/
mv.visitLabel(lSkip);
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
}
}
并使用 ByteBuddy 重新加载类(同样,帖子底部的完整代码):
ClassReader cr;
try {
/*note to self: don't forget the ``.getClassLoader()``*/
cr = new ClassReader(manipsClass.getClassLoader().getResourceAsStream( manipsClass.getName().replace('.','/') + ".class"));
}catch(IOException e){
throw new RuntimeException(e);
}
ClassWriter cw = new ClassWriter(cr, 0);
VersionAdder adder = new VersionAdder(C.latest + 1,Opcodes.ASM5,cw);
cr.accept(adder,0);
System.out.println("reloading C$Manipulatables class");
byte[] bytes = cw.toByteArray();
ClassFileLocator classFileLocator = ClassFileLocator.Simple.of(manipsClass.getName(), bytes);
new ByteBuddy()
.redefine(manipsClass,classFileLocator)
.name(manipsClass.getName())
.make()
.load(C.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent())
;
C.latest++;
System.out.println("RELOADED");
}
}
这失败了。
got 0
reloading C$Manipulatables class
Exception in thread "main" java.lang.VerifyError
at sun.instrument.InstrumentationImpl.redefineClasses0(Native Method)
at sun.instrument.InstrumentationImpl.redefineClasses(InstrumentationImpl.java:170)
at net.bytebuddy.dynamic.loading.ClassReloadingStrategy$Strategy$1.apply(ClassReloadingStrategy.java:261)
at net.bytebuddy.dynamic.loading.ClassReloadingStrategy.load(ClassReloadingStrategy.java:171)
at net.bytebuddy.dynamic.TypeResolutionStrategy$Passive.initialize(TypeResolutionStrategy.java:79)
at net.bytebuddy.dynamic.DynamicType$Default$Unloaded.load(DynamicType.java:4456)
at redefineconcept.CInserter.addNext(CInserter.java:60)
at redefineconcept.CInserter.run(CInserter.java:22)
at redefineconcept.CInserter.main(CInserter.java:16)
Process finished with exit code 1
事实上,当我评论 return null
stmt 生成时(正如我在下面提供的完整代码中所做的那样),这甚至会失败。
显然,java 只是不喜欢我构造我的 IF 的方式,即使它本质上是我在
上使用asmifier
时得到的代码
public class B {
public Object run(long version, String field){
if(version == 2) {
return null;
}
return null;
}
}
产生了
{
mv = cw.visitMethod(ACC_PUBLIC, "run", "(JLjava/lang/String;)Ljava/lang/Object;", null, null);
mv.visitCode();
mv.visitVarInsn(LLOAD, 1);
mv.visitLdcInsn(new Long(2L));
mv.visitInsn(LCMP);
Label l0 = new Label();
mv.visitJumpInsn(IFNE, l0);
mv.visitInsn(ACONST_NULL);
mv.visitInsn(ARETURN);
mv.visitLabel(l0);
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
mv.visitInsn(ACONST_NULL);
mv.visitInsn(ARETURN);
mv.visitMaxs(4, 4);
mv.visitEnd();
}
我只是简单地离开了之后的一切
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
因为在那之后,方法的已经存在的部分紧随其后。
我确实相信 Java 不喜欢 visitFrame
的某些方面。
假设我更改了我的 visitCode
s.t.上面写着
public void visitCode() {
super.visitCode();
mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
mv.visitLdcInsn("Work, you ..!");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
// mv.visitVarInsn(LLOAD, 1); //arg 1 of method is version number
//
// /*if arg1 == the new version*/
// mv.visitLdcInsn(v);
// Label lSkip = new Label();
//
// mv.visitInsn(LCMP);
// mv.visitJumpInsn(IFNE, lSkip);
//
//// mv.visitInsn(ACONST_NULL);
//// mv.visitInsn(ARETURN);
//
// /*else*/
// mv.visitLabel(lSkip);
// mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
}
然后重新定义工作。我得到了预期的异常,因为代码落入了无法处理新版本号的原始 if-else block ,但至少我确实得到了输出。
got 0
reloading C$Manipulatables class
RELOADED
Work, you ..!
Exception in thread "main" java.lang.RuntimeException: unacceptable: v not found
at redefineconcept.C$Manipulatables.get(C.java:27)
at redefineconcept.C.get(C.java:10)
at redefineconcept.CInserter.run(CInserter.java:23)
at redefineconcept.CInserter.main(CInserter.java:16)
如果您能帮我解决这个问题,我将不胜感激。插入 java 将接受的新 if stmt 的正确方法是什么?
完整代码
C.java
(注意 C$Manipulatables
类是必需的,因为 ByteBuddy
不能重新定义具有静态初始化器的类。)
package redefineconcept;
public class C {
public static volatile int latest = 0;
public static final C$Manipulatables manips = new C$Manipulatables();
public int get(){
int v = latest;
return manips.get(v,"").value;
}
}
class Wrapper{
int value;
public Wrapper(int value){
this.value = value;
}
}
class C$Manipulatables{
public Wrapper get(long v, String f){
if(v == 0){
return new Wrapper(0);
}else{
throw new RuntimeException("unacceptable: v not found");
}
}
}
CInserter.java
package redefineconcept;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.agent.ByteBuddyAgent;
import net.bytebuddy.dynamic.ClassFileLocator;
import net.bytebuddy.dynamic.loading.ClassReloadingStrategy;
import net.bytebuddy.jar.asm.*;
import java.io.IOException;
public class CInserter {
public static void main(String[] args) {
ByteBuddyAgent.install();
new CInserter().run();
}
private void run(){
C c = new C();
System.out.println("got " + c.get());
addNext();
System.out.println("got " + c.get()); //should trigger nullptr exception
}
private void addNext(){
Object manips;
String manipsFld = "manips";
try {
manips = C.class.getDeclaredField(manipsFld).get(null);
}catch(NoSuchFieldException | IllegalAccessException e){
throw new RuntimeException(e);
}
Class<?> manipsClass = manips.getClass();
assert(manipsClass.getName().equals("redefineconcept.C$Manipulatables"));
ClassReader cr;
try {
/*note to self: don't forget the ``.getClassLoader()``*/
cr = new ClassReader(manipsClass.getClassLoader().getResourceAsStream( manipsClass.getName().replace('.','/') + ".class"));
}catch(IOException e){
throw new RuntimeException(e);
}
ClassWriter cw = new ClassWriter(cr, 0);
VersionAdder adder = new VersionAdder(C.latest + 1,Opcodes.ASM5,cw);
cr.accept(adder,0);
System.out.println("reloading C$Manipulatables class");
byte[] bytes = cw.toByteArray();
ClassFileLocator classFileLocator = ClassFileLocator.Simple.of(manipsClass.getName(), bytes);
new ByteBuddy()
.redefine(manipsClass,classFileLocator)
.name(manipsClass.getName())
.make()
.load(C.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent())
;
C.latest++;
System.out.println("RELOADED");
}
}
class VersionAdder extends ClassVisitor{
private int v;
public VersionAdder(int v, int api, ClassVisitor cv) {
super(api, cv);
this.v = v;
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
if(mv != null && name.equals("get")){
return new AddingMethodVisitor(v,Opcodes.ASM5,mv);
}
return mv;
}
class AddingMethodVisitor extends MethodVisitor implements Opcodes{
int v;
public AddingMethodVisitor(int v, int api, MethodVisitor mv) {
super(api, mv);
this.v = v;
}
@Override
public void visitCode() {
super.visitCode();
mv.visitVarInsn(LLOAD, 1); //arg 1 of method is version number
/*if arg1 == the new version*/
mv.visitLdcInsn(v);
Label lSkip = new Label();
mv.visitInsn(LCMP);
mv.visitJumpInsn(IFNE, lSkip);
// mv.visitInsn(ACONST_NULL);
// mv.visitInsn(ARETURN);
/*else*/
mv.visitLabel(lSkip);
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
}
}
}
最佳答案
我在您的代码中注意到的一个错误是以下行
mv.visitLdcInsn(v);
这段代码的目的是创建并加载一个 long 常量,但是 v
的类型是 int
,因此将创建一个整型常量,从而创建一个类型将字节码与下一行的 lcmp
进行比较时出现字节码错误。 visitLdcInsn
将根据您传入的对象类型创建不同的常量类型,因此参数必须是您想要的确切类型。
附带说明,您首先不需要 LDC 来创建值为 1 的长整型常量,因为有专门的字节码指令用于此,lconst_1
。在 ASM 中,这应该类似于 visitInsn(LCONST_1);
关于java - 在运行时向方法添加 if stmt 时出现 VerifyException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47459014/
我正在编写一个具有以下签名的 Java 方法。 void Logger(Method method, Object[] args); 如果一个方法(例如 ABC() )调用此方法 Logger,它应该
我是 Java 新手。 我的问题是我的 Java 程序找不到我试图用作的图像文件一个 JButton。 (目前这段代码什么也没做,因为我只是得到了想要的外观第一的)。这是我的主课 代码: packag
好的,今天我在接受采访,我已经编写 Java 代码多年了。采访中说“Java 垃圾收集是一个棘手的问题,我有几个 friend 一直在努力弄清楚。你在这方面做得怎么样?”。她是想骗我吗?还是我的一生都
我的 friend 给了我一个谜语让我解开。它是这样的: There are 100 people. Each one of them, in his turn, does the following
如果我将使用 Java 5 代码的应用程序编译成字节码,生成的 .class 文件是否能够在 Java 1.4 下运行? 如果后者可以工作并且我正在尝试在我的 Java 1.4 应用程序中使用 Jav
有关于why Java doesn't support unsigned types的问题以及一些关于处理无符号类型的问题。我做了一些搜索,似乎 Scala 也不支持无符号数据类型。限制是Java和S
我只是想知道在一个 java 版本中生成的字节码是否可以在其他 java 版本上运行 最佳答案 通常,字节码无需修改即可在 较新 版本的 Java 上运行。它不会在旧版本上运行,除非您使用特殊参数 (
我有一个关于在命令提示符下执行 java 程序的基本问题。 在某些机器上我们需要指定 -cp 。 (类路径)同时执行java程序 (test为java文件名与.class文件存在于同一目录下) jav
我已经阅读 StackOverflow 有一段时间了,现在我才鼓起勇气提出问题。我今年 20 岁,目前在我的家乡(罗马尼亚克卢日-纳波卡)就读 IT 大学。足以介绍:D。 基本上,我有一家提供簿记应用
我有 public JSONObject parseXML(String xml) { JSONObject jsonObject = XML.toJSONObject(xml); r
我已经在 Java 中实现了带有动态类型的简单解释语言。不幸的是我遇到了以下问题。测试时如下代码: def main() { def ks = Map[[1, 2]].keySet()
一直提示输入 1 到 10 的数字 - 结果应将 st、rd、th 和 nd 添加到数字中。编写一个程序,提示用户输入 1 到 10 之间的任意整数,然后以序数形式显示该整数并附加后缀。 public
我有这个 DownloadFile.java 并按预期下载该文件: import java.io.*; import java.net.URL; public class DownloadFile {
我想在 GUI 上添加延迟。我放置了 2 个 for 循环,然后重新绘制了一个标签,但这 2 个 for 循环一个接一个地执行,并且标签被重新绘制到最后一个。 我能做什么? for(int i=0;
我正在对对象 Student 的列表项进行一些测试,但是我更喜欢在 java 类对象中创建硬编码列表,然后从那里提取数据,而不是连接到数据库并在结果集中选择记录。然而,自从我这样做以来已经很长时间了,
我知道对象创建分为三个部分: 声明 实例化 初始化 classA{} classB extends classA{} classA obj = new classB(1,1); 实例化 它必须使用
我有兴趣使用 GPRS 构建车辆跟踪系统。但是,我有一些问题要问以前做过此操作的人: GPRS 是最好的技术吗?人们意识到任何问题吗? 我计划使用 Java/Java EE - 有更好的技术吗? 如果
我可以通过递归方法反转数组,例如:数组={1,2,3,4,5} 数组结果={5,4,3,2,1}但我的结果是相同的数组,我不知道为什么,请帮助我。 public class Recursion { p
有这样的标准方式吗? 包括 Java源代码-测试代码- Ant 或 Maven联合单元持续集成(可能是巡航控制)ClearCase 版本控制工具部署到应用服务器 最后我希望有一个自动构建和集成环境。
我什至不知道这是否可能,我非常怀疑它是否可能,但如果可以,您能告诉我怎么做吗?我只是想知道如何从打印机打印一些文本。 有什么想法吗? 最佳答案 这里有更简单的事情。 import javax.swin
我是一名优秀的程序员,十分优秀!