java json第三方库比较好_Java用 Rhino/Nashorn 代替第三方 JSON 转换库

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 getMap(String js, String key) {

return (Map) accessMember(js, key, Map.class);

}

/**

* 读取 json 里面的 map

*

* @param js

* JSON 字符串

* @return Map 对象

*/

public static Map 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 accessMember(String js, String key, Class 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> getList(String js, String key) {

return (List>) accessMember(js, key, List.class);

}

/**

* 读取 json 里面的 list,list 里面每一个都是 map

*

* @param js

* JSON 字符串

* @return 包含 Map 的列表

*/

public static List> 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 getStringList(String js, String key) {

return (List) accessMember(js, key, List.class);

}

/**

* 读取 json 里面的 list,list 里面每一个都是 String

*

* @param js

* JSON 字符串

* @return 包含 String 的列表

*/

public static List 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 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> 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 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 的异常的。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持聚米学院。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值