Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ public static Constructor<?> resolveConstructor(Class<?> cls, Class<?>[] argType
if (!constructor.isVarArgs()) {
continue;
}
if (argTypes.length < constructor.getParameterTypes().length - 1) {
continue;
}
varArgsCandidates.add(adapt2VarArgTypes(constructor.getParameterTypes(), argTypes.length));
varArgsConstructorI.add(i);
}
Expand Down Expand Up @@ -156,6 +159,9 @@ public static IMethod resolveMethod(List<? extends IMethod> methods, Class<?>[]
if (!declaredMethod.isVarArgs()) {
continue;
}
if (argTypes.length < declaredMethod.getParameterTypes().length - 1) {
continue;
}
varArgsCandidates.add(adapt2VarArgTypes(declaredMethod.getParameterTypes(), argTypes.length));
varArgsMethodI.add(i);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ public QResult execute(QContext qContext, QLOptions qlOptions) {

private Object newInstance(QContext qContext) {
Constructor<?> constructor = qContext.getReflectLoader().loadConstructor(newCls, new Class[0]);
if (constructor == null) {
throw errorReporter.reportFormat(QLErrorCodes.NO_SUITABLE_CONSTRUCTOR.name(),
QLErrorCodes.NO_SUITABLE_CONSTRUCTOR.getErrorMsg(),
"[]");
}
try {
return constructor.newInstance();
}
Expand All @@ -69,7 +74,7 @@ private Object newInstance(QContext qContext) {
QLErrorCodes.INVOKE_CONSTRUCTOR_INNER_ERROR.getErrorMsg());
}
catch (Exception e) {
throw errorReporter.report(QLErrorCodes.INVOKE_CONSTRUCTOR_UNKNOWN_ERROR.name(),
throw errorReporter.report(e, QLErrorCodes.INVOKE_CONSTRUCTOR_UNKNOWN_ERROR.name(),
QLErrorCodes.INVOKE_CONSTRUCTOR_UNKNOWN_ERROR.getErrorMsg());
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ private Object newObject(Constructor<?> constructor, Object[] params) {
QLErrorCodes.INVOKE_CONSTRUCTOR_INNER_ERROR.getErrorMsg());
}
catch (Exception e) {
throw errorReporter.report(QLErrorCodes.INVOKE_CONSTRUCTOR_UNKNOWN_ERROR.name(),
throw errorReporter.report(e, QLErrorCodes.INVOKE_CONSTRUCTOR_UNKNOWN_ERROR.name(),
QLErrorCodes.INVOKE_CONSTRUCTOR_UNKNOWN_ERROR.getErrorMsg());
}
}
Expand Down
58 changes: 58 additions & 0 deletions src/test/java/com/alibaba/qlexpress4/Express4RunnerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -1968,4 +1968,62 @@ public Object call(QContext qContext, Parameters parameters) {
QLResult result = express4Runner.execute("CURRENT_TIME()", context, QLOptions.DEFAULT_OPTIONS);
assertTrue((Long)result.getResult() > 0);
}

@Test
public void testNewFilledInstanceWithNoDefaultConstructor() {
Express4Runner express4Runner =
new Express4Runner(InitOptions.builder().securityStrategy(QLSecurityStrategy.open()).build());

try {
express4Runner.execute(
"{'@class': 'com.alibaba.qlexpress4.inport.NoDefaultConstructor', 'name': 'test'}",
new HashMap<>(), QLOptions.DEFAULT_OPTIONS);
fail("Expected QLRuntimeException for class without no-arg constructor");
}
catch (QLRuntimeException e) {
assertTrue("Expected NO_SUITABLE_CONSTRUCTOR error but got: " + e.getMessage(),
e.getMessage().contains("no suitable constructor"));
}
}

@Test
public void testVarArgsMethodWithTooFewArgs() {
Express4Runner express4Runner =
new Express4Runner(InitOptions.builder().securityStrategy(QLSecurityStrategy.open()).build());

// Calling a varargs method with fewer arguments than required parameters should
// produce a meaningful error instead of ArrayIndexOutOfBoundsException
try {
express4Runner.execute("com.alibaba.qlexpress4.inport.VarArgsHelper.sum()",
new HashMap<>(), QLOptions.DEFAULT_OPTIONS);
fail("Expected QLRuntimeException for varargs method called with too few args");
}
catch (QLRuntimeException e) {
// Should get a method-not-found or similar error, not ArrayIndexOutOfBoundsException
assertFalse("Should not expose ArrayIndexOutOfBoundsException",
e.getMessage().contains("ArrayIndexOutOfBounds"));
}

// Verify normal varargs calls still work correctly
QLResult result1 = express4Runner.execute(
"com.alibaba.qlexpress4.inport.VarArgsHelper.sumAll()",
new HashMap<>(), QLOptions.DEFAULT_OPTIONS);
assertEquals(0, result1.getResult());

QLResult result2 = express4Runner.execute(
"com.alibaba.qlexpress4.inport.VarArgsHelper.sumAll(1, 2, 3)",
new HashMap<>(), QLOptions.DEFAULT_OPTIONS);
assertEquals(6, result2.getResult());

QLResult result3 = express4Runner.execute(
"com.alibaba.qlexpress4.inport.VarArgsHelper.sum(10, 1, 2, 3)",
new HashMap<>(), QLOptions.DEFAULT_OPTIONS);
assertEquals(16, result3.getResult());

// Calling with exactly the minimum required args (no varargs items) should also work
QLResult result4 = express4Runner.execute(
"com.alibaba.qlexpress4.inport.VarArgsHelper.sum(10)",
new HashMap<>(), QLOptions.DEFAULT_OPTIONS);
assertEquals(10, result4.getResult());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.alibaba.qlexpress4.inport;

/**
* A test helper class that intentionally has NO no-arg constructor,
* used to verify that NewFilledInstanceInstruction reports a proper
* error instead of NullPointerException.
*/
public class NoDefaultConstructor {

private final String name;

public NoDefaultConstructor(String name) {
this.name = name;
}

public String getName() {
return name;
}
}
29 changes: 29 additions & 0 deletions src/test/java/com/alibaba/qlexpress4/inport/VarArgsHelper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.alibaba.qlexpress4.inport;

/**
* A test helper class with varargs methods,
* used to verify that MemberResolver handles varargs resolution correctly
* when fewer arguments than required parameters are provided.
*/
public class VarArgsHelper {

public static String format(String template, Object... args) {
return String.format(template, args);
}

public static int sum(int required, int... rest) {
int total = required;
for (int r : rest) {
total += r;
}
return total;
}

public static int sumAll(int... values) {
int total = 0;
for (int v : values) {
total += v;
}
return total;
}
}