-
Notifications
You must be signed in to change notification settings - Fork 41.6k
Description
This application will fail to start:
package com.example;
import java.io.IOException;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.jackson.JsonComponent;
import org.springframework.core.convert.ConversionService;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
@SpringBootApplication
public class JsonComponentConversionServiceCycle {
public static void main(String[] args) {
SpringApplication.run(JsonComponentConversionServiceCycle.class, args)
.getBean(ConversionService.class);
}
@JsonComponent
static class ThingDeserializer extends JsonDeserializer<Thing> {
public ThingDeserializer(ConversionService conversionService) {
}
@Override
public Thing deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
return null;
}
}
static class Thing {
}
}
***************************
APPLICATION FAILED TO START
***************************
Description:
The dependencies of some of the beans in the application context form a cycle:
┌─────┐
| jsonComponentConversionServiceCycle.ThingDeserializer defined in file [/Users/awilkinson/dev/workspaces/spring/spring-boot/1.5.x/security-4202/target/classes/com/example/JsonComponentConversionServiceCycle$ThingDeserializer.class]
↑ ↓
| org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$EnableWebMvcConfiguration
↑ ↓
| org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter
↑ ↓
| org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration
↑ ↓
| mappingJackson2HttpMessageConverter defined in class path resource [org/springframework/boot/autoconfigure/web/JacksonHttpMessageConvertersConfiguration$MappingJackson2HttpMessageConverterConfiguration.class]
↑ ↓
| jacksonObjectMapper defined in class path resource [org/springframework/boot/autoconfigure/jackson/JacksonAutoConfiguration$JacksonObjectMapperConfiguration.class]
└─────┘
If you bring Spring Security into the mix (by extending WebSecurityConfigurerAdapter) the problem will appear to have gone away as some eager initialisation that Spring Security triggers manages to break the cycle. The cycle is broken by Spring Security triggering the creation of the conversion service before any WebMvcConfigurerAdapter beans have been injected into DelegatingWebMvcConfiguration. This has the unwanted side-effect of losing any conversion service-related configuration that would have been performed by those beans. There's a Spring Security issue that can hopefully be used to prevent it from triggering that early initialisation.
A user can avoid the problem by marking the ConversionService dependency as @Lazy. It would be better if they didn't have to do that, though. One solution that appears to work is for the HttpMessageConverters dependency in WebMvcAutoConfigurationAdapter to be marked as @Lazy.