├── .github └── workflows │ ├── nodejs.yml │ └── release.yml ├── .gitignore ├── .jshintignore ├── .jshintrc ├── CHANGELOG.md ├── LICENSE ├── README.md ├── index.js ├── lib ├── exception.js └── revert.js ├── package.json └── test ├── exception.test.js ├── index.test.js └── revert.test.js /.github/workflows/nodejs.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | 7 | pull_request: 8 | branches: [ master ] 9 | 10 | workflow_dispatch: {} 11 | 12 | jobs: 13 | Job: 14 | name: Node.js 15 | uses: node-modules/github-actions/.github/workflows/node-test.yml@master 16 | with: 17 | os: 'ubuntu-latest' 18 | version: '12, 14, 16, 18, 20' 19 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | 7 | jobs: 8 | release: 9 | name: Node.js 10 | uses: node-modules/github-actions/.github/workflows/node-release.yml@master 11 | secrets: 12 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 13 | GIT_TOKEN: ${{ secrets.GIT_TOKEN }} 14 | with: 15 | checkTest: false 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | coverage 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | 10 | pids 11 | logs 12 | results 13 | 14 | npm-debug.log 15 | node_modules 16 | .DS_Store 17 | .idea/ 18 | .nyc_output/ 19 | -------------------------------------------------------------------------------- /.jshintignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | coverage/ 3 | .tmp/ 4 | .git/ 5 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | // JSHint Default Configuration File (as on JSHint website) 3 | // See http://jshint.com/docs/ for more details 4 | 5 | "maxerr" : 50, // {int} Maximum error before stopping 6 | 7 | // Enforcing 8 | "bitwise" : true, // true: Prohibit bitwise operators (&, |, ^, etc.) 9 | "camelcase" : false, // true: Identifiers must be in camelCase 10 | "curly" : true, // true: Require {} for every new block or scope 11 | "eqeqeq" : true, // true: Require triple equals (===) for comparison 12 | "forin" : false, // true: Require filtering for..in loops with obj.hasOwnProperty() 13 | "immed" : false, // true: Require immediate invocations to be wrapped in parens e.g. `(function () { } ());` 14 | "indent" : false, // {int} Number of spaces to use for indentation 15 | "latedef" : false, // true: Require variables/functions to be defined before being used 16 | "newcap" : false, // true: Require capitalization of all constructor functions e.g. `new F()` 17 | "noarg" : true, // true: Prohibit use of `arguments.caller` and `arguments.callee` 18 | "noempty" : true, // true: Prohibit use of empty blocks 19 | "nonew" : false, // true: Prohibit use of constructors for side-effects (without assignment) 20 | "plusplus" : false, // true: Prohibit use of `++` & `--` 21 | "quotmark" : false, // Quotation mark consistency: 22 | // false : do nothing (default) 23 | // true : ensure whatever is used is consistent 24 | // "single" : require single quotes 25 | // "double" : require double quotes 26 | "undef" : true, // true: Require all non-global variables to be declared (prevents global leaks) 27 | "unused" : false, // true: Require all defined variables be used 28 | "strict" : true, // true: Requires all functions run in ES5 Strict Mode 29 | "trailing" : false, // true: Prohibit trailing whitespaces 30 | "maxparams" : false, // {int} Max number of formal params allowed per function 31 | "maxdepth" : false, // {int} Max depth of nested blocks (within functions) 32 | "maxstatements" : false, // {int} Max number statements per function 33 | "maxcomplexity" : false, // {int} Max cyclomatic complexity per function 34 | "maxlen" : false, // {int} Max number of characters per line 35 | 36 | // Relaxing 37 | "asi" : false, // true: Tolerate Automatic Semicolon Insertion (no semicolons) 38 | "boss" : true, // true: Tolerate assignments where comparisons would be expected 39 | "debug" : false, // true: Allow debugger statements e.g. browser breakpoints. 40 | "eqnull" : false, // true: Tolerate use of `== null` 41 | "es5" : false, // true: Allow ES5 syntax (ex: getters and setters) 42 | "esnext" : true, // true: Allow ES.next (ES6) syntax (ex: `const`) 43 | "moz" : false, // true: Allow Mozilla specific syntax (extends and overrides esnext features) 44 | // (ex: `for each`, multiple try/catch, function expression…) 45 | "evil" : false, // true: Tolerate use of `eval` and `new Function()` 46 | "expr" : true, // true: Tolerate `ExpressionStatement` as Programs 47 | "funcscope" : false, // true: Tolerate defining variables inside control statements" 48 | "globalstrict" : false, // true: Allow global "use strict" (also enables 'strict') 49 | "iterator" : false, // true: Tolerate using the `__iterator__` property 50 | "lastsemic" : false, // true: Tolerate omitting a semicolon for the last statement of a 1-line block 51 | "laxbreak" : true, // true: Tolerate possibly unsafe line breakings 52 | "laxcomma" : false, // true: Tolerate comma-first style coding 53 | "loopfunc" : false, // true: Tolerate functions being defined in loops 54 | "multistr" : true, // true: Tolerate multi-line strings 55 | "proto" : false, // true: Tolerate using the `__proto__` property 56 | "scripturl" : false, // true: Tolerate script-targeted URLs 57 | "smarttabs" : false, // true: Tolerate mixed tabs/spaces when used for alignment 58 | "shadow" : true, // true: Allows re-define variables later in code e.g. `var x=1; x=2;` 59 | "sub" : false, // true: Tolerate using `[]` notation when it can still be expressed in dot notation 60 | "supernew" : false, // true: Tolerate `new function () { ... };` and `new Object;` 61 | "validthis" : true, // true: Tolerate using this in a non-constructor function 62 | 63 | // Environments 64 | "browser" : true, // Web Browser (window, document, etc) 65 | "couch" : false, // CouchDB 66 | "devel" : true, // Development/debugging (alert, confirm, etc) 67 | "dojo" : false, // Dojo Toolkit 68 | "jquery" : false, // jQuery 69 | "mootools" : false, // MooTools 70 | "node" : true, // Node.js 71 | "nonstandard" : false, // Widely adopted globals (escape, unescape, etc) 72 | "prototypejs" : false, // Prototype and Scriptaculous 73 | "rhino" : false, // Rhino 74 | "worker" : false, // Web Workers 75 | "wsh" : false, // Windows Scripting Host 76 | "yui" : false, // Yahoo User Interface 77 | "noyield" : true, // allow generators without a yield 78 | 79 | // Legacy 80 | "nomen" : false, // true: Prohibit dangling `_` in variables 81 | "onevar" : false, // true: Allow only one `var` statement per function 82 | "passfail" : false, // true: Stop on first error 83 | "white" : false, // true: Check against strict whitespace and indentation rules 84 | 85 | // Custom Globals 86 | "globals" : { // additional predefined global variables 87 | // mocha 88 | "describe": true, 89 | "it": true, 90 | "before": true, 91 | "afterEach": true, 92 | "beforeEach": true, 93 | "after": true 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [2.8.0](https://github.com/node-modules/js-to-java/compare/v2.7.0...v2.8.0) (2023-07-11) 4 | 5 | 6 | ### Features 7 | 8 | * support revert array in vm ([#69](https://github.com/node-modules/js-to-java/issues/69)) ([dcb2384](https://github.com/node-modules/js-to-java/commit/dcb2384928c5eec1189d8f9fa3420079f42a11d2)) 9 | 10 | --- 11 | 12 | 13 | 2.7.0 / 2021-04-25 14 | ================== 15 | 16 | **fixes** 17 | * [[`19bb555`](http://github.com/node-modules/js-to-java/commit/19bb555118795b964374f10aa6bec9a0f65802fe)] - fix: add Enum for ts (#67) (赵磊鹏 <<872538464@qq.com>>) 18 | 19 | 2.6.1 / 2019-01-30 20 | ================== 21 | 22 | * fix: enum default use https://github.com/alipay/sofa-hessian-node/pull/14 (#63) 23 | 24 | 2.6.0 / 2018-06-01 25 | ================== 26 | 27 | **fixes** 28 | * [[`8a9a7da`](http://github.com/node-modules/js-to-java/commit/8a9a7da99e90a215c8073d2c2ea4675c99e30d5d)] - fix: add cause prop to exception (#60) (zōng yǔ <>) 29 | 30 | **others** 31 | * [[`8324a91`](http://github.com/node-modules/js-to-java/commit/8324a91eefb147280ee1eda47bf75445a61de124)] - chore: fix version (#58) (zōng yǔ <>) 32 | 33 | 2.5.0 / 2018-02-27 34 | ================== 35 | 36 | * feat: 增加 collection (#57) 37 | * chore(package): update should to version 10.0.0 38 | 39 | 2.4.0 / 2016-06-07 40 | ================== 41 | 42 | * feat: convert js error to java exception (#44) 43 | 44 | 2.3.5 / 2016-03-30 45 | ================== 46 | 47 | * fix: Boolean null 48 | * fix: Long == null should return null 49 | 50 | 2.3.4 / 2016-03-09 51 | ================== 52 | 53 | * fix: bigdecimal support {value} 54 | 55 | 2.3.3 / 2016-01-08 56 | ================== 57 | 58 | * chore: rm safeLong warn 59 | * chore(package): update should to version 8.0.2 60 | 61 | 2.3.1 / 2015-11-27 62 | ================== 63 | 64 | * chore: rm 0.10 test 65 | * fix: long prompt info 66 | 67 | 2.3.0 / 2015-11-09 68 | ================== 69 | 70 | * chore: jslint and ci 71 | * feat: add revert method as an implementation of java to js 72 | * chore(package): update dependencies 73 | 74 | 2.2.0 / 2015-10-21 75 | ================== 76 | 77 | * chore: add env check 78 | * feat: currency & safeLong 79 | * chore: use codecov.io 80 | 81 | 2.1.0 / 2015-09-07 82 | ================== 83 | 84 | * feat: support java.math.BigDecimal 85 | 86 | 2.0.7 / 2015-07-06 87 | ================== 88 | 89 | * fix: Class({name:}) 90 | 91 | 2.0.6 / 2015-04-02 92 | ================== 93 | 94 | * fix(class): array type 95 | 96 | 2.0.5 / 2015-03-13 97 | ================== 98 | 99 | * feat(combile): add check in combile 100 | 101 | 2.0.4 / 2015-03-09 102 | ================== 103 | 104 | * perf(enum): Improve the enumeration type conversion 105 | 106 | 2.0.3 / 2015-02-03 107 | ================== 108 | 109 | * feat(array): class enum locale 110 | 111 | 2.0.2 / 2015-01-28 112 | ================== 113 | 114 | * fix(valid): string & boolean; add null type test 115 | 116 | 2.0.1 / 2015-01-28 117 | ================== 118 | 119 | * fix(null): null should target type; modify int type valid 120 | 121 | 2.0.0 / 2015-01-22 122 | ================== 123 | 124 | * feat(valid): #5 support valid & Null valud 125 | 126 | 1.1.0 / 2014-11-05 127 | ================== 128 | 129 | * Merge pull request #3 from node-modules/more 130 | * feat(support): add java.lang.Class & java.util.Locale 131 | 132 | 1.0.0 / 2014-04-24 133 | ================== 134 | 135 | * Merge pull request #1 from node-modules/enum 136 | * fix github links 137 | * add enum() test cases 138 | * add enum() helper 139 | * add abstract in readme 140 | 141 | 0.0.3 / 2014-04-06 142 | ================== 143 | 144 | * add abstract 145 | * fix comment 146 | 147 | 0.0.2 / 2014-03-20 148 | ================== 149 | 150 | * add files in package 151 | * fix readme link 152 | * no need to use harmony istanbul 153 | 154 | 0.0.1 / 2014-03-20 155 | ================== 156 | 157 | * update readme 158 | * complete 159 | * Initial commit 160 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 - 2016 node-modules and other contributors 4 | Copyright (c) 2014 dead_horse 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # js-to-java 2 | 3 | [![NPM version][npm-image]][npm-url] 4 | [![CI](https://github.com/node-modules/js-to-java/actions/workflows/nodejs.yml/badge.svg)](https://github.com/node-modules/js-to-java/actions/workflows/nodejs.yml) 5 | [![Test coverage][cov-image]][cov-url] 6 | [![npm download][download-image]][download-url] 7 | 8 | [npm-image]: https://img.shields.io/npm/v/js-to-java.svg?style=flat-square 9 | [npm-url]: https://npmjs.org/package/js-to-java 10 | [cov-image]: http://codecov.io/github/node-modules/js-to-java/coverage.svg?branch=master 11 | [cov-url]: http://codecov.io/github/node-modules/js-to-java?branch=master 12 | [download-image]: https://img.shields.io/npm/dm/js-to-java.svg?style=flat-square 13 | [download-url]: https://npmjs.org/package/js-to-java 14 | 15 | Easy way to wrap js object to java object. 16 | 17 | In [hessian.js](https://github.com/node-modules/hessian.js), we need to write java classname with js object so make it encode as the write class. 18 | 19 | ## Install 20 | 21 | [![NPM](https://nodei.co/npm/js-to-java.png?downloads=true)](https://nodei.co/npm/js-to-java/) 22 | 23 | ```bash 24 | npm install js-to-java 25 | ``` 26 | 27 | ## Usage 28 | 29 | ### Example 30 | 31 | ```js 32 | var java = require('js-to-java'); 33 | 34 | // Java: com.java.Object o = new com.java.Object(); 35 | java('com.java.Object', { foo: 'bar' }); 36 | // => {$class: 'com.java.Object', $: { foo: 'bar' }} 37 | 38 | // Java: Boolean r; 39 | java.Boolean(true); 40 | // => {$class: 'java.lang.Boolean', $: true} 41 | 42 | // Java: short[] shorts = new short[] {1, 2, 3}; 43 | java.array('short', [1, 2, 3]); 44 | // => {$class: '[short', $: [1, 2, 3]} 45 | 46 | // Java: int[] ints = new int[] {1, 2, 3}; 47 | java.array('int', [1, 2, 3]); 48 | // same to the next example 49 | java.array.int([1, 2, 3]); 50 | // => {$class: '[int', $: [1, 2, 3]} 51 | ``` 52 | 53 | ## API 54 | 55 | ### Type Mapping 56 | 57 | ```js 58 | Boolean: 'java.lang.Boolean', 59 | boolean: 'boolean', 60 | Integer: 'java.lang.Integer', 61 | int: 'int', 62 | short: 'short', 63 | Short: 'java.lang.Short', 64 | byte: 'byte', 65 | Byte: 'java.lang.Byte', 66 | long: 'long', 67 | Long: 'java.lang.Long', 68 | double: 'double', 69 | Double: 'java.lang.Double', 70 | float: 'float', 71 | Float: 'java.lang.Float', 72 | String: 'java.lang.String', 73 | char: 'char', 74 | chars: 'char[]', 75 | Character: 'java.lang.Character', 76 | List: 'java.util.List', 77 | Set: 'java.util.Set', 78 | Collection: 'java.util.Collection', 79 | Iterator: 'java.util.Iterator', 80 | Enumeration: 'java.util.Enumeration', 81 | HashMap: 'java.util.HashMap', 82 | Map: 'java.util.Map', 83 | Dictionary: 'java.util.Dictionary' 84 | ``` 85 | 86 | ### java.abstract(abstractClassname, classname, value) 87 | 88 | abstract class 89 | 90 | ```js 91 | java.abstract('com.demo.Parent', 'com.demo.Child', { foo: 'bar' }); 92 | // => { $abstractClass: 'com.demo.Parent', $class: 'com.demo.Child', $: { foo: 'bar' } } 93 | ``` 94 | 95 | ### java[.combine](classname, value) 96 | 97 | Custom combineFunction: 98 | 99 | ```js 100 | java.combine('com.test.Object', { foo: 'bar' }); 101 | java('com.test.Object', { foo: 'bar' }); 102 | // => { $class: 'com.test.Object', $: { foo: 'bar' } } 103 | ``` 104 | 105 | ### java.Class(classname) 106 | 107 | ```js 108 | java.Class('java.lang.String'); 109 | // => { $class: 'java.lang.Class', $: { name: 'java.lang.String' } } 110 | ``` 111 | 112 | ### java.Locale(locale, handle) 113 | 114 | ```js 115 | java.Locale('zh_CN', ['com.caucho.hessian.io.LocaleHandle']); 116 | // => { $class: 'com.caucho.hessian.io.LocaleHandle', $: { value: 'zh_CN' } } 117 | ``` 118 | 119 | ### java.BigDecimal(decimal) 120 | 121 | ```js 122 | java.BigDecimal('100.06'); 123 | // Or java.BigDecimal({value: '100.06'}); 124 | // => { $class: 'java.math.BigDecimal', $: { value: '100.06' } } 125 | ``` 126 | 127 | ### java.enum(classname, value) 128 | 129 | ```js 130 | java.enum('hessian.demo.Color', 'RED'); 131 | or 132 | java.enum('hessian.demo.Color', {name: 'RED'}); 133 | // => { $class: 'hessian.demo.Color', $: { name: 'RED' } } 134 | ``` 135 | 136 | ### java.array(classname, values) 137 | 138 | ```js 139 | java.array('Boolean', [true, false]); 140 | // => { $class: '[java.lang.Boolean' $: [true, false] } 141 | ``` 142 | 143 | Available built-in classes shortcuts: 144 | 145 | - `java.array.Boolean(values)` 146 | - `java.array.boolean(values)` 147 | - `java.array.Integer(values)` 148 | - `java.array.int(values)` 149 | - `java.array.short(values)` 150 | - `java.array.Short(values)` 151 | - `java.array.byte(values)` 152 | - `java.array.Byte(values)` 153 | - `java.array.long(values)` 154 | - `java.array.Long(values)` 155 | - `java.array.double(values)` 156 | - `java.array.Double(values)` 157 | - `java.array.float(values)` 158 | - `java.array.Float(values)` 159 | - `java.array.String(values)` 160 | - `java.array.char(values)` 161 | - `java.array.chars(values)` 162 | - `java.array.Character(values)` 163 | - `java.array.List(values)` 164 | - `java.array.Set(values)` 165 | - `java.array.Iterator(values)` 166 | - `java.array.Enumeration(values)` 167 | - `java.array.HashMap(values)` 168 | - `java.array.Map(values)` 169 | - `java.array.Dictionary(values)` 170 | 171 | ### java.exception(err[, className]) 172 | 173 | default className is `java.lang.Exception`. 174 | 175 | ```js 176 | { 177 | '$class': `${className}`, 178 | '$': { 179 | detailMessage: { 180 | '$class': 'java.lang.String', 181 | '$': `${err.name}: ${err.message}`, 182 | }, 183 | stackTrace: { 184 | '$class': '[java.lang.StackTraceElement', 185 | '$': stackTraceElements, 186 | }, 187 | }, 188 | } 189 | ``` 190 | 191 | ### java.revert(obj) 192 | 193 | Wrap java object back to js object reversely. 194 | 195 | ```js 196 | var data = { 197 | $class: 'xxxx', 198 | $: { 199 | foo: 'bar', 200 | bar: { 201 | $class: 'int', 202 | $: 3, 203 | }, 204 | }, 205 | }; 206 | java.revert(data); 207 | // => {foo: 'bar', bar: 3} 208 | ``` 209 | 210 | ## License 211 | 212 | [MIT](LICENSE) 213 | 214 | 215 | 216 | ## Contributors 217 | 218 | |[
dead-horse](https://github.com/dead-horse)
|[
coolme200](https://github.com/coolme200)
|[
fengmk2](https://github.com/fengmk2)
|[
greenkeeperio-bot](https://github.com/greenkeeperio-bot)
|[
shaoshuai0102](https://github.com/shaoshuai0102)
|[
gxcsoccer](https://github.com/gxcsoccer)
| 219 | | :---: | :---: | :---: | :---: | :---: | :---: | 220 | [
mytEcust](https://github.com/mytEcust)
|[
semantic-release-bot](https://github.com/semantic-release-bot)
|[
zhaoleipeng](https://github.com/zhaoleipeng)
221 | 222 | This project follows the git-contributor [spec](https://github.com/xudafeng/git-contributor), auto updated at `Tue Jul 11 2023 11:39:26 GMT+0800`. 223 | 224 | 225 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var combine = function (type, value) { 4 | if (typeof type === 'string') { 5 | type = simpleTypeMap[type] || { 6 | name: type, 7 | valid: ignore 8 | }; 9 | } 10 | return { 11 | $class: type.name, 12 | $: type.valid(value) 13 | }; 14 | }; 15 | 16 | var combineArray = function (type, value) { 17 | var values = null; 18 | if (value) { 19 | values = []; 20 | for (var i = 0, len = value.length; i < len; i++) { 21 | values.push(combine(type, value[i])); 22 | } 23 | } 24 | return { 25 | $class: '[' + (type.name || type), 26 | $: values 27 | }; 28 | }; 29 | 30 | /** 31 | * java('com.java.Object', {}) 32 | * => 33 | * { 34 | * $class: 'com.java.Object', 35 | * $: {} 36 | * } 37 | * @param {String} className 38 | * @param {Mixed} value 39 | */ 40 | exports = module.exports = function (className, value) { 41 | return combine(className, value); 42 | }; 43 | 44 | exports.__defineSetter__('combine', function (fn) { 45 | combine = fn; 46 | }); 47 | 48 | exports.__defineGetter__('combine', function () { 49 | return combine; 50 | }); 51 | 52 | // valid list 53 | function ignore(val) {return val;} 54 | 55 | function baseBool(val) {return !!val;} 56 | 57 | function bool(val) { 58 | /* jshint eqnull: true */ 59 | if (val == null) { 60 | return null; 61 | } 62 | return !!val; 63 | } 64 | 65 | function baseInt(val) { 66 | /* jshint eqnull: true */ 67 | return val == null ? 0 : integer(val); 68 | } 69 | 70 | function baseFloat(val) { 71 | /* jshint eqnull: true */ 72 | return val == null ? 0 : float(val); 73 | } 74 | 75 | function float(val) { 76 | /* jshint eqnull: true */ 77 | if (val == null) { 78 | return null; 79 | } 80 | var r = parseFloat(val); 81 | return isNaN(r) ? val : r; 82 | } 83 | 84 | function integer(val) { 85 | /* jshint eqnull: true */ 86 | if (val == null) { 87 | return null; 88 | } 89 | var r = parseInt(val, 10); 90 | return isNaN(r) ? val : r; 91 | } 92 | 93 | function string(val) { 94 | /* jshint eqnull: true */ 95 | if (val == null) { 96 | return null; 97 | } 98 | return String(val); 99 | } 100 | 101 | function baseLong(val) { 102 | /* jshint eqnull: true */ 103 | if (val == null) { 104 | return 0; 105 | } 106 | return val; 107 | } 108 | 109 | function long(val) { 110 | /* jshint eqnull: true */ 111 | if (val == null) { 112 | return null; 113 | } 114 | return val; 115 | } 116 | 117 | var simpleTypeMap = exports.simpleTypeMap = { 118 | Boolean: {name: 'java.lang.Boolean', valid: bool}, 119 | boolean: {name: 'boolean', valid: baseBool}, 120 | Integer: {name: 'java.lang.Integer', valid: integer}, 121 | int: {name: 'int', valid: baseInt}, 122 | short: {name: 'short', valid: baseInt}, 123 | Short: {name: 'java.lang.Short', valid: integer}, 124 | byte: {name: 'byte', valid: baseInt}, 125 | Byte: {name: 'java.lang.Byte', valid: integer}, 126 | // long support both string and number 127 | long: {name: 'long', valid: baseLong}, 128 | Long: {name: 'java.lang.Long', valid: long}, 129 | double: {name: 'double', valid: baseFloat}, 130 | Double: {name: 'java.lang.Double', valid: float}, 131 | float: {name: 'float', valid: baseFloat}, 132 | Float: {name: 'java.lang.Float', valid: float}, 133 | String: {name: 'java.lang.String', valid: string}, 134 | char: {name: 'char', valid: string}, 135 | chars: {name: 'char[]', valid: string}, 136 | Character: {name: 'java.lang.Character', valid: string}, 137 | List: {name: 'java.util.List', valid: ignore}, 138 | Set: {name: 'java.util.Set', valid: ignore}, 139 | Collection: {name: 'java.util.Collection', valid: ignore}, 140 | Iterator: {name: 'java.util.Iterator', valid: ignore}, 141 | Enumeration: {name: 'java.util.Enumeration', valid: ignore}, 142 | HashMap: {name: 'java.util.HashMap', valid: ignore}, 143 | Map: {name: 'java.util.Map', valid: ignore}, 144 | Dictionary: {name: 'java.util.Dictionary', valid: ignore}, 145 | }; 146 | 147 | for (var key in simpleTypeMap) { 148 | var type = simpleTypeMap[key]; 149 | simpleTypeMap[type.name] = type; 150 | } 151 | 152 | /** 153 | * java.Boolean(true); 154 | * => 155 | * { 156 | * $class: 'java.lang.Boolean', 157 | * $: true 158 | * } 159 | */ 160 | 161 | Object.keys(simpleTypeMap).forEach(function (key) { 162 | exports[key] = function (val) { 163 | return combine(simpleTypeMap[key], val); 164 | }; 165 | }); 166 | 167 | /** 168 | * java.array('Boolean', [true, false]); 169 | * => 170 | * { 171 | * $class: '[java.lang.Boolean', 172 | * $: [true, false] 173 | * } 174 | * 175 | * @param {String} className class name in array 176 | * @param {Array} val 177 | */ 178 | 179 | exports.array = function (className, val) { 180 | className = simpleTypeMap[className] || className; 181 | return combineArray(className, val); 182 | }; 183 | 184 | /** 185 | * java.array.Boolean([true, false]); 186 | * => 187 | * { 188 | * $class: '[java.lang.Boolean', 189 | * $: [true, false] 190 | * } 191 | */ 192 | 193 | Object.keys(simpleTypeMap).forEach(function (key) { 194 | exports.array[key] = function (val) { 195 | return combineArray(simpleTypeMap[key], val); 196 | }; 197 | }); 198 | 199 | /** 200 | * java abstract class 201 | * 202 | * @param {String} abstractClassName 203 | * @param {String} className 204 | * @param {Object} val 205 | * @return {Object} 206 | */ 207 | 208 | exports.abstract = function (abstractClassName, className, val) { 209 | var res = combine(className, val); 210 | res.$abstractClass = abstractClassName; 211 | return res; 212 | }; 213 | 214 | /** 215 | * java.enum("hessian.demo.Color", "RED"); 216 | * => 217 | * { 218 | * $class: 'hessian.demo.Color', 219 | * $: { name: 'RED' } 220 | * } 221 | */ 222 | function Enum (className, name) { 223 | var value; 224 | if (!name) { 225 | value = null; 226 | } else if (typeof name === 'string') { 227 | value = {name: name}; 228 | } else if (typeof name === 'object' && (name.$name || name.name)) { 229 | // java enum class has name() and getName(), user can override property name 230 | // -> $name => name() 231 | // -> name => getName() 232 | // Usually two values are equal 233 | value = {name: name.$name || name.name}; 234 | } else { 235 | // Still to return the wrong value, when the error is convenient to find the reasons. 236 | value = name; 237 | } 238 | return combine(className, value); 239 | } 240 | 241 | // backward compatible 242 | exports.enum = Enum; 243 | 244 | // enum is key word, this is for TS 245 | exports.Enum = Enum; 246 | 247 | function ArrayEnum (className, names) { 248 | var values = null; 249 | if (names) { 250 | values = []; 251 | for (var i = 0, len = names.length; i < len; i++) { 252 | values.push(exports.enum(className, names[i])); 253 | } 254 | } 255 | return { 256 | $class: '[' + className, 257 | $: values 258 | }; 259 | } 260 | 261 | // backward compatible 262 | exports.array.enum = ArrayEnum; 263 | 264 | // enum is key word, this is for TS 265 | exports.array.Enum = ArrayEnum; 266 | 267 | /** 268 | * java.Class("java.lang.String"); 269 | * => 270 | * { 271 | * $class: 'java.lang.Class', 272 | * $: { name: 'java.lang.String' } 273 | * } 274 | */ 275 | exports.Class = function (name) { 276 | var value; 277 | if (!name) { 278 | value = null; 279 | } else if (typeof name === 'string') { 280 | value = { 281 | name: name.indexOf('[') !== -1 ? ('[L' + name.replace(/(\[L)|(\[)|;/g, '') + ';') : name 282 | }; 283 | } else if (typeof name === 'object' && name.name) { 284 | value = { 285 | name: name.name 286 | }; 287 | } else { 288 | // Still to return the wrong value, when the error is convenient to find the reasons. 289 | value = name; 290 | } 291 | return combine('java.lang.Class', value); 292 | }; 293 | 294 | exports.array.Class = function (names) { 295 | var values = null; 296 | if (names) { 297 | values = []; 298 | for (var i = 0, len = names.length; i < len; i++) { 299 | values.push(exports.Class(names[i])); 300 | } 301 | } 302 | return { 303 | $class: '[java.lang.Class', 304 | $: values 305 | }; 306 | }; 307 | 308 | /** 309 | * // for java.util.Locale 310 | * java.Locale("zh_CN"); 311 | * => 312 | * { 313 | * $class: 'com.caucho.hessian.io.LocaleHandle', 314 | * $: { value: 'zh_CN' } 315 | * } 316 | */ 317 | exports.Locale = function (locale, handle) { 318 | var value = locale ? { 319 | value: locale 320 | } : null; 321 | return combine(handle || 'com.caucho.hessian.io.LocaleHandle', value); 322 | }; 323 | 324 | exports.array.Locale = function (locales, handle) { 325 | var values = null; 326 | if (locales) { 327 | values = []; 328 | for (var i = 0, len = locales.length; i < len; i++) { 329 | values.push(exports.Locale(locales[i], handle)); 330 | } 331 | } 332 | return { 333 | $class: '[' + (handle || 'com.caucho.hessian.io.LocaleHandle'), 334 | $: values 335 | }; 336 | }; 337 | 338 | /** 339 | * // for java.math.BigDecimal 340 | * java.BigDecimal("100.06"); 341 | * => 342 | * { 343 | * $class: 'java.math.BigDecimal', 344 | * $: { value: '100.06' } 345 | * } 346 | */ 347 | exports.BigDecimal = function (val) { 348 | if (val === null || val === undefined) { 349 | val = 0; 350 | } 351 | if (typeof val === 'object') { 352 | val = val.value || 0; 353 | } 354 | return combine('java.math.BigDecimal', { value: String(val) }); 355 | }; 356 | 357 | exports.array.BigDecimal = function (vals) { 358 | var values = null; 359 | if (vals) { 360 | values = []; 361 | for (var i = 0, len = vals.length; i < len; i++) { 362 | values.push(exports.BigDecimal(vals[i])); 363 | } 364 | } 365 | return { 366 | $class: '[java.math.BigDecimal', 367 | $: values 368 | }; 369 | }; 370 | 371 | exports.Currency = function (value) { 372 | if (typeof value === 'string') { 373 | value = { 374 | currencyCode: value, 375 | }; 376 | } else if (typeof value === 'object' && value.currencyCode) { 377 | value = { 378 | currencyCode: value.currencyCode, 379 | }; 380 | } else if (!value || !value.currencyCode) { 381 | value = null; 382 | } 383 | return combine('java.util.Currency', value); 384 | }; 385 | 386 | exports.array.Currency = function (vals) { 387 | var values = null; 388 | if (Array.isArray(vals)) { 389 | values = []; 390 | for (var i = 0, len = vals.length; i < len; i++) { 391 | values.push(exports.Currency(vals[i])); 392 | } 393 | } 394 | return { 395 | $class: '[java.util.Currency', 396 | $: values, 397 | }; 398 | }; 399 | 400 | exports.revert = require('./lib/revert'); 401 | exports.exception = require('./lib/exception'); 402 | -------------------------------------------------------------------------------- /lib/exception.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function toException(err, className) { 4 | className = className || 'java.lang.Exception'; 5 | var stackTraceElements = []; 6 | var lines = err.stack.match(/ at .+$/gm); 7 | if (lines) { 8 | // Error: foo 9 | // at repl:1:11 10 | // at REPLServer.defaultEval (repl.js:262:27) 11 | // at bound (domain.js:287:14) 12 | // at REPLServer.runBound [as eval] (domain.js:300:12) 13 | // at REPLServer. (repl.js:431:12) 14 | // at emitOne (events.js:82:20) 15 | // at REPLServer.emit (events.js:169:7) 16 | // at REPLServer.Interface._onLine (readline.js:211:10) 17 | // at REPLServer.Interface._line (readline.js:550:8) 18 | // at REPLServer.Interface._ttyWrite (readline.js:827:14) 19 | for (var line of lines) { 20 | var splits = line.replace(' at ', '').split('('); 21 | if (splits.length < 2) { 22 | splits.push(splits[0]); 23 | splits[0] = '.'; 24 | } 25 | var declaring = splits[0]; 26 | var lastIndexDot = declaring.lastIndexOf('.'); 27 | var declaringClass = declaring.substring(0, lastIndexDot) || ''; 28 | var methodName = declaring.substring(lastIndexDot + 1).trim(); 29 | 30 | var fileSplits = splits[1].split(':'); 31 | var fileName = fileSplits[0].replace(')', ''); 32 | var lineNumber = parseInt(fileSplits[1]) || 0; 33 | // if (isNaN(lineNumber)) { 34 | // // ignore invaild format 35 | // // e.g.: `at next (native)` 36 | // continue; 37 | // } 38 | stackTraceElements.push({ 39 | '$class': 'java.lang.StackTraceElement', 40 | '$': { 41 | declaringClass: { '$class': 'java.lang.String', '$': declaringClass }, 42 | methodName: { '$class': 'java.lang.String', '$': methodName }, 43 | fileName: { '$class': 'java.lang.String', '$': fileName }, 44 | lineNumber: { '$class': 'int', '$': lineNumber }, 45 | }, 46 | }); 47 | } 48 | } 49 | return { 50 | '$class': className, 51 | '$': { 52 | detailMessage: { 53 | '$class': 'java.lang.String', 54 | '$': err.name + ': ' + err.message, 55 | }, 56 | stackTrace: { 57 | '$class': '[java.lang.StackTraceElement', 58 | '$': stackTraceElements, 59 | }, 60 | cause: { 61 | '$class': 'java.lang.Throwable', 62 | '$': null, 63 | }, 64 | }, 65 | }; 66 | }; 67 | -------------------------------------------------------------------------------- /lib/revert.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var DELIMITER = '_$$$_'; 4 | 5 | // {$class: 'xx', $: {foo: 'bar'}} => {foo: 'bar'} 6 | function derecycle(java, refs, path) { 7 | refs = refs || []; 8 | path = path || ''; 9 | 10 | // simple type, null, undefined 11 | if (typeof java !== 'object' || 12 | java === null || 13 | //java === undefined || 14 | java instanceof Boolean || 15 | java instanceof Date || 16 | java instanceof Number || 17 | java instanceof RegExp || 18 | java instanceof String || 19 | Object.prototype.toString.call(java) === '[object Boolean]'|| 20 | Object.prototype.toString.call(java) === '[object Date]' || 21 | Object.prototype.toString.call(java) === '[object Number]' || 22 | Object.prototype.toString.call(java) === '[object RegExp]' || 23 | Object.prototype.toString.call(java) === '[object String]') { 24 | return java; 25 | } 26 | 27 | // plain object, array 28 | 29 | // cycular reference detection 30 | var cache; 31 | for (var i = 0, l = refs.length; i < l; i++) { 32 | cache = refs[i]; 33 | if (cache.key === java) { 34 | return { 35 | $ref: cache.path, // path to root, ig. 'path_$$$_to_$$$_root' 36 | }; 37 | } 38 | } 39 | 40 | refs.push({ 41 | key: java, 42 | path: path, 43 | }); 44 | 45 | var result; 46 | if (java.$class) { 47 | result = derecycle(java.$, refs, path); 48 | /* 49 | } else if (java instanceof Map) { 50 | result = {}; 51 | java.forEach(function(v, k) { 52 | k = derecycle(k, refs); 53 | result[k] = derecycle(v, refs, path ? path + DELIMITER + k : k); 54 | }); 55 | */ 56 | } else if (java instanceof Array || Array.isArray(java)) { 57 | result = []; 58 | java.forEach(function(v, i) { 59 | result[i] = derecycle(v, refs, path ? path + DELIMITER + i : i + ''); 60 | }); 61 | } else if (java instanceof Error || Object.prototype.toString.call(java) === "[object Error]") { 62 | result = java; 63 | } else { 64 | // plain object 65 | result = {}; 66 | for (var i in java) { 67 | result[i] = derecycle(java[i], refs, path ? path + DELIMITER + i : i); 68 | } 69 | } 70 | 71 | return result; 72 | } 73 | 74 | // obj = { 75 | // a: { 76 | // b: 1 77 | // } 78 | // } 79 | // retrieve(obj, 'a_$$$_b') => 1 80 | function retrieve(obj, path) { 81 | if (!path) { 82 | return obj; 83 | } 84 | 85 | var arr = path.split(DELIMITER); 86 | var result = obj; 87 | for (var i = 0, l = arr.length; i < l; i++) { 88 | result = result[arr[i]]; 89 | } 90 | return result; 91 | } 92 | 93 | function retrocycle(js, root) { 94 | if (!root) { 95 | root = js; 96 | } 97 | 98 | var i, l, item, path; 99 | 100 | if (js && typeof js === 'object') { 101 | if (js instanceof Array || Array.isArray(js)) { 102 | for (i = 0, l = js.length; i < l; i++) { 103 | item = js[i]; 104 | if (item && typeof item === 'object') { 105 | path = item.$ref; 106 | if (typeof path === 'string') { 107 | js[i] = retrieve(root, path); 108 | } else { 109 | retrocycle(item, root); 110 | } 111 | } 112 | } 113 | } else if (js instanceof Error || Object.prototype.toString.call(js) === "[object Error]") { 114 | return js; 115 | } else { 116 | for (i in js) { 117 | item = js[i]; 118 | if (item && typeof item === 'object') { 119 | path = item.$ref; 120 | if (typeof path === 'string') { 121 | js[i] = retrieve(root, path); 122 | } else { 123 | retrocycle(item, root); 124 | } 125 | } 126 | } 127 | } 128 | } 129 | return js; 130 | } 131 | 132 | function java2js(java) { 133 | return retrocycle(derecycle(java)); 134 | } 135 | 136 | module.exports = java2js; 137 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-to-java", 3 | "version": "2.8.0", 4 | "description": "easy way to wrap js object to java object", 5 | "main": "index.js", 6 | "files": [ 7 | "index.js", 8 | "lib" 9 | ], 10 | "scripts": { 11 | "test": "mocha -R spec -t 3000 -r should test/*.test.js", 12 | "test-cov": "nyc mocha -- -t 3000 -r should test/*.test.js", 13 | "ci": "npm run jshint && npm run test-cov", 14 | "jshint": "jshint lib index.js", 15 | "contributor": "git-contributor" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "git://github.com/node-modules/js-to-java.git" 20 | }, 21 | "keywords": [ 22 | "js", 23 | "java", 24 | "object", 25 | "class" 26 | ], 27 | "author": "dead_horse ", 28 | "license": "MIT", 29 | "bugs": { 30 | "url": "https://github.com/node-modules/js-to-java/issues" 31 | }, 32 | "homepage": "https://github.com/node-modules/js-to-java", 33 | "dependencies": {}, 34 | "devDependencies": { 35 | "cov": "*", 36 | "git-contributor": "^2.1.5", 37 | "jshint": "2", 38 | "mocha": "*", 39 | "nyc": "^15.1.0", 40 | "should": "10.0.0" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /test/exception.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | 7 | var assert = require('assert'); 8 | var java = require('../'); 9 | 10 | describe('js error to java exception', function() { 11 | it('should work with TypeError', function() { 12 | var err = new TypeError('mock js type error throw'); 13 | var exception = java.exception(err, 'com.nodejs.eggdemo.FooException'); 14 | assert.equal(exception.$class, 'com.nodejs.eggdemo.FooException'); 15 | assert.equal(exception.$.detailMessage.$, 'TypeError: mock js type error throw'); 16 | assert.equal(exception.$.stackTrace.$class, '[java.lang.StackTraceElement'); 17 | exception.$.stackTrace.$.forEach(function(ele) { 18 | assert.equal(ele.$class, 'java.lang.StackTraceElement'); 19 | }); 20 | assert.equal(exception.$.cause.$class, 'java.lang.Throwable'); 21 | assert(exception.$.cause.$ === null); 22 | // console.log(JSON.stringify(exception, null, 2)); 23 | }); 24 | 25 | it('should work with Error and default className', function() { 26 | var err = new Error('mock js error throw'); 27 | var exception = java.exception(err); 28 | assert.equal(exception.$class, 'java.lang.Exception'); 29 | assert.equal(exception.$.detailMessage.$, 'Error: mock js error throw'); 30 | assert.equal(exception.$.stackTrace.$class, '[java.lang.StackTraceElement'); 31 | exception.$.stackTrace.$.forEach(function(ele) { 32 | assert.equal(ele.$class, 'java.lang.StackTraceElement'); 33 | }); 34 | assert.equal(exception.$.cause.$class, 'java.lang.Throwable'); 35 | assert(exception.$.cause.$ === null); 36 | // console.log(JSON.stringify(exception, null, 2)); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /test/index.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | 7 | var should = require('should'); 8 | var java = require('../'); 9 | 10 | describe('js to java', function () { 11 | it('should java wrap work fine', function () { 12 | java('com.test.Object', {}).should.eql({$class: 'com.test.Object', $: {}}); 13 | java.revert({$class: 'com.test.Object', $: {}}).should.eql({}); 14 | }); 15 | 16 | it('should simple type map work fine', function () { 17 | var val = 1; 18 | java.boolean(val).should.eql({$class: 'boolean', $: true}); 19 | java.revert({$class: 'boolean', $: true}).should.equal(true); 20 | java.Boolean(val).should.eql({$class: 'java.lang.Boolean', $: true}); 21 | java.revert({$class: 'java.lang.Boolean', $: true}).should.equal(true); 22 | java.Boolean().should.eql({$class: 'java.lang.Boolean', $: null}); 23 | java.revert({$class: 'java.lang.Boolean', $: false}).should.equal(false); 24 | 25 | java.Integer('1').should.eql({$class: 'java.lang.Integer', $: 1}); 26 | java.revert({$class: 'java.lang.Integer', $: 1}).should.equal(1); 27 | java.int('1').should.eql({$class: 'int', $: 1}); 28 | java.revert({$class: 'int', $: 1}).should.equal(1); 29 | java.int().should.eql({$class: 'int', $: 0}); 30 | java.revert({$class: 'int', $: 0}).should.equal(0); 31 | 32 | java.Short('101').should.eql({$class: 'java.lang.Short', $: 101}); 33 | java.revert({$class: 'java.lang.Short', $: 101}).should.equal(101); 34 | java.short('101').should.eql({$class: 'short', $: 101}); 35 | java.revert({$class: 'short', $: 101}).should.equal(101); 36 | java.short('str').should.eql({$class: 'short', $: 'str'}); 37 | java.revert({$class: 'short', $: 'str'}).should.equal('str'); 38 | java.short().should.eql({$class: 'short', $: 0}); 39 | java.revert({$class: 'short', $: 0}).should.equal(0); 40 | 41 | java.byte('1').should.eql({$class: 'byte', $: 1}); 42 | java.revert({$class: 'byte', $: 1}).should.equal(1); 43 | java.Byte('1').should.eql({$class: 'java.lang.Byte', $: 1}); 44 | java.revert({$class: 'java.lang.Byte', $: 1}).should.equal(1); 45 | java.Byte().should.eql({$class: 'java.lang.Byte', $: null}); 46 | should(java.revert({$class: 'java.lang.Byte', $: null})).equal(null); 47 | 48 | java.long('1').should.eql({$class: 'long', $: '1'}); 49 | java.revert({$class: 'long', $: '1'}).should.equal('1'); 50 | java.Long(1).should.eql({$class: 'java.lang.Long', $: 1}); 51 | java.revert({$class: 'java.lang.Long', $: 1}).should.equal(1); 52 | java.long().should.eql({$class: 'long', $: 0}); 53 | java.Long().should.eql({$class: 'java.lang.Long', $: null}); 54 | 55 | java.double('1.02').should.eql({$class: 'double', $: 1.02}); 56 | java.revert({$class: 'double', $: 1.02}).should.equal(1.02); 57 | java.double().should.eql({$class: 'double', $: 0}); 58 | java.revert({$class: 'double', $: 0}).should.equal(0); 59 | java.Double('1').should.eql({$class: 'java.lang.Double', $: 1}); 60 | java.revert({$class: 'java.lang.Double', $: 1}).should.equal(1); 61 | java.Double().should.eql({$class: 'java.lang.Double', $: null}); 62 | should(java.revert({$class: 'java.lang.Double', $: null})).equal(null); 63 | 64 | java.float('1').should.eql({$class: 'float', $: 1}); 65 | java.revert({$class: 'float', $: 1}).should.equal(1); 66 | java.float().should.eql({$class: 'float', $: 0}); 67 | java.revert({$class: 'float', $: 0}).should.equal(0); 68 | java.float('str').should.eql({$class: 'float', $: 'str'}); 69 | java.revert({$class: 'float', $: 'str'}).should.equal('str'); 70 | java.Float('1.03').should.eql({$class: 'java.lang.Float', $: 1.03}); 71 | java.revert({$class: 'java.lang.Float', $: 1.03}).should.equal(1.03); 72 | java.Float().should.eql({$class: 'java.lang.Float', $: null}); 73 | should(java.revert({$class: 'java.lang.Float', $: null})).equal(null); 74 | 75 | java.String(123).should.eql({$class: 'java.lang.String', $: '123'}); 76 | java.revert({$class: 'java.lang.String', $: '123'}).should.equal('123'); 77 | java.String().should.eql({$class: 'java.lang.String', $: null}); 78 | should(java.revert({$class: 'java.lang.String', $: null})).equal(null); 79 | 80 | java.char('2').should.eql({$class: 'char', $: '2'}); 81 | java.revert({$class: 'char', $: '2'}).should.equal('2'); 82 | java.chars('3').should.eql({$class: 'char[]', $: '3'}); 83 | java.revert({$class: 'char[]', $: '3'}).should.equal('3'); 84 | java.char().should.eql({$class: 'char', $: null}); 85 | should(java.revert({$class: 'char', $: null})).equal(null); 86 | 87 | java.Character(1).should.eql({$class: 'java.lang.Character', $: '1'}); 88 | java.revert({$class: 'java.lang.Character', $: '1'}).should.equal('1'); 89 | java.List([]).should.eql({$class: 'java.util.List', $: []}); 90 | java.revert({$class: 'java.util.List', $: []}).should.eql([]); 91 | java.Integer().should.eql({$class: 'java.lang.Integer', $: null}); 92 | should(java.revert({$class: 'java.lang.Integer', $: null})).equal(null); 93 | java.Integer('a').should.eql({$class: 'java.lang.Integer', $: 'a'}); 94 | java.revert({$class: 'java.lang.Integer', $: 'a'}).should.equal('a'); 95 | 96 | java.Collection([]).should.eql({$class: 'java.util.Collection', $: []}); 97 | java.revert({$class: 'java.util.Collection', $: []}).should.eql([]); 98 | 99 | }); 100 | 101 | it('should array work fine', function () { 102 | var result = {$class: '[java.lang.Short', $: [ 103 | { 104 | $class: 'java.lang.Short', 105 | $: 1 106 | } 107 | ]}; 108 | java.array('Short', [1]).should.eql(result); 109 | java.revert(result).should.eql([1]); 110 | 111 | result = {$class: '[com.java.Object', $: [{ 112 | $class: 'com.java.Object', 113 | $: {} 114 | }]}; 115 | java.array('com.java.Object', [{}]).should.eql(result); 116 | java.revert(result).should.eql([{}]); 117 | }); 118 | 119 | it('should array.type work fine', function () { 120 | var result = {$class: '[java.lang.Integer', $: [ 121 | { $: 1, $class: 'java.lang.Integer' }, 122 | { $: 2, $class: 'java.lang.Integer' }, 123 | { $: 3, $class: 'java.lang.Integer' } 124 | ]}; 125 | java.array.Integer(['1', '2', 3]).should.eql(result); 126 | java.revert(result).should.eql([1, 2, 3]); 127 | }); 128 | 129 | it('should abstractClass work ok', function () { 130 | var result = { 131 | $class: 'com.java.Object', 132 | $abstractClass: 'java.lang.Object', 133 | $: {} 134 | }; 135 | java.abstract('java.lang.Object', 'com.java.Object', {}).should.eql(result); 136 | java.revert(result).should.eql({}); 137 | }); 138 | 139 | it('should combine work fine', function () { 140 | function combine(className, value) { 141 | return { 142 | className: className, 143 | value: value 144 | }; 145 | } 146 | var _old = java.combine; 147 | java.combine = combine; 148 | java.combine.should.equal(combine); 149 | java('com.test.Object', {}).should.eql({className: 'com.test.Object', value: {}}); 150 | java.combine = _old; 151 | }); 152 | 153 | it('should create enum', function () { 154 | var result = { 155 | $class: 'hessian.demo.Color', 156 | $: {name: 'RED'} 157 | }; 158 | java.enum('hessian.demo.Color', 'RED').should.eql(result); 159 | java.Enum('hessian.demo.Color', 'RED').should.eql(result); 160 | java.enum('hessian.demo.Color', {name: 'RED'}).should.eql(result); 161 | java.Enum('hessian.demo.Color', {name: 'RED'}).should.eql(result); 162 | java.enum('hessian.demo.Color', {$name: 'RED'}).should.eql(result); 163 | java.Enum('hessian.demo.Color', {$name: 'RED'}).should.eql(result); 164 | java.revert(result).should.eql({name: 'RED'}); 165 | 166 | result = { 167 | $class: 'xxx', 168 | $: null 169 | }; 170 | java.enum('xxx').should.eql(result); 171 | java.Enum('xxx').should.eql(result); 172 | should(java.revert(result)).equal(null); 173 | 174 | result = { 175 | $class: '[com.xxx', 176 | $: null 177 | }; 178 | java.array.enum('com.xxx').should.eql(result); 179 | java.array.Enum('com.xxx').should.eql(result); 180 | should(java.revert(result)).equal(null); 181 | 182 | result = { 183 | $class: '[com.xxx', 184 | $: [ 185 | { 186 | $class: 'com.xxx', 187 | $: { 188 | name: 'aaa' 189 | } 190 | } 191 | ] 192 | }; 193 | java.array.enum('com.xxx', ['aaa']).should.eql(result); 194 | java.array.Enum('com.xxx', ['aaa']).should.eql(result); 195 | java.array.enum('com.xxx', [{name: 'aaa'}]).should.eql(result); 196 | java.array.Enum('com.xxx', [{name: 'aaa'}]).should.eql(result); 197 | java.revert(result).should.eql([{name: 'aaa'}]); 198 | }); 199 | 200 | it('should create Class', function () { 201 | var result = { 202 | $class: 'java.lang.Class', 203 | $: {name: 'java.lang.String'} 204 | }; 205 | java.Class({name: 'java.lang.String'}).should.eql(result); 206 | java.Class('java.lang.String').should.eql(result); 207 | java.revert(result).should.eql({name: 'java.lang.String'}); 208 | 209 | result = { 210 | $class: 'java.lang.Class', 211 | $: null 212 | }; 213 | java.Class().should.eql(result); 214 | should(java.revert(result)).equal(null); 215 | 216 | result = { 217 | $class: 'java.lang.Class', 218 | $: { 219 | name: '[Ljava.lang.String;' 220 | } 221 | }; 222 | java.Class('[java.lang.String').should.eql(result); 223 | java.Class('[Ljava.lang.String;').should.eql(result); 224 | java.Class('[Ljava.lang.String').should.eql(result); 225 | java.revert(result).should.eql({name: '[Ljava.lang.String;'}); 226 | 227 | result = { 228 | $class: 'java.lang.Class', 229 | $: { 230 | name: '[Ljava.Lang.String;' 231 | } 232 | }; 233 | java.Class('[Ljava.Lang.String').should.eql(result); 234 | java.revert(result).should.eql({name: '[Ljava.Lang.String;'}); 235 | 236 | result = { 237 | $class: '[java.lang.Class', 238 | $: null 239 | }; 240 | java.array.Class().should.eql(result); 241 | should(java.revert(result)).equal(null); 242 | 243 | result = { 244 | $class: '[java.lang.Class', 245 | $: [ 246 | { 247 | $class: 'java.lang.Class', 248 | $: { 249 | name: 'aaa' 250 | } 251 | } 252 | ] 253 | }; 254 | java.array.Class(['aaa']).should.eql(result); 255 | java.revert(result).should.eql([{name: 'aaa'}]); 256 | }); 257 | 258 | it('should create Locale with out input `handle`', function () { 259 | var result = { 260 | $class: 'com.caucho.hessian.io.LocaleHandle', 261 | $: {value: 'zh_CN'} 262 | }; 263 | java.Locale('zh_CN').should.eql(result); 264 | java.revert(result).should.eql({value: 'zh_CN'}); 265 | 266 | result = { 267 | $class: '[com.caucho.hessian.io.LocaleHandle', 268 | $: null 269 | }; 270 | java.array.Locale().should.eql(result); 271 | should(java.revert(result)).equal(null); 272 | 273 | result = { 274 | $class: '[com.caucho.hessian.io.LocaleHandle', 275 | $: [ 276 | { 277 | $class: 'com.caucho.hessian.io.LocaleHandle', 278 | $: { 279 | value: 'zh_CN' 280 | } 281 | } 282 | ] 283 | }; 284 | java.array.Locale(['zh_CN']).should.eql(result); 285 | java.revert(result).should.eql([{value: 'zh_CN'}]); 286 | }); 287 | 288 | it('should create Locale with input `handle`', function () { 289 | var result = { 290 | $class: 'test.com.caucho.hessian.io.LocaleHandle', 291 | $: {value: 'zh_CN'} 292 | }; 293 | java.Locale('zh_CN', 'test.com.caucho.hessian.io.LocaleHandle').should.eql(result); 294 | java.revert(result).should.eql({value: 'zh_CN'}); 295 | 296 | result = { 297 | $class: 'com.caucho.hessian.io.LocaleHandle', 298 | $: null 299 | }; 300 | java.Locale().should.eql(result); 301 | should(java.revert(result)).equal(null); 302 | }); 303 | 304 | it('should create BigDecimal', function () { 305 | var result = { 306 | $class: 'java.math.BigDecimal', 307 | $: {value: '100.06'} 308 | }; 309 | java.BigDecimal('100.06').should.eql(result); 310 | java.revert(result).should.eql({value: '100.06'}); 311 | java.BigDecimal({value: '100.06'}).should.eql(result); 312 | java.BigDecimal({value: 100.06}).should.eql(result); 313 | java.BigDecimal({val: '100.06'}).should.eql({ 314 | $class: 'java.math.BigDecimal', 315 | $: {value: '0'} 316 | }); 317 | result = { 318 | $class: '[java.math.BigDecimal', 319 | $: [ 320 | { 321 | $class: 'java.math.BigDecimal', 322 | $: {value: '100.06'} 323 | }, 324 | { 325 | $class: 'java.math.BigDecimal', 326 | $: {value: '200.07'} 327 | } 328 | ] 329 | }; 330 | java.array.BigDecimal(['100.06', '200.07']).should.eql(result); 331 | java.revert(result).should.eql([{value: '100.06'}, {value: '200.07'}]); 332 | 333 | result = { 334 | $class: '[java.math.BigDecimal', 335 | $: null 336 | }; 337 | java.array.BigDecimal(null).should.eql(result); 338 | should(java.revert(result)).equal(null); 339 | }); 340 | 341 | it('should check type with combile', function () { 342 | java('java.lang.Integer', '123').should.eql({$class: 'java.lang.Integer', $: 123}); 343 | java.revert({$class: 'java.lang.Integer', $: 123}).should.equal(123); 344 | java('int', '123').should.eql({$class: 'int', $: 123}); 345 | java.revert({$class: 'int', $: 123}).should.equal(123); 346 | java('java.lang.String', 123).should.eql({$class: 'java.lang.String', $: '123'}); 347 | java.revert({$class: 'java.lang.String', $: '123'}).should.equal('123'); 348 | }); 349 | 350 | it('should create Currency', function () { 351 | java.Currency('CNY').should.eql({$class: 'java.util.Currency', $: {currencyCode: 'CNY'}}); 352 | java.revert({$class: 'java.util.Currency', $: {currencyCode: 'CNY'}}).should.eql({currencyCode: 'CNY'}); 353 | java.Currency({currencyCode: undefined}).should.eql({$class: 'java.util.Currency', $: null}); 354 | java.Currency(undefined).should.eql({$class: 'java.util.Currency', $: null}); 355 | should(java.revert({$class: 'java.util.Currency', $: null})).equal(null); 356 | java.Currency({currencyCode: 'CNY'}).should.eql({$class: 'java.util.Currency', $: {currencyCode: 'CNY'}}); 357 | java.revert({$class: 'java.util.Currency', $: {currencyCode: 'CNY'}}).should.eql({currencyCode: 'CNY'}); 358 | 359 | java.array.Currency([]).should.eql({$class: '[java.util.Currency', $: []}); 360 | java.revert({$class: '[java.util.Currency', $: []}).should.eql([]); 361 | java.array.Currency().should.eql({$class: '[java.util.Currency', $: null}); 362 | should(java.revert({$class: '[java.util.Currency', $: null})).equal(null); 363 | java.array.Currency(['CNY']).should.eql({$class: '[java.util.Currency', $: [{$class: 'java.util.Currency', $: {currencyCode: 'CNY'}}]}); 364 | java.revert({$class: '[java.util.Currency', $: [{$class: 'java.util.Currency', $: {currencyCode: 'CNY'}}]}).should.eql([{currencyCode: 'CNY'}]); 365 | }); 366 | 367 | }); 368 | -------------------------------------------------------------------------------- /test/revert.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var assert = require('assert'); 4 | var vm = require('vm'); 5 | require('should'); 6 | var revert = require('../index').revert; 7 | 8 | describe('revert: java to js', function() { 9 | it('should work with simple value', function() { 10 | var java = { 11 | $class: 'string', 12 | $: 'foo', 13 | }; 14 | revert(java).should.equal('foo'); 15 | 16 | java = { 17 | $class: 'int', 18 | $: 33, 19 | }; 20 | revert(java).should.equal(33); 21 | 22 | java = { 23 | $class: 'long', 24 | $: 44, 25 | }; 26 | revert(java).should.equal(44); 27 | 28 | java = { 29 | $class: 'boolean', 30 | $: true, 31 | }; 32 | revert(java).should.equal(true); 33 | 34 | revert(33).should.equal(33); 35 | revert('foo').should.equal('foo'); 36 | revert(true).should.equal(true); 37 | }); 38 | 39 | it('should work with error', function() { 40 | var error = new Error(); 41 | error.message = 'this is a java IOException instance'; 42 | error.name = 'java.io.IOException'; 43 | error.cause = error; 44 | var java = { 45 | $class: 'java.io.IOException', 46 | $: error, 47 | }; 48 | revert(java).should.equal(error); 49 | }); 50 | 51 | it('should work with nested object', function() { 52 | var java = { 53 | $class: 'xxxx', 54 | $: { 55 | $class: 'gggg', 56 | $: { 57 | $class: 'xxxxag', 58 | $: 'bar', 59 | }, 60 | }, 61 | }; 62 | 63 | revert(java).should.equal('bar'); 64 | 65 | java = { 66 | $class: 'xxxx', 67 | $: { 68 | foo: 'bar', 69 | bar: { 70 | $class: 'int', 71 | $: 3, 72 | }, 73 | }, 74 | }; 75 | revert(java).should.eql({foo: 'bar', bar: 3}); 76 | }); 77 | 78 | it('should work with list', function() { 79 | var java = [2, 3, 5]; 80 | revert(java).should.eql(java); 81 | 82 | java = [ 83 | {$class: 'string', $: 'foo'}, 84 | {$class: 'string', $: 'bar'}, 85 | {$class: 'string', $: 'zoo'}, 86 | ]; 87 | revert(java).should.eql(['foo', 'bar', 'zoo']); 88 | }); 89 | 90 | it('should work when used with cycular reference', function() { 91 | var java, result; 92 | 93 | java = { 94 | $class: 'xxxxx', 95 | $: { 96 | foo: 'bar', 97 | }, 98 | }; 99 | java.$.parent_node = java; 100 | 101 | result = {foo: 'bar'}; 102 | result.parent_node = result; 103 | revert(java).should.eql(result); 104 | 105 | java = { 106 | $class: 'xxxxx', 107 | $: { 108 | foo: { 109 | $class: 'yyyyy', 110 | $: { 111 | a: 'barz', 112 | b: { 113 | $class: 'zzzzz', 114 | $: { 115 | c: 'barzz' 116 | } 117 | } 118 | }, 119 | }, 120 | }, 121 | }; 122 | java.$.parent_node = java; 123 | java.$.foo.$.parent_node = java.$.foo; 124 | java.$.foo.$.parent_node2 = java.$.foo.$; 125 | java.$.foo.$.ancestor_node = java; 126 | java.$.foo.$.ancestor_node2 = java.$; 127 | java.$.foo.$.b.$.parent_node = java.$.foo.$.b.$; 128 | result = {foo: {a: 'barz', b: {c: 'barzz'}}}; 129 | result.parent_node = result; 130 | result.foo.parent_node = result.foo; 131 | result.foo.parent_node2 = result.foo; 132 | result.foo.ancestor_node = result; 133 | result.foo.ancestor_node2 = result; 134 | result.foo.b.parent_node = result.foo.b; 135 | revert(java).should.eql(result); 136 | 137 | java = { 138 | $class: 'xxList', 139 | $: [ 140 | { 141 | $class: 'java.lang.object', 142 | $: { 143 | foo: 'bar', 144 | }, 145 | }, 146 | { 147 | $class: 'java.lang.object', 148 | $: { 149 | bar: { 150 | $class: 'java.lang.object', 151 | $: { 152 | foo: 'bar', 153 | }, 154 | }, 155 | } 156 | }, 157 | ], 158 | }; 159 | java.$[1].$.brother = java.$[0]; 160 | java.$[1].$.brother2 = java.$[0].$; 161 | java.$[1].$.bar.$.parent_node = java.$[1].$.bar; 162 | java.$[1].$.bar.$.parent_node2 = java.$[1].$.bar.$; 163 | result = [{foo: 'bar'}, {bar: {foo: 'bar'}}]; 164 | result[1].brother = result[0]; 165 | result[1].brother2 = result[0]; 166 | result[1].bar.parent_node = result[1].bar; 167 | result[1].bar.parent_node2 = result[1].bar; 168 | revert(java).should.eql(result); 169 | 170 | java = { 171 | $class: 'xxList', 172 | $: [ 173 | { 174 | $class: 'java.lang.Object', 175 | $: { 176 | foo: 'bar', 177 | }, 178 | }, 179 | ], 180 | }; 181 | java.$[1] = java.$[0]; 182 | result = [{foo: 'bar'}]; 183 | result[1] = result[0]; 184 | revert(java).should.eql(result); 185 | }); 186 | 187 | it('should work in vm', function() { 188 | revert(new vm.Script(`33`).runInNewContext({})).should.equal(33); 189 | revert(new vm.Script(`'foo'`).runInNewContext({})).should.equal('foo'); 190 | revert(new vm.Script(`true`).runInNewContext({})).should.equal(true); 191 | 192 | assert.deepEqual(revert(new vm.Script(`new Boolean(true)`).runInNewContext({})), new Boolean(true)); 193 | assert.deepEqual(revert(new vm.Script(`new Date('2023-01-01')`).runInNewContext({})), new Date('2023-01-01')); 194 | assert.deepEqual(revert(new vm.Script(`new Number(1)`).runInNewContext({})), new Number(1)); 195 | assert.deepEqual(revert(new vm.Script(`new RegExp(/[12]/)`).runInNewContext({})), new RegExp(/[12]/)); 196 | assert.deepEqual(revert(new vm.Script(`new String('foo')`).runInNewContext({})), new String('foo')); 197 | 198 | var java = new vm.Script(`[ 199 | {$class: 'string', $: 'foo'}, 200 | {$class: 'string', $: 'bar'}, 201 | {$class: 'string', $: 'zoo'}, 202 | ]`).runInNewContext({}); 203 | revert(java).should.eql(['foo', 'bar', 'zoo']); 204 | 205 | var error = new Error(); 206 | error.message = 'this is a java IOException instance'; 207 | error.name = 'java.io.IOException'; 208 | error.cause = error; 209 | assert.deepEqual(revert(new vm.Script(`var error = new Error(); 210 | error.message = 'this is a java IOException instance'; 211 | error.name = 'java.io.IOException'; 212 | error.cause = error; 213 | var java = { 214 | $class: 'java.io.IOException', 215 | $: error, 216 | };`).runInNewContext({})), error); 217 | 218 | class javaError extends Error { 219 | constructor(message) { 220 | super(message); 221 | this.name = 'java.io.IOException'; 222 | this.cause = this; 223 | } 224 | } 225 | var error2 = new javaError('this is a java IOException instance'); 226 | 227 | assert.deepEqual(revert(new vm.Script(`class javaError extends Error { 228 | constructor(message) { 229 | super(message); 230 | this.name = 'java.io.IOException'; 231 | this.cause = this; 232 | } 233 | } 234 | var error2 = new javaError('this is a java IOException instance'); 235 | var java = { 236 | $class: 'java.io.IOException', 237 | $: error2, 238 | }; 239 | java`).runInNewContext({})), error2); 240 | }); 241 | }); 242 | --------------------------------------------------------------------------------