Skip to content
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

java.lang.NoClassDefFoundError: gg/jte/html/HtmlTemplateOutput #280

Closed
venkatwilliams opened this issue Oct 4, 2023 · 4 comments
Closed
Assignees

Comments

@venkatwilliams
Copy link

venkatwilliams commented Oct 4, 2023

Handler dispatch failed: java.lang.NoClassDefFoundError: gg/jte/html/HtmlTemplateOutput] with root cause

java.lang.ClassNotFoundException: gg.jte.html.HtmlTemplateOutput
at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:445) ~[na:na]
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:592) ~[na:na]
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:525) ~[na:na]
at java.base/java.lang.Class.getDeclaredMethods0(Native Method) ~[na:na]
at java.base/java.lang.Class.privateGetDeclaredMethods(Class.java:3402) ~[na:na]
at java.base/java.lang.Class.getDeclaredMethods(Class.java:2504) ~[na:na]
at gg.jte.runtime.Template.findRenderMethods(Template.java:69) ~[jte-runtime-3.1.0.jar!/:na]
at gg.jte.runtime.Template.(Template.java:26) ~[jte-runtime-3.1.0.jar!/:na]
at gg.jte.runtime.TemplateLoader.load(TemplateLoader.java:26) ~[jte-runtime-3.1.0.jar!/:na]
at java.base/java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1708) ~[na:na]
at gg.jte.TemplateEngine.resolveTemplate(TemplateEngine.java:339) ~[jte-runtime-3.1.0.jar!/:na]
at gg.jte.TemplateEngine.render(TemplateEngine.java:228) ~[jte-runtime-3.1.0.jar!/:na]

private static Path JTE_FILE_PATH = Path.of("src", "main", "resources", "jte");
private static Path JTE_PRECOMPILED_FILE_PATH = Path.of("jte-classes");

if(activeProfile != null) {
   CodeResolver codeResolver = new DirectoryCodeResolver(JTE_FILE_PATH);
   this.templateEngine = TemplateEngine.create(codeResolver, ContentType.Html);
} else {
  this.templateEngine = TemplateEngine.createPrecompiled(JTE_PRECOMPILED_FILE_PATH, ContentType.Html);
}

I can see the dependent libraries in the jar file.

inflated: META-INF/build-info.properties
created: BOOT-INF/classes/jte/
inflated: BOOT-INF/classes/jte/hello.jte
inflated: BOOT-INF/classes/application.properties
extracted: BOOT-INF/lib/jte-extension-api-3.1.0.jar
extracted: BOOT-INF/lib/jte-runtime-3.1.0.jar
extracted: BOOT-INF/lib/jte-3.1.0.jar

build.gradle file


dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.projectlombok:lombok:1.18.20'
    implementation 'junit:junit:4.13.1'
    compileOnly 'org.projectlombok:lombok' // Plugin to remove boilerplate code
    annotationProcessor 'org.projectlombok:lombok'
    implementation 'com.google.cloud:google-cloud-aiplatform:3.24.0'
    implementation 'com.google.code.gson:gson:2.10.1'
    implementation 'org.postgresql:postgresql:42.6.0'
    implementation 'com.pgvector:pgvector:0.1.3'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'com.google.cloud:spring-cloud-gcp-starter-secretmanager:4.7.2'
    implementation 'com.google.cloud:spring-cloud-gcp-starter:4.7.2'

    implementation 'org.apache.commons:commons-dbcp2:2.9.0'
    implementation 'org.apache.tomcat:tomcat-jdbc:10.1.13'

    implementation 'gg.jte:jte:3.1.0'
    implementation 'com.puppycrawl.tools:checkstyle:10.12.3'
    testImplementation 'com.h2database:h2'

    implementation 'org.springframework.boot:spring-boot-starter-validation'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
}

tasks.precompileJte {
    sourceDirectory = Paths.get(project.projectDir.absolutePath, "src", "main", "resources", "jte")
    targetDirectory = Paths.get(project.projectDir.absolutePath, "jte-classes")
    compilePath = sourceSets.main.runtimeClasspath
    contentType = ContentType.Html
}

tasks.precompileJte {
    dependsOn(tasks.compileJava)
}

tasks.test {
    dependsOn(tasks.precompileJte)
}
@casid
Copy link
Owner

casid commented Oct 4, 2023

Hi, from the stacktrace I assume the error happens in the TemplateEngine.createPrecompiled branch.

When this happens with Spring Boot it usually is a classloader problem. Can you try to pass the Spring Boot classloader like this?
TemplateEngine.createPrecompiled(JTE_PRECOMPILED_FILE_PATH, ContentType.Html, getClass().getClassLoader());

@venkatwilliams
Copy link
Author

With this change it is working.
TemplateEngine.createPrecompiled(JTE_PRECOMPILED_FILE_PATH, ContentType.Html, getClass().getClassLoader());

Want to know the best practice in managing "jte-classes" code.

  1. Is it good to commit the generated classes in github or generate them every build time?
  2. Is it good practice to include jte generated classes along with src/main/java classes inside the jar file?
  3. If so how do do in this in Gradle project?
  4. If we include jte-classes as part of of jar file what would be the path in place of JTE_PRECOMPILED_FILE_PATH

@casid
Copy link
Owner

casid commented Oct 4, 2023

Glad it is working!

Personally, I put the jte source files in something like src/main/jte (like we do it with Java files)

If you want a self contained jar, you can use the generate Gradle task as described here: https://github.com/casid/jte/blob/main/DOCUMENTATION.md#using-the-application-class-loader-since-120. This way the Gradle task only generates a Java file for each jte file and leaves compilation to the regular Java compiler. You can specify which package the jte templates be located in, but you don't have to. With the default config, you would just create the template engine like this: TemplateEngine templateEngine = TemplateEngine.createPrecompiled(ContentType.Html);(I think in this case there won't be a need to specify the Spring classloader either)

@venkatwilliams
Copy link
Author

Thank you very much @casid both the suggestions worked fine.

Able to include jte generated classes inside jar file using the gradle task.
https://github.com/casid/jte/blob/main/DOCUMENTATION.md#using-the-application-class-loader-since-120

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants