0

Short version

When I change resources in my app, then attempt to hot-deploy them, the files are deleted instead of updated from the target/ directory and I don't understand why.

Long version

I have a Java 8 + Tomcat 8 + Spring Boot + Thymeleaf project that I'm running out of IntelliJ. When I change files, such as CSS files from the src/main/resources/static/css directory, and run Update Resources or Update classes and resources, the file is deleted from target/classes/static/css instead of updated. Nothing is printed in the Tomcat logs about the file, nothing is printed in the IntelliJ logs (in ~/Library/Logs/IntelliJIdea13/idea.log) about deleting the file... it just disappears.

Tomcat 8 is set up as an external application server (not the built-in Spring Boot embedded server) with the following config. The only thing I've customized in the IntelliJ Run Configuration setup is to have specified CATALINA_BASE to the same value as the "Tomcat Base", like so:

Tomcat Home: /usr/local/tomcat8
Tomcat Base: /path/to/my/catalina/base
Java Env Vars: CATALINA_BASE=/path/to/my/catalina/base

... If I don't, CATALINA_BASE is set to /Users/me/Library/Caches/IntelliJIdea13/tomcat/Unnamed_demo_app, which seems to be a non-working clone of my real catalina base and I get 404's everywhere. This may be a red herring here, or the key to the mystery.

Extra, probably useless info

Here's the relevant (but uninteresting) output in idea.log:

INFO - ij.compiler.impl.CompileDriver - COMPILATION STARTED (BUILD PROCESS)
INFO - j.compiler.server.BuildManager - BUILDER_PROCESS [stdout]: Build process started. Classpath: /Applications/IntelliJ IDEA 13.app/lib/jps-launcher.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_31.jdk/Contents/Home/lib/tools.jar:/Applications/IntelliJ IDEA 13.app/lib/optimizedFileManager.jar:/Applications/IntelliJ IDEA 13.app/lib/ecj-4.3.2.jar
INFO - lij.compiler.impl.CompilerUtil -   COMPILATION FINISHED (BUILD PROCESS); Errors: 0; warnings: 0 took 3709 ms: 0 min 3sec

The app is configured to do WAR deployments, with a custom catalina base containing a stock conf/server.xml and conf/web.xml, and various 3rd party libraries provided in lib.

Here's my POM:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>myapp</artifactId>
    <version>0.1-BETA</version>
    <packaging>war</packaging>

    <properties>
        <spring-boot-version>1.2.1.RELEASE</spring-boot-version>
        <spring-version>4.1.4.RELEASE</spring-version>
    </properties>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.2.1.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
            <version>${spring-boot-version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
            <version>${spring-boot-version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
            <version>${spring-boot-version}</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.34</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>dojo</artifactId>
            <version>1.10.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <!-- for equals/hash/toString builder -->
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.0.1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <!-- Spring/Mail integration -->
            <groupId>javax.mail</groupId>
            <artifactId>mail</artifactId>
            <version>1.4.7</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <!-- Spring/Mail integration -->
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring-version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <!-- connection pooling -->
            <groupId>com.zaxxer</groupId>
            <artifactId>HikariCP</artifactId>
            <version>2.3.5</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

</project>

I'm not sure really what is worth telling about this issue otherwise, though it doesn't feel like what I've provided is useful. Add a comment if there's any info I should add.

inanutshellus
  • 9,683
  • 9
  • 53
  • 71
  • I spent defining the cataline to be used via VM Options: [see this question](https://stackoverflow.com/questions/28520601/intellij-and-apache-tomcat-not-updating/57674641#57674641) – Daniel Arrais Aug 27 '19 at 12:39

2 Answers2

0

I am guessing that you are using the maven plugin.

By default, any src/main/resources folder will be added to the application classpath when you run the application and any duplicate found in target/classes will be removed. This allows hot refreshing of resources which can be very useful when developing web applications. For example, you can work on HTML, CSS or JavaScipt files and see your changes immediately without recompiling your application. It is also a helpful way of allowing your front end developers to work without needing to download and install a Java IDE.

If you can start the application right from IDEA (just run the main class) I would do that. Otherwise, disable that feature by configuring the plugin:

<build>
  ...
  <plugins>
    ...
    <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
      <version>1.2.3.RELEASE</version>
      <configuration>
        <addResources>false</addResources>
      </configuration>
    </plugin>
    ...
  </plugins>
  ...
</build>

http://docs.spring.io/spring-boot/docs/current/maven-plugin/usage.html

Stephane Nicoll
  • 31,977
  • 9
  • 97
  • 89
  • I wasn't using the maven-plugin, I was using an external Tomcat. But I tried converting to using the maven-plugin I also tried introducing `springloaded` as a dependency, and tried mucking around with the config left and right, but still the `src/main/resources` directory's changes were not being recognized. I had to explicitly add it as a "classes" runtime module dependency before my changes were seen. I can finally make a JS change without restarting Tomcat. – inanutshellus Jun 11 '15 at 02:30
0

I had to explicitly supply src/main/resources as a Runtime Module Dependency in IDEA before changes to my web files (Thymeleaf templates, static files, etc) would be hot-swapped.

Update -- While explicitly setting src/main/resources still feels like a compensating control for misconfiguration on my part, it did let me update my files. However, I still found another issue where my email templates weren't resolvable when packaged in a Spring-Boot jar, giving me an error like this:

org.thymeleaf.exceptions.TemplateInputException: 
    Error resolving template "foo", template might not exist 
    or might not be accessible by any of the configured Template Resolvers
at org.thymeleaf.TemplateRepository.getTemplate(TemplateRepository.java:246)
at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1104)
at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1060)
at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1011)
at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:924)
at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:898)
[...]

I'd had the following code, where I had a leading slash. The leading slash didn't matter when I was configured to use an external Tomcat, but when packaged within the jar the leading slash breaks the classpath search.

@Bean
public ClassLoaderTemplateResolver emailTemplateResolver(){
    ClassLoaderTemplateResolver emailTemplateResolver = new ClassLoaderTemplateResolver();
  //emailTemplateResolver.setPrefix("/templates/mail/");   // <-- The problem!
    emailTemplateResolver.setPrefix("templates/mail/");    // <-- The fix!
    emailTemplateResolver.setSuffix(".html");
    emailTemplateResolver.setTemplateMode("HTML5");
    emailTemplateResolver.setCharacterEncoding("UTF-8");
    emailTemplateResolver.setOrder(1);

    return emailTemplateResolver;
}
Community
  • 1
  • 1
inanutshellus
  • 9,683
  • 9
  • 53
  • 71