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

Spring WebMVC support? #38

Closed
hurelhuyag opened this issue Dec 26, 2020 · 12 comments
Closed

Spring WebMVC support? #38

hurelhuyag opened this issue Dec 26, 2020 · 12 comments
Assignees
Labels
question Further information is requested

Comments

@hurelhuyag
Copy link

Hi, Did you try to integrate with SpringMVC? I tried to use minimal spring-webmvc project. But it can't compile templates.

Here is my minimal MVC setup.

public class Message{
    private final String text;

    public Message(String text) {
        this.text = text;
    }

    public String getText() {
        return text;
    }
}

@ComponentScan("net.hurelhuyag.jtetest")
@EnableWebMvc
@Controller
class Config implements WebMvcConfigurer {

    @Bean
    TemplateEngine templateEngine(ServletContext context) throws MalformedURLException, URISyntaxException {
        var root = context.getResource("/WEB-INF/views/").toURI();
        var codeResolver = new DirectoryCodeResolver(Path.of(root));
        return TemplateEngine.create(codeResolver, ContentType.Html);
    }

    @Bean
    ViewResolver viewResolver(TemplateEngine templateEngine){
        return (viewName, locale) -> (model, request, response) -> {
            templateEngine.render(viewName+".jte", (Map<String, Object>) model, new PrintWriterOutput(response.getWriter()));
        };
    }

    @GetMapping({"/"})
    String index(ModelMap model){
        model.put("message", new Message("Hello World"));
        return "index";
    }
}

Error:

/tmp/demo-jte-classes/gg/jte/generated/JteindexGenerated.java:2: error: package net.hurelhuyag.jtetest does not exist
import net.hurelhuyag.jtetest.Message;
                             ^
/tmp/demo-jte-classes/gg/jte/generated/JteindexGenerated.java:6: error: package gg.jte.html does not exist
	public static void render(gg.jte.html.HtmlTemplateOutput jteOutput, gg.jte.html.HtmlInterceptor jteHtmlInterceptor, Message message) {
	                                     ^
/tmp/demo-jte-classes/gg/jte/generated/JteindexGenerated.java:6: error: package gg.jte.html does not exist
	public static void render(gg.jte.html.HtmlTemplateOutput jteOutput, gg.jte.html.HtmlInterceptor jteHtmlInterceptor, Message message) {
	                                                                               ^
/tmp/demo-jte-classes/gg/jte/generated/JteindexGenerated.java:6: error: cannot find symbol
	public static void render(gg.jte.html.HtmlTemplateOutput jteOutput, gg.jte.html.HtmlInterceptor jteHtmlInterceptor, Message message) {
	                                                                                                                    ^
  symbol:   class Message
  location: class JteindexGenerated
@casid
Copy link
Owner

casid commented Dec 26, 2020

@hurelhuyag no I haven't tried that (I did not use Spring MVC so far).

Does the exception message say more about the error? There was a slightly similiar error with Ktor Framework (#35), which was resolved by setting another classloader for the jte.

Do you have your sample project in a repository? If you want, I'll have a look at it.

@hurelhuyag
Copy link
Author

here is my sample https://github.com/hurelhuyag/demo-spring-jte

@casid
Copy link
Owner

casid commented Dec 26, 2020

Thanks for sharing. How do I run the sample? The main method is commented out and it seems to be not related to Spring.

From looking at the code, I noticed that Config is located within the Message class file. Could you try to put it as a top level class? Maybe that already resolves the classloader problem.

@hurelhuyag
Copy link
Author

It's war project. You need tomcat supported IDE. IntelliJ or something.

@casid
Copy link
Owner

casid commented Dec 26, 2020

I'm working with IntelliJ. But without some setup instructions I won't be able to help you. I'm confused by your setup. You have spring boot configured in the pom, but you run as WAR on local Tomcat?

Did you try my suggestion about the Config class?

@hurelhuyag
Copy link
Author

@hurelhuyag
Copy link
Author

sample repo cleaned and tomcat9 plugin added. Now can run with this command

 mvn package org.codehaus.cargo:cargo-maven2-plugin:run

@casid
Copy link
Owner

casid commented Dec 26, 2020

Thanks! I was able to reproduce the error.

It was a bit hard to debug, but the problem is that ToolProvider.getSystemJavaCompiler() on Tomcat does not include the current class path when compiling classes. That's why no classes are known to the compiler.

Now I understand your previous question about hot reload a lot better. You started with precompiled templates and now you tried hot reload, but it does not work with WAR deployments.

I probably won't be able to look into the WAR / Tomcat issue anytime soon. None of my projects use that setup anymore, instead they run an embedded webserver and start with a simple main method, so my motivation for application server support is not very high :-)

Since this question is about Spring MVC, maybe Spring Boot is an option for you?

I forked your demo repository and changed it to a Spring Boot application (https://github.com/casid/demo-spring-jte). Now hot reloading works as expected. To give it a try, you'd need to clone it and run/debug Application::main. If hot reloading does not work for you, you might need to do a mvn clean first (the generated jte sources were still present in my case).

@hurelhuyag
Copy link
Author

It works on spring-boot. Great. But I still don't understand what makes different spring-boot still uses tomcat9.

@casid
Copy link
Owner

casid commented Dec 26, 2020

The difference is that Spring Boot uses an embedded Tomcat, so the application class loader is used.

A standalone Tomcat runs every deployed WAR in isolation with its own classloader (see https://tomcat.apache.org/tomcat-8.0-doc/class-loader-howto.html). And apparently with this setup the Java compiler behaves differently, too.

Are you forced to use a standalone Tomcat by a client or so? If not, I'd recommend to try the Spring Boot way. The development experience is a lot better. Imho running that in production, too.

@casid casid added the question Further information is requested label Dec 26, 2020
@casid casid self-assigned this Dec 26, 2020
@casid casid closed this as completed Feb 4, 2021
@izogfif
Copy link

izogfif commented Jun 25, 2021

@hurelhuyag
I found the working configuration for your project. Here is the fork with the working version: https://github.com/izogfif/demo-spring-jte
@casid maybe add this as a demo for spring-webmvc?

In src/main/java/net/hurelhuyag/jtetest/Config.java file I replaced

return TemplateEngine.create(codeResolver, Path.of("/tmp/demo-jte-classes"), ContentType.Html);

with

return TemplateEngine.create(codeResolver, Path.of("/WEB-INF/classes/"), ContentType.Html, this.getClass().getClassLoader());

in pom.xml I changed

<jte.version>1.5.0</jte.version>

to

<jte.version>1.11.0</jte.version>

@casid
Copy link
Owner

casid commented Jun 25, 2021

Hey @izogfif, thanks for sharing! I added a link to your repostitory to the jte readme.

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

No branches or pull requests

3 participants