Java 本身就自带 JS 引擎,自从 Java 1.6 开始就支持了,愈来愈好。我对 js 比较熟悉,因此有个大胆的想法,为什么不用自带 js 引擎作 json 转换呢?这样我们可以不用引入其他第三方库。

背景知识:Java 6 提供对执行脚本语言的支持,这个支持来自于 JSR223 规范,对应的包是 javax.script。默认情况下,Java 6 只支持 JavaScript 脚本,它底层的实现是 Mozilla Rhino,它是个纯 Java 的 JavaScript 实现。
除了 OpenJDK 不自带 js 引擎外,Sun/Oracle 的都支持。所以完全可以这么来做。
我本人很早就这么做了。只是早期 1.6/1.7 的 Rhino 性能低下,但到了 1.8 性能已经不能同日而语了,——因为已经升级到 Nashorn 引擎了,一个非常快的 js 引擎实现。另外一点,之前写的代码十分累赘。尽管也重构了几次,但还是写不好。于是现欲改之,改成为一个稍“明快”的版本。请各位看官见下面代码,其作用就是将 JSON 字符串转换为 Java 的 Map 或者 List。
import java.util.List;
import java.util.Map;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
/**
* json 转为 java 对象的工具类
*
* @author frank
*
*/
public class JSON {
/**
* 创建 js 引擎工厂,支持 java 6/7 的 rhino 和 java 8 的 nashorn
*
* @return js 引擎
*/
public static ScriptEngine engineFatory() {
return new ScriptEngineManager()
.getEngineByName(System.getProperty("java.version").contains("1.8.") ? "nashorn" : "rhino");
}
/**
* JVM 自带的 JS 引擎
*/
private final static ScriptEngine engine = engineFatory();
/**
* 读取 json 里面的 map
*
* @param js
* JSON 字符串
* @param key
* JSON Path,可以带有 aa.bb.cc
* @return Map 对象
*/
@SuppressWarnings("unchecked")
public static Map<String, Object> getMap(String js, String key) {
return (Map<String, Object>) accessMember(js, key, Map.class);
}
/**
* 读取 json 里面的 map
*
* @param js
* JSON 字符串
* @return Map 对象
*/
public static Map<String, Object> getMap(String js) {
return getMap(js, null);
}
/**
* 转换为 map 或 list
*
* @param js
* JSON 字符串
* @param key
* JSON Path,可以带有 aa.bb.cc
* @param clazz
* 目标类型
* @return 目标对象
*/
@SuppressWarnings("unchecked")
public static <T> T accessMember(String js, String key, Class<T> clazz) {
T result = null;
try {
engine.eval("var obj = " + js);// rhino 不能直接返回 map,如 eval("{a:1}")
// -->null,必须加变量,例如 执行 var xx =
// {...};
Object obj;
if (key == null) {
obj = engine.eval("obj;");
} else {
if (key.contains(".")) {
obj = engine.eval("obj." + key + ";");
} else {
obj = engine.eval("obj['" + key + "'];");
}
}
result = (T) obj;
} catch (ScriptException e) {
System.err.println("脚本eval()运算发生异常!eval 代码:" + js);
e.printStackTrace();
}
return result;
}
/**
* 读取 json 里面的 list,list 里面每一个都是 map
*
* @param js
* JSON 字符串
* @param key
* JSON Path,可以带有 aa.bb.cc
* @return 包含 Map 的列表
*/
@SuppressWarnings("unchecked")
public static List<Map<String, Object>> getList(String js, String key) {
return (List<Map<String, Object>>) accessMember(js, key, List.class);
}
/**
* 读取 json 里面的 list,list 里面每一个都是 map
*
* @param js
* JSON 字符串
* @return 包含 Map 的列表
*/
public static List<Map<String, Object>> getList(String js) {
return getList(js, null);
}
/**
* 读取 json 里面的 list,list 里面每一个都是 String
*
* @param js
* JSON 字符串
* @param key
* JSON Path,可以带有 aa.bb.cc
* @return 包含 String 的列表
*/
@SuppressWarnings("unchecked")
public static List<String> getStringList(String js, String key) {
return (List<String>) accessMember(js, key, List.class);
}
/**
* 读取 json 里面的 list,list 里面每一个都是 String
*
* @param js
* JSON 字符串
* @return 包含 String 的列表
*/
public static List<String> getStringList(String js) {
return getStringList(js, null);
}
/**
* js number 为 double 类型,在 java 里面使用不方便,将其转换为 int
*
* @param d
* js number
* @return int 值
*/
public static int double2int(Double d) {
if (d > Integer.MAX_VALUE) {
System.out.println(d + "数值太大,不应用这个方法转换到 int");
return 0;
} else {
return d.intValue();
}
}
}
其实使用起来非常地方便!js 的对象本身是 map 结构,而 Rhino 原生对象 NativeObject 是 js 对象在 Java 语言里面的对应物,它已经实现了 Map 接口,所以完全可以把 NativeObject 当作 map 来使用!类型转换下即可!eval() 返回的是 object,如果可以判断 object 类型为 NativeObject,直接转化 (Map)object 就可以了——接着就是使用 get 等方法,甚至在 JSP 页面中也可以使用。
List 的也是同理。
下面是单测的代码。
import java.util.List;
import java.util.Map;
import org.junit.Test;
import com.ajaxjs.util.json.JSON;
import static org.junit.Assert.*;
public class TestJSON {
@Test
public void testGetMap() {
Map<String, Object> map;
map = JSON.getMap("{a:'hello', b: 'world!', c: { d: 'Nice!'}}");
System.out.println(map.get("a"));
assertNotNull(map);
map = JSON.getMap("{a:'hello', b: 'world!', c: { d: 'Nice!'}}", "c");
System.out.println(map.get("d"));
assertNotNull(map);
map = JSON.getMap("{a:'hello', b: 'world!', c: { d: 'Nice!', e: { f: 'fff'}}}", "c.e");
System.out.println(map.get("f"));
assertNotNull(map);
}
@Test
public void testGetListMap() {
List<Map<String, Object>> list;
list = JSON.getList("[{a:'hello'}, 123, true]");
System.out.println(list.get(0).get("a"));
assertTrue(list.size() > 0);
list = JSON.getList("[{a:'hello'}, {b: 'world!'}, {c: { d: 'Nice!'}}]");
System.out.println(list.get(0).get("a"));
assertTrue(list.size() > 0);
list = JSON.getList("{a:'hello', b: 'world!', c: [{ d: 'Nice!!!'}]}", "c");
System.out.println(list.get(0).get("d"));
}
@Test
public void testGetListString() {
List<String> list;
list = JSON.getStringList("['a', 'b', 'c']");
System.out.println(list.get(0));
assertTrue(list.size() > 0);
list = JSON.getStringList("[1, 'b', 'c']");
System.out.println(list.get(1));
assertTrue(list.size() > 0);
}
}
值得注意的是,虽然 JSEngine 提供了 Map 接口,但通常只能读的操作,如果对其执行 map.put(key, value) 的操作,是会引发 UnsupportOperation 的异常的。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
# rhino
# nashorn
# json
# Java
相关文章:
云南网站制作公司有哪些,云南最好的招聘网站是哪个?
如何选择香港主机高效搭建外贸独立站?
宝塔新建站点为何无法访问?如何排查?
太平洋网站制作公司,网络用语太平洋是什么意思?
行程制作网站有哪些,第三方机票电子行程单怎么开?
如何在自有机房高效搭建专业网站?
如何通过虚拟主机空间快速建站?
购物网站制作公司有哪些,哪个购物网站比较好?
宝塔新建站点报错如何解决?
广州商城建站系统开发成本与周期如何控制?
极客网站有哪些,DoNews、36氪、爱范儿、虎嗅、雷锋网、极客公园这些互联网媒体网站有什么差异?
linux top下的 minerd 木马清除方法
利用JavaScript实现拖拽改变元素大小
C#如何在一个XML文件中查找并替换文本内容
微课制作网站有哪些,微课网怎么进?
如何在万网开始建站?分步指南解析
网站好制作吗知乎,网站开发好学吗?有什么技巧?
网站图片在线制作软件,怎么在图片上做链接?
图片制作网站免费软件,有没有免费的网站或软件可以将图片批量转为A4大小的pdf?
香港服务器租用费用高吗?如何避免常见误区?
如何在腾讯云服务器快速搭建个人网站?
北京网页设计制作网站有哪些,继续教育自动播放怎么设置?
官网网站制作腾讯审核要多久,联想路由器newifi官网
图册素材网站设计制作软件,图册的导出方式有几种?
头像制作网站在线观看,除了站酷,还有哪些比较好的设计网站?
深圳防火门网站制作公司,深圳中天明防火门怎么编码?
详解免费开源的DotNet二维码操作组件ThoughtWorks.QRCode(.NET组件介绍之四)
北京的网站制作公司有哪些,哪个视频网站最好?
建站之星后台搭建步骤解析:模板选择与产品管理实操指南
高防服务器租用指南:配置选择与快速部署攻略
Android滚轮选择时间控件使用详解
,在苏州找工作,上哪个网站比较好?
自助网站制作软件,个人如何自助建网站?
如何实现建站之星域名转发设置?
建站之星如何实现PC+手机+微信网站五合一建站?
如何在宝塔面板中创建新站点?
网站制作公司排行榜,四大门户网站排名?
英语简历制作免费网站推荐,如何将简历翻译成英文?
电脑免费海报制作网站推荐,招聘海报哪个网站多?
Android自定义listview布局实现上拉加载下拉刷新功能
c++怎么实现高并发下的无锁队列_c++ std::atomic原子变量与CAS操作【详解】
已有域名能否直接搭建网站?
如何在Golang中处理模块冲突_解决依赖版本不兼容问题
宁波免费建站如何选择可靠模板与平台?
如何配置WinSCP新建站点的密钥验证步骤?
XML的“混合内容”是什么 怎么用DTD或XSD定义
如何用搬瓦工VPS快速搭建个人网站?
建站之星如何防范黑客攻击与数据泄露?
如何在橙子建站上传落地页?操作指南详解
网页设计网站制作软件,microsoft office哪个可以创建网页?
*请认真填写需求信息,我们会在24小时内与您取得联系。