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。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
|
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 的也是同理。
下面是單測的代碼。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
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 的異常的。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:http://blog.csdn.net/zhangxin09/article/details/51810804