如何在Java中序列化包含JavaScript函数的JavaScript对象?
在Java中序列化包含JavaScript函数的JS对象字面量
首先要明确:你要生成的是JavaScript对象字面量,而非严格符合JSON规范的内容——因为标准JSON并不支持函数类型。org.json库是严格遵循JSON规范的,所以默认无法直接输出函数,需要通过自定义逻辑来实现。
以下是几种可行的解决方案:
方案1:自定义函数封装类 + 字符串替换(轻量快速)
先定义一个封装JS函数的类,重写其toString方法输出函数的原生代码:
public class JsFunction { private final String args; private final String body; public JsFunction(String args, String body) { this.args = args; this.body = body; } @Override public String toString() { return String.format("function (%s) {\n %s\n}", args, body); } }
之后使用org.json生成初始JSON字符串,再替换掉函数内容的包裹引号:
import org.json.JSONObject; public class Main { public static void main(String[] args) { JSONObject obj = new JSONObject(); obj.put("foo", "bar"); obj.put("baz", new JsFunction("x, y", "return x+y;")); // 生成带引号包裹函数的JSON字符串 String rawJson = obj.toString(2); // 替换引号,得到原生JS对象字面量 String jsObject = rawJson.replace("\"function (", "function (") .replace("}\"", "}"); System.out.println(jsObject); } }
输出结果就是你期望的格式:
{ "foo": "bar", "baz": function (x, y) { return x+y; } }
方案2:扩展org.json的JSONWriter(更优雅的定制)
org.json的序列化依赖JSONWriter,可以自定义Writer来识别JsFunction类型并直接输出原生代码:
import org.json.JSONWriter; import java.io.IOException; import java.io.StringWriter; public class JsObjectWriter extends JSONWriter { public JsObjectWriter(StringWriter writer) { super(writer); } @Override public JSONWriter value(Object value) throws IOException { if (value instanceof JsFunction) { // 直接写入函数内容,不添加JSON字符串的引号包裹 this.writer.write(value.toString()); return this; } return super.value(value); } }
使用自定义Writer生成内容:
import java.io.StringWriter; public class Main { public static void main(String[] args) throws IOException { StringWriter sw = new StringWriter(); JsObjectWriter writer = new JsObjectWriter(sw); writer.object(); writer.key("foo").value("bar"); writer.key("baz").value(new JsFunction("x, y", "return x+y;")); writer.endObject(); String jsObject = sw.toString(); System.out.println(jsObject); } }
这个方案无需后续字符串替换,直接生成目标内容,适合需要频繁生成这类对象的场景。
方案3:切换到支持原生JS输出的库(健壮性更高)
如果你的项目可以引入其他库,Jackson是更好的选择——它支持自定义序列化器输出原生JS代码:
首先定义JsFunction类和对应的序列化器:
import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.ser.std.StdSerializer; import java.io.IOException; public class JsFunction { private final String args; private final String body; public JsFunction(String args, String body) { this.args = args; this.body = body; } public String getArgs() { return args; } public String getBody() { return body; } } class JsFunctionSerializer extends StdSerializer<JsFunction> { public JsFunctionSerializer() { super(JsFunction.class); } @Override public void serialize(JsFunction value, JsonGenerator gen, SerializerProvider provider) throws IOException { // 使用writeRawValue输出原生JS代码,不转义 String funcStr = String.format("function (%s) {\n %s\n}", value.getArgs(), value.getBody()); gen.writeRawValue(funcStr); } }
然后配置Jackson并生成内容:
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; import java.util.HashMap; import java.util.Map; public class Main { public static void main(String[] args) throws IOException { ObjectMapper mapper = new ObjectMapper(); // 注册自定义序列化器 SimpleModule module = new SimpleModule(); module.addSerializer(new JsFunctionSerializer()); mapper.registerModule(module); Map<String, Object> jsObj = new HashMap<>(); jsObj.put("foo", "bar"); jsObj.put("baz", new JsFunction("x, y", "return x+y;")); // 生成格式化后的JS对象字面量 String jsObject = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsObj); System.out.println(jsObject); } }
注意事项
- 生成的内容不是标准JSON,无法被JSON解析器正确解析,仅适用于JavaScript环境。
- 如果函数体包含特殊字符(如换行、引号),需要自行处理转义,避免破坏JS语法。
内容的提问来源于stack exchange,提问作者Chris Farmer
相关产品推荐
相关产品推荐

