How to configure spring boot dev tools so it doesn't fail when an interface is loaded by both classloaders?

102 views Asked by At

I keep getting errors with the RestartClassLoader including

java.lang.LinkageError: loader constraint violation: loader 'app' wants to load
interface com.company.core.AnInterface. A different interface with the same name was
previously loaded by org.springframework.boot.devtools.restart.classloader.RestartClassLoader
@7ee94bd7. (com.company.core.AnInterface is in unnamed module of loader
org.springframework.boot.devtools.restart.classloader.RestartClassLoader
@7ee94bd7, parent loader 'app')

I'm building a multi-module spring boot project with a structure similar to

com.company.parent (to tie everything together)
com.company.app (dependencies for core and module)
com.company.core
com.company.module

I define an interface in the core project, AnInterface.

public interface AnInterface {
    String getInterfaceId();
    boolean isInterface(AnInterface anInterface);
}

I also have an abstract Entity class in module, AbstractEntity.

@Data
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class AbstractEntity implements AnInterface {
    private String interfaceId;
        private abstract boolean isInterface(AnInterface anInterface);
}

In the appplication package I have the SubEntity

@Data
@Entity
@EntityListeners(AuditingEntityListener.class)
public class SubEntity extends AbstractEntity implements Serialiazable {
    @Override
    public boolean isInterface(AnInterface  anInterface) {
        //check for nulls ommited
        return anInterface.getId().equals(getInterfaceId());
    }
}

As I understand the error, DevTools uses two class loaders. One for the app, and then one for all the dependencies, of which core, and module are. AnInterface gets loaded by both causing 2 different versions of AnInterface.

From what I understand there are ways to have RestartClassLoader include or exclude classes/sources/jars but I'm having issues with the placement and syntax.

The only way I can bypass the exception is to add a system property in my main class

@SpringBootApplication
@EnableAutoCOnfiguration
@CompnentScan(basePackages = {"com.company.web", "com.company.core", "com.company.module"}
@EnableJpaRepositories(basePackages = {"com.company.web", "com.company.core", "com.company.module"}
@EntityScan(basePackages = {"com.company.web", "com.company.core", "com.company.module"}
@PropertySource("classpath:application.properties")
@PropertySource("classpath:module.properties")
@PropertySource("classpath:core.properties")
public class MainClass implements WebMvcConfigurer {
    public static void main(String[] args) {
    System.setProperty("spring.devtools.restart.enabled", "false");
    }
}

If I put spring.devtools.restart.enabled=false into application.properties it doesn't appear to do anything. I also tried creating a spring-devtools.properties in the same folder as application.properties which didn't fix it either.

While this gets me to be able to continue developing, losing the ability for devtools to restart the application is slowing me down. How can I configure devtools restartClassLoader to avoid this collission?

The best I could figure out it has something to do with setting in application.properties a property like

restart.include.com-company-core=/com-company-core-[\\w\\d-\\.]+\\.jar
restart.include.com-company-module=/com-company-module-[\\w\\d-\\.]+\\.jar

but that hasn't worked for me and neither did putting it in the main class as

System.setProperty("spring.devtools.restart.include.com-company-module", "/com-company-core-[\\\\w\\\\d-\\\\.]+\\\\.jar]");
System.setProperty("spring.devtools.restart.include.com-company-module", "/com-company-module-[\\\\w\\\\d-\\\\.]+\\\\.jar]");

It feels like I'm close, what am I missing to be able to get devtools restart working again?

0

There are 0 answers