Closed tuzonghua closed 5 months ago
It looks like this doesn't even work in Java. Not sure what I'm missing. There aren't a ton of examples out there to compare to.
import com.google.common.collect.Maps;
import com.hubspot.jinjava.Jinjava;
import com.hubspot.jinjava.lib.fn.ELFunctionDefinition;
import java.util.Map;
public class JinjavaTest {
public static void main(String[] args) {
Jinjava jinjava = new Jinjava();
Map<String, Object> context = Maps.newHashMap();
String template = "{% if is_day_of_week(input_date) %} SELECT {{ input_date }} FROM `table` {% endif %}";
jinjava.getGlobalContext().registerFunction(
new ELFunctionDefinition(
"",
"is_day_of_week",
JinjavaTest.class,
"isDayOfWeek",
String.class
)
);
context.put("input_date", "2024-03-23");
String renderedTemplate = jinjava.render(template, context);
System.out.println(renderedTemplate);
}
boolean isDayOfWeek(String param) {
return true;
}
}
It turned out to be my mistake. My Java example above was incorrectly declaring the isDayOfWeek
method (it should be public static boolean isDayOfWeek()
). As for the Scala code, the example above compiles to public boolean isDayOfWeek(java.lang.String);
rather than public static boolean isDayOfWeek(java.lang.String);
. The correct approach is to use a companion object to compile to the correct Java method signature, like so:
class MyFuncsClass {
import MyFuncsClass.isDayOfWeek
}
object MyFuncsClass {
def isDayOfWeek(param: String): Boolean =
true
}
@tuzonghua Check out https://github.com/HubSpot/jinjava/blob/master/src/test/java/com/hubspot/jinjava/lib/fn/InjectedContextFunctionProxyTest.java#L73 for if you want to register non-static methods
@jasmith-hs Thanks! I tried this and got a different error. I think that it's still due to what the Scala code gets compiled to (the class containing the target method gets compiled to public class MyFuncsClass
rather than public static class MyFuncsClass
). I'm fine using Scala companion objects for now.
package some.test.package
import com.hubspot.jinjava.Jinjava
import com.hubspot.jinjava.lib.fn.{ELFunctionDefinition, InjectedContextFunctionProxy}
import java.lang.reflect.Method
import java.util
class MyFuncsClass {
def isDayOfWeek(param: String): Boolean =
true
}
object JinjavaScalaTest extends App {
val jinjava: Jinjava = new Jinjava()
val context: util.HashMap[String, Object] = new util.HashMap[String, Object]()
val template: String = "{% if is_day_of_week(input_date) %} SELECT {{ input_date }} FROM `table` {% endif %}"
val m: Method = classOf[MyFuncsClass].getDeclaredMethod("isDayOfWeek", classOf[String])
val instance = new MyFuncsClass
val proxy: ELFunctionDefinition = InjectedContextFunctionProxy.defineProxy(
"",
"is_day_of_week",
m,
instance
)
jinjava.getGlobalContext.registerFunction(proxy)
context.put("input_date", "2024-03-19")
val renderedTemplate: String = jinjava.render(template, context)
println(renderedTemplate)
}
Output:
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "java.lang.reflect.AccessibleObject.setAccessible(boolean)" because "ao" is null
at javassist.util.proxy.SecurityActions.setAccessible(SecurityActions.java:103)
at javassist.util.proxy.DefineClassHelper.toClass3(DefineClassHelper.java:151)
at javassist.util.proxy.DefineClassHelper.toClass2(DefineClassHelper.java:134)
at javassist.util.proxy.DefineClassHelper.toClass(DefineClassHelper.java:95)
at javassist.ClassPool.toClass(ClassPool.java:1143)
at javassist.ClassPool.toClass(ClassPool.java:1106)
at javassist.ClassPool.toClass(ClassPool.java:1064)
at javassist.CtClass.toClass(CtClass.java:1275)
at com.hubspot.jinjava.lib.fn.InjectedContextFunctionProxy.defineProxy(InjectedContextFunctionProxy.java:82)
at some.test.package.JinjavaScalaTest$.delayedEndpoint$some$test$package$JinjavaScalaTest$1(JinjavaScalaTest.scala:25)
at some.test.package.JinjavaScalaTest$delayedInit$body.apply(JinjavaScalaTest.scala:14)
at scala.Function0.apply$mcV$sp(Function0.scala:42)
at scala.Function0.apply$mcV$sp$(Function0.scala:42)
at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:17)
at scala.App.$anonfun$main$1(App.scala:98)
at scala.App.$anonfun$main$1$adapted(App.scala:98)
at scala.collection.IterableOnceOps.foreach(IterableOnce.scala:575)
at scala.collection.IterableOnceOps.foreach$(IterableOnce.scala:573)
at scala.collection.AbstractIterable.foreach(Iterable.scala:933)
at scala.App.main(App.scala:98)
at scala.App.main$(App.scala:96)
at some.test.package.JinjavaScalaTest$.main(JinjavaScalaTest.scala:14)
at some.test.package.JinjavaScalaTest.main(JinjavaScalaTest.scala)
I'm trying to render a simple custom function in a Jinja template and getting a
NullPointerException
. I've included the elided stack trace. My example below is in Scala, hopefully that's not an issue unto itself.Build env:
Sample code:
Output: