如何在Nashorn中为Java对象实现猴子补丁?
解决Nashorn中Java POJO的猴子补丁问题
嘿,这个场景我太熟悉了!Nashorn对Java对象的代理机制确实会让你没法直接给POJO实例动态添加属性——因为它只是把Java对象映射成了一个代理对象,而非真正的原生JavaScript对象,所以你直接赋值pojo.bar = 'baz'其实根本没生效,自然输出undefined。
下面给你两种不同场景下的解决方案:
方案1:不修改Java类,在JS中包装成原生对象
如果你没法改动现有的Pojo类,最简单的办法就是把Java对象的属性拷贝到一个原生JS对象里,之后就可以自由添加动态属性了:
// 把Java POJO的属性拷贝到原生JS对象 const jsPojo = Object.assign({}, pojo); // 现在可以自由添加动态属性 jsPojo.bar = 'baz'; print(jsPojo.bar); // 输出: baz // 原POJO的属性也能访问 print(jsPojo.foo); // 输出: foo
如果需要和原POJO的属性保持同步,可以用getter/setter来做绑定:
const jsPojo = { get foo() { return pojo.foo; }, set foo(value) { pojo.foo = value; } }; jsPojo.bar = 'baz'; print(jsPojo.bar); // 输出: baz // 修改JS对象的foo会同步到原POJO jsPojo.foo = 'updated foo'; print(pojo.foo); // 输出: updated foo
方案2:修改Java类,支持动态属性
如果你有权限修改Pojo类,可以让它实现Nashorn提供的jdk.nashorn.api.scripting.JSObject接口,这样就能让Java对象直接支持JS风格的动态属性操作。
修改后的Java类示例:
import jdk.nashorn.api.scripting.JSObject; import java.util.HashMap; import java.util.Map; public class Pojo implements JSObject { public String foo = "foo"; // 用来存储动态添加的属性 private final Map<String, Object> dynamicProperties = new HashMap<>(); @Override public Object getMember(String name) { // 优先返回Java类本身的属性 if ("foo".equals(name)) { return foo; } // 否则返回动态属性 return dynamicProperties.get(name); } @Override public void setMember(String name, Object value) { if ("foo".equals(name)) { foo = (String) value; } else { dynamicProperties.put(name, value); } } @Override public boolean hasMember(String name) { return "foo".equals(name) || dynamicProperties.containsKey(name); } // 实现JSObject接口的其他方法,默认返回空或false即可 @Override public Object getSlot(int index) { return null; } @Override public void setSlot(int index, Object value) {} @Override public boolean hasSlot(int slot) { return false; } @Override public void removeMember(String name) { dynamicProperties.remove(name); } @Override public Object call(Object thiz, Object... args) { return null; } @Override public Object newObject(Object... args) { return null; } }
现在再运行你的原代码:
pojo.bar = 'baz'; print(pojo.bar); // 输出: baz
就可以正常工作了!
内容的提问来源于stack exchange,提问作者geca
相关产品推荐
相关产品推荐

