Skip to content

Issue #11: Support of static functions with varargs #22

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: 5.0.0
Choose a base branch
from
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
1 change: 1 addition & 0 deletions src/main/java/org/glassfish/expressly/Messages.properties
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ error.property.notfound=Property ''{1}'' not found on {0}
error.fnMapper.null=Expression uses functions, but no FunctionMapper was provided
error.fnMapper.method=Function ''{0}'' not found
error.fnMapper.paramcount=Function ''{0}'' specifies {1} params, but {2} were supplied
error.fnMapper.minparamcount=Function ''{0}'' requires at least {1} params, but {2} were supplied

# **ExpressionImpl
error.context.null=ELContext was null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,12 @@ public void visit(Node node) throws ELException {

int parameterCount = functionMethod.getParameterCount();
int argumentCount = ((AstMethodArguments) node.jjtGetChild(0)).getParameterCount();
if (argumentCount != parameterCount) {
if(functionMethod.isVarArgs()) {
// last param of the method is the vararg -> 0..n vararg-arguments allowed
if (argumentCount < parameterCount - 1) {
throw new ELException(MessageFactory.get("error.fnMapper.minparamcount", funcNode.getOutputName(), parameterCount - 1, argumentCount));
}
} else if (argumentCount != parameterCount) {
throw new ELException(MessageFactory.get("error.fnMapper.paramcount", funcNode.getOutputName(), parameterCount, argumentCount));
}
} else if (node instanceof AstIdentifier && varMapper != null) {
Expand Down
12 changes: 6 additions & 6 deletions src/main/java/org/glassfish/expressly/parser/AstFunction.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

import org.glassfish.expressly.lang.EvaluationContext;
import org.glassfish.expressly.util.MessageFactory;
import org.glassfish.expressly.util.ReflectionUtil;

import jakarta.el.ELClass;
import jakarta.el.ELException;
Expand Down Expand Up @@ -167,12 +168,11 @@ public Object getValue(EvaluationContext ctx) throws ELException {
Class<?>[] paramTypes = functionMethod.getParameterTypes();
Object[] params = ((AstMethodArguments) this.children[0]).getParameters(ctx);
Object result = null;
for (int i = 0; i < params.length; i++) {
try {
params[i] = ctx.convertToType(params[i], paramTypes[i]);
} catch (ELException ele) {
throw new ELException(MessageFactory.get("error.function", this.getOutputName()), ele);
}
try {
params = ReflectionUtil.buildParameters(ctx, paramTypes, functionMethod.isVarArgs(), params);
}
catch(ELException ele) {
throw new ELException(MessageFactory.get("error.function", this.getOutputName()), ele);
}

try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -655,7 +655,8 @@ public static Object[] buildParameters(ELContext context, Class<?>[] parameterTy
}

// Last parameter is the varargs
if (parameterTypes.length == paramCount && parameterTypes[varArgIndex] == params[varArgIndex].getClass()) {
if (parameterTypes.length == paramCount &&
(params[varArgIndex] == null || parameterTypes[varArgIndex] == params[varArgIndex].getClass())) {
parameters[varArgIndex] = params[varArgIndex];
} else {
Class<?> varArgClass = parameterTypes[varArgIndex].getComponentType();
Expand Down
66 changes: 66 additions & 0 deletions src/test/java/org/glassfish/el/test/ELProcessorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,12 @@

import jakarta.el.ELProcessor;
import jakarta.el.ELManager;
import jakarta.el.ELException;
import jakarta.el.ExpressionFactory;
import jakarta.el.MethodExpression;
import jakarta.el.ELContext;
import java.lang.reflect.Method;
import java.util.Arrays;

public class ELProcessorTest {

Expand Down Expand Up @@ -160,6 +162,61 @@ public void defineFuncTest() {
}
assertTrue(caught);
}

@Test
public void defineVarargFuncTest()
{
Class<?> c = MyBean.class;
Method meth1 = null;
Method meth2 = null;
try {
meth1 = c.getMethod("join", new Class<?>[] {String[].class});
meth2 = c.getMethod("joinPrefixed", new Class<?>[] {String.class, String[].class});
} catch(Exception e) {
System.out.printf("Exception: ", e);
}
try {
elp.defineFunction("xx", "", meth1);
String joined = elp.eval("xx:join()");
assertEquals("", joined);
joined = elp.eval("xx:join('abc')");
assertEquals("abc", joined);
joined = elp.eval("xx:join('abc','def')");
assertEquals("abc,def", joined);
joined = elp.eval("xx:join('abc',null)"); // null is converted to empty string
assertEquals("abc,", joined);
joined = elp.eval("xx:join(null)"); // this is join((String[])null) in Java
assertEquals("<null array>", joined);
} catch(NoSuchMethodException ex) {

}

boolean caught = false;
try {
elp.defineFunction("xx", "", meth2);
Integer sum = elp.eval("xx:joinPrefixed()");
assertEquals(0, sum.intValue());
} catch (ELException ex) {
caught = true;
} catch (NoSuchMethodException ex) {

}
assertTrue(caught);

try {
elp.defineFunction("xx", "", meth2);
String joined = elp.eval("xx:joinPrefixed('res:')");
assertEquals("res:", joined);
joined = elp.eval("xx:joinPrefixed('res:', 'abc')");
assertEquals("res:abc", joined);
joined = elp.eval("xx:joinPrefixed('res:', 'abc', 'def')");
assertEquals("res:abc,def", joined);
joined = elp.eval("xx:joinPrefixed('res:', null)");
assertEquals("res:<null array>", joined);
} catch(NoSuchMethodException ex) {

}
}
/*
@Test
public void testBean() {
Expand Down Expand Up @@ -200,6 +257,15 @@ public int getFoo(int i) {
public static int getBar() {
return 64;
}
public static String join(String... args) {
if(args == null)
return "<null array>";

return String.join(",", args);
}
public static String joinPrefixed(String prefix, String... args) {
return prefix + join(args);
}
}
}