Skip to content

Instantly share code, notes, and snippets.

@IvanaGyro
Created February 12, 2020 03:19
Show Gist options
  • Save IvanaGyro/92d31f3e5c05e38ac2be8036a228ffaa to your computer and use it in GitHub Desktop.
Save IvanaGyro/92d31f3e5c05e38ac2be8036a228ffaa to your computer and use it in GitHub Desktop.
Wrap java objects to get the properties with the dot operator.
const java = require('java');
const path = require('path');
const JAVA_DIR = path.resolve(__dirname, '../libs/java/');
java.options = [ '-Xms3072m' , '-Xmx3072m', '-Xmn1152m' ];
java.asyncOptions = {
asyncSuffix: 'Async',
syncSuffix: '', // For readability, remove the convetional suffix of sync
// functions.
ifReadOnlySuffix: '_alt',
};
java.classpath.push(path.resolve(JAVA_DIR, 'hanlp/hanlp-1.7.3.jar'));
java.classpath.push(path.resolve(JAVA_DIR, 'gson/gson-2.8.5.jar'));
const gson = java.newInstanceSync('com.google.gson.Gson');
/**
* I do not know where is the current working directory of JMV, so set the
* properties path of HanLP mannually.
*/
const Predefine = java.import('com.hankcs.hanlp.utility.Predefine');
Predefine.HANLP_PROPERTIES_PATH =
path.resolve(__dirname, '../libs/java/hanlp/hanlp.properties');
/**
* Cache the classes object imported from Java.
*/
var classes = {};
var newClassTarget = function (javaClass, className) {
// To enable handling construct operattor, `new`, the target must have a
// `[[Construct]]` internal method (i.e. `new target` must be valid).
// Please refer to:
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler/construct
var r = function () {};
r.javaClass = javaClass;
r.className = className;
return r;
};
var ImporterTarget = function (prefix) {
this.prefix = prefix;
};
var instanceHandler = {
get: function (target, name) {
var r = target[name];
if (r === undefined) return undefined;
if (r.constructor === Function) {
return (...args) => {
// `r(...args)` will crash the java bridge, I don't know why
// var res = r(...args);
var res = java.callMethodSync(target, name, ...args);
return JSON.parse(gson.toJson(res));
}
} else if (r.constructor.name.startsWith('nodeJava')) { // is a Java object
return new Proxy(r, instanceHandler);
} else {
return r;
}
},
};
var classHandler = {
get: function (target, name) {
var r = target.javaClass[name];
if (r === undefined) return r;
if (r.constructor === Function) {
if (Object.keys(r).length != 0) {
// If `r` has keys, it may be a subclass.
let subClassName = target.className + '$' + name;
let klass = hasClass(subClassName);
if (klass) return klass;
}
return (...args) => {
// `apply` is not work because accessing the function `r` by `apply` may
// skip the proxy set by the module, `java`.
// var res = r.apply(null, arguments);
var res = r(...args);
return gson.toJson(res);
}
} else if (r.constructor.name == 'nodeJava_java_lang_Class') {
// The first argument of `java.import()` must be an object, so comparing
// the name of constructor is more general.
return new Proxy(
newClassTarget(r, target.name + '.' + name),
classHandler);
} else if (r.constructor.name.startsWith('nodeJava')) { // is a Java object
return new Proxy(r, instanceHandler);
} else {
return r;
}
},
set: function (target, name, value) {
target.javaClass[name] = value;
},
construct: function (target, args) {
var instance = java.newInstanceSync(target.className, ...args);
return new Proxy(instance, instanceHandler);
}
};
var hasClass = function (fullClassName) {
if (fullClassName in classes) return classes[fullClassName];
try {
let javaClass = java.import(fullClassName);
classes[fullClassName] =
new Proxy(
newClassTarget(javaClass, fullClassName),
classHandler);
return classes[fullClassName];
} catch (err) {
if (err.cause &&
java.instanceOf(err.cause, 'java.lang.NoClassDefFoundError')) {
// not found
return false;
} else {
// unknown error
throw err;
}
}
};
var importerHandler = {
get: function(target, name) {
var fullClassName = 'com.hankcs.hanlp' + target.prefix + '.' + name;
var klass = hasClass(fullClassName);
if (klass) return klass;
return new Proxy(
new ImporterTarget(target.prefix + '.' + name),
importerHandler,
);
}
};
var HanLP = new Proxy(new ImporterTarget(''), importerHandler);
module.exports = HanLP;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment