NoClassDefFoundError when trying to define a java UDF

216 views
Skip to first unread message

Benjamin Solwitz

unread,
Dec 4, 2017, 11:31:12 PM12/4/17
to H2 Database
I am attempting to create a java UDF with H2 1.4.196 to replicate the behavior of TRUNC in Oracle. I think I am pretty close, but I am getting an error with the stack trace cut off and I have no idea how to debug it at this point.

Here's my code:

create alias trunc_udf as $$
java.util.Date trunc(java.util.Date dateToTrunc, String whereToTrunc) throws Exception {
  Calendar cal = Calendar.getInstance();
  if(whereToTrunc.equals("HH")) {
    cal.setTime(dateToTrunc);
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.SECOND, 0);
    cal.set(Calendar.MILLISECOND, 0);
    return cal.getTime();
  } else {
    throw new Exception("this H2 UDF only supports HH, please enhance it");
  }
}
$$;

And here's the error message I get back:

Syntax error in SQL statement "/org/h2/dynamic/TRUNC_UDF.java:5: warning: Can't initialize javac processor due to (most likely) a class loader problem: java.lang.NoClassDefFoundError: com/sun/tools/javac/processing/JavacProcessingEnvironment
public class TRUNC_UDF {
       ^
  at lombok.javac.apt.Processor.init(Processor.java:84)
  at lombok.core.AnnotationProcessor$JavacDescriptor.want(AnnotationProcessor.java:87)
  at lombok.core.AnnotationProcessor.init(AnnotationProcessor.java:141)
  at lombok.launch.AnnotationProcessorHider$AnnotationProcessor.init(AnnotationProcessor.java:53)
  at com.sun.tools.javac.processing.JavacProcessingEnvironment$ProcessorState.<init>(JavacProcessingEnvironment.java:500)
  at com.sun.tools.javac.processing.JavacProcessingEnvironment$DiscoveredProcessors$ProcessorStateIterator.next(JavacProcessingEnvironment.java:597)
  at com.sun.tools.javac.processing.JavacProcessingEnvironment.discoverAndRunProcs(JavacProcessingEnvironment.java:690)
  at com.sun.tools.javac.processing.JavacProcessingEnvironment.access$1800(JavacProcessingEnvironment.java:91)
  at com.sun.tools.javac.processing.JavacProcessingEnvironment$Round.run(JavacProcessingEnvironment.java:1035)
  at com.sun.tools.javac.processing.JavacProcessingEnvironment.doProcessing(JavacProcessingEnvironment.java:1176)
  at com.sun.tools.javac.main.JavaCompiler.processAnnotations(JavaCompiler.java:1170)
  at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:856)
  at com.sun.tools.javac.main.Main.compile(Main.java:523)
  at com.sun.tools.javac.api.JavacTaskImpl.doCall(JavacTaskImpl.java:129)
  at com.sun.tools.javac.api.JavacTaskImpl.call(JavacTaskImpl.java:138)
  at org.h2.util.SourceCompiler.javaxToolsJavac(SourceCompiler.java:287)
  at org.h2.util.SourceCompiler$1.findClass(SourceCompiler.java:150)
  at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
  at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
  at org.h2.util.SourceCompiler.getClass(SourceCompiler.java:164)
  at org.h2.util.SourceCompiler.getMethod(SourceCompiler.java:178)
  at org.h2.engine.FunctionAlias.loadFromSource(FunctionAlias.java:131)
  at org.h2.engine.FunctionAlias.load(FunctionAlias.java:119)
  at org.h2.engine.FunctionAlias.init(FunctionAlias.java:106)
  at org.h2.engine.FunctionAlias.newInstanceFromSource(FunctionAlias.java:98)
  at org.h2.command.ddl.CreateFunctionAlias.update(CreateFunctionAlias.java:53)
  at org.h2.command.CommandContainer.update(CommandContainer.java:101)
  at org.h2.command.Command.executeUpdate(Command.java:260)
  at org.h2.server.TcpServerThread.process(TcpServerThread.java:354)
  at org.h2.server.TcpServerThread.run(TcpServerThread.java:158)
  at java.lang.Thread.run(Thread.java:748)
  Caused by: java.lang.ClassNotFoundException: com.sun.tools.javac.processing.JavacProcessingEnvironment
  at java.lang.ClassLoader.findClass(ClassLoader.java:530)
  at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
  at lombok.launch.ShadowClassLoader.loadClass(ShadowClassLoader.java:418)
  at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
  ... 31 more
1 warning
"; SQL statement:
create alias trunc_udf as $$
java.util.Date trunc(java.util.Date dateToTrunc, String whereToTrunc) throws Exception {
  Calendar cal = Calendar.getInstance();
  if(whereToTrunc.equals("HH")) {
    cal.setTime(dateToTrunc);
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.SECOND, 0);
    cal.set(Calendar.MILLISECOND, 0);
    return cal.getTime();
  } else {
    throw new Exception("this H2 UDF only supports HH, please enhance it");
  }
}
$$;
 [42000-196]

Noel Grandin

unread,
Dec 5, 2017, 1:32:42 AM12/5/17
to h2-da...@googlegroups.com
that is very weird. you seem to be missing part of the javac compiler in your installation.​

Benjamin Solwitz

unread,
Dec 5, 2017, 12:44:16 PM12/5/17
to H2 Database
I tried an example from the h2 docs and got the same error:

CREATE ALIAS NEXT_PRIME AS $$
String nextPrime(String value) {
    return new BigInteger(value).nextProbablePrime().toString();
}
$$;

I am starting H2 with gradle, here is the process:

/usr/lib/jvm/java-8-openjdk-amd64/bin/java -Dfile.encoding=UTF-8 -Duser.country=US -Duser.language=en -Duser.variant -cp <huge classpath> org.h2.tools.Server -web -tcp

Benjamin Solwitz

unread,
Dec 5, 2017, 12:51:45 PM12/5/17
to H2 Database
Maybe related to this lombok java 8 issue from 2015?

Noel Grandin

unread,
Dec 5, 2017, 2:13:15 PM12/5/17
to h2-da...@googlegroups.com
ah, yes, this does indeed look like a lombok problem, not a javac problem. 

You'll need to ask them why they are hooked into the javac compiler like that.

Benjamin Solwitz

unread,
Dec 5, 2017, 3:30:45 PM12/5/17
to H2 Database
I guess I can fix this by putting it into a jar on the classpath so H2 doesn't need to compile it?

Noel Grandin

unread,
Dec 6, 2017, 1:44:08 AM12/6/17
to h2-da...@googlegroups.com
yup , that could work too​
Reply all
Reply to author
Forward
0 new messages