Skip to content

Commit

Permalink
Add support for instantiating classes that do not have a constructor
Browse files Browse the repository at this point in the history
  • Loading branch information
AeonLucid committed Apr 3, 2024
1 parent 1e23abb commit e84a11d
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 16 deletions.
48 changes: 32 additions & 16 deletions lib/class-factory.js
Original file line number Diff line number Diff line change
Expand Up @@ -1318,37 +1318,53 @@ function makeSuperHandleGetter (classWrapper) {
function makeConstructor (classHandle, classWrapper, env) {
const { $n: className, $f: factory } = classWrapper;
const methodName = basename(className);
const Class = env.javaLangClass();
const Constructor = env.javaLangReflectConstructor();
const invokeObjectMethodNoArgs = env.vaMethod('pointer', []);
const invokeUInt8MethodNoArgs = env.vaMethod('uint8', []);

const jsCtorMethods = [];
const jsInitMethods = [];
const jsRetType = factory._getType(className, false);
const jsVoidType = factory._getType('void', false);

const constructors = invokeObjectMethodNoArgs(env.handle, classHandle, env.javaLangClass().getDeclaredConstructors);
const constructors = invokeObjectMethodNoArgs(env.handle, classHandle, Class.getDeclaredConstructors);
try {
const n = env.getArrayLength(constructors);

for (let i = 0; i !== n; i++) {
let methodId, types;
const constructor = env.getObjectArrayElement(constructors, i);
try {
methodId = env.fromReflectedMethod(constructor);
types = invokeObjectMethodNoArgs(env.handle, constructor, Constructor.getGenericParameterTypes);
} finally {
env.deleteLocalRef(constructor);
if (n > 0) {
for (let i = 0; i !== n; i++) {
let methodId, types;
const constructor = env.getObjectArrayElement(constructors, i);
try {
methodId = env.fromReflectedMethod(constructor);
types = invokeObjectMethodNoArgs(env.handle, constructor, Constructor.getGenericParameterTypes);
} finally {
env.deleteLocalRef(constructor);
}

Check failure on line 1345 in lib/class-factory.js

View workflow job for this annotation

GitHub Actions / eslint

Trailing spaces not allowed
let jsArgTypes;
try {
jsArgTypes = readTypeNames(env, types).map(name => factory._getType(name));
} finally {
env.deleteLocalRef(types);
}

Check failure on line 1352 in lib/class-factory.js

View workflow job for this annotation

GitHub Actions / eslint

Trailing spaces not allowed
jsCtorMethods.push(makeMethod(methodName, classWrapper, CONSTRUCTOR_METHOD, methodId, jsRetType, jsArgTypes, env));
jsInitMethods.push(makeMethod(methodName, classWrapper, INSTANCE_METHOD, methodId, jsVoidType, jsArgTypes, env));
}
} else {
const isInterface = invokeUInt8MethodNoArgs(env.handle, classHandle, Class.isInterface);

let jsArgTypes;
try {
jsArgTypes = readTypeNames(env, types).map(name => factory._getType(name));
} finally {
env.deleteLocalRef(types);
if (isInterface) {
throw new Error('Can not instantiate an interface');
}

jsCtorMethods.push(makeMethod(methodName, classWrapper, CONSTRUCTOR_METHOD, methodId, jsRetType, jsArgTypes, env));
jsInitMethods.push(makeMethod(methodName, classWrapper, INSTANCE_METHOD, methodId, jsVoidType, jsArgTypes, env));
const defaultClass = env.javaLangObject();
const defaultConstructor = env.getMethodId(defaultClass, '<init>', '()V');

jsCtorMethods.push(makeMethod(methodName, classWrapper, CONSTRUCTOR_METHOD, defaultConstructor, jsRetType, [], env));
jsInitMethods.push(makeMethod(methodName, classWrapper, INSTANCE_METHOD, defaultConstructor, jsVoidType, [], env));
}
} finally {
env.deleteLocalRef(constructors);
Expand Down
2 changes: 2 additions & 0 deletions lib/env.js
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,7 @@ Env.prototype.javaLangClass = function () {
getDeclaredFields: get('getDeclaredFields', '()[Ljava/lang/reflect/Field;'),
isArray: get('isArray', '()Z'),
isPrimitive: get('isPrimitive', '()Z'),
isInterface: get('isInterface', '()Z'),
getComponentType: get('getComponentType', '()Ljava/lang/Class;')
};
} finally {
Expand All @@ -683,6 +684,7 @@ Env.prototype.javaLangObject = function () {
try {
const get = this.getMethodId.bind(this, handle);
javaLangObject = {
handle: register(this.newGlobalRef(handle)),
toString: get('toString', '()Ljava/lang/String;'),
getClass: get('getClass', '()Ljava/lang/Class;')
};
Expand Down

0 comments on commit e84a11d

Please sign in to comment.