Search code examples
intellij-ideaspring-bootclassloader

Spring boot devtools load twice of a class and cause LinkageError


IDE is Idea, Spring boot project have META-INF/spring-devtools.properties, the content is

restart.include.dozer=/dozer-5.5.1.jar

when run project throw below exception

2015-12-03 12:02:49,491 [restartedMain] INFO  org.dozer.DozerBeanMapper - Initializing a new instance of dozer bean mapper.
2015-12-03 12:02:49,494 [restartedMain] WARN  o.s.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dozerBeanMapper' defined in class path resource [com/foo/common/CommonConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.dozer.Mapper]: Factory method 'dozerBeanMapper' threw exception; nested exception is java.lang.LinkageError: loader constraint violation: loader (instance of org/springframework/boot/devtools/restart/classloader/RestartClassLoader) previously initiated loading for a different type with name "org/dozer/DozerBeanMapper"
2015-12-03 12:02:49,517 [restartedMain] ERROR org.springframework.boot.SpringApplication - Application startup failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dozerBeanMapper' defined in class path resource [com/foo/common/CommonConfiguration.class]: Bean instantiation via factory method failed; nested exception is    org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.dozer.Mapper]: Factory method 'dozerBeanMapper' threw exception; nested exception is java.lang.LinkageError: loader constraint violation: loader (instance of org/springframework/boot/devtools/restart/classloader/RestartClassLoader) previously initiated loading for a different type with name "org/dozer/DozerBeanMapper"
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:599) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE]

What strange is when run the project in Eclipse, no above problem. Add -XX:+TraceClassLoading configuration in idea, I found dozer is loaded twice.

9569 [Loaded org.dozer.DozerBeanMapper from file:/C:/Users/otto/.m2/repository/net/sf/dozer/dozer/5.5.1/dozer-5.5.1.jar]

9618 [Loaded org.dozer.DozerBeanMapper from file:/C:/Users/otto/.m2/repository/net/sf/dozer/dozer/5.5.1/dozer-5.5.1.jar]

Now I don't know how to locate the reason of this problem?


Solution

  • There's some critical information in the README of the project that you shared that's not included in the question:

    Download sample project then import this project to eclipse, closed bar project then run FooApplication you could get below error

    Closing the bar project mean that its classes will not be eligible for restart. This means that they will be loaded by the main class loader rather than the restart class loader. The code in bar depends on Dozer, but you've configured DevTools so that Dozer's classes will be loaded by the restart class loader:

    restart.include.dozer=/dozer-5.5.1.jar
    

    It's not clear to me why you've configured things this way. Your sample works fine for me if I delete spring-devtools.properties. Perhaps the sample doesn't illustrate the problem that caused you to apply that configuration?

    If you do need this configuration and you don't want to have the bar project open in Eclipse then you also need to configure bar to be included in restarts so that both it and Dozer upon which it depends are loaded by the restart class loader:

    restart.include.dozer=/dozer-5\.5\.1\.jar
    restart.include.bar=/bar-1\.0-SNAPSHOT\.jar