Reputation: 5120
Overriding a bean definition appears to me be harder than what I thought. First of all, I would like to keep Open/Close principle.
I am using Springfox that would provide a swagger json based on Spring Mapping. Springfox is loaded by a Config class that I have to provide:
@EnableWebMvc
@Configuration
@Import({Swagger2DocumentationConfiguration.class})
@ComponentScan(basePackages = {"special.package.swagger"})
public class ApplicationSwaggerConfig {
@Bean
public Docket swaggerApi() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("rest-api")
.select()
.build()
.pathMapping("/rest-api");
}
...
Of course, I don't wanna change Swagger2DocumentationConfiguration class (following the open/closed principle) but change the behavior of ServiceModelToSwagger2Mapper.
For that, I created a MyServiceModelToSwagger2Mapper class in "special.package.swagger" folder such as:
@Component
@Primary
public class MyServiceModelToSwagger2Mapper extends ServiceModelToSwagger2MapperImpl {
@Override
public Swagger mapDocumentation(Documentation from) {
System.out.println("\n\n\n\n\n\n\n\n\n\n\n\n\n******************** Override works!!!\n");
return super.mapDocumentation(from);
}
}
Spring loads the component, what solves the ambiguity problem but at the override does not work. Does anyone has any idea why!?
Edit: @smarquis comments helped a lot. Spring is working properly.
I accidentally added multiple versions of springfox library. The application server loaded both libraries and got lost. Once the classpath issue was solved overriding worked perfectly.
Upvotes: 1
Views: 8931
Reputation: 540
It is due to the way spring with java config is build -- it is getting quite complex internally with proxies and stuff.
I do not remember exactly the reason, but if you do it like this your override works:
@EnableWebMvc
@Configuration
@Import({Swagger2DocumentationConfiguration.class})
//@ComponentScan(basePackages = {"springfoxswagger.specialpackageswagger"})
public class ApplicationSwaggerConfig {
@Bean
public Docket swaggerApi() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("rest-api")
.select()
.build()
.pathMapping("/rest-api");
}
@Bean
public springfox.documentation.swagger2.mappers.ServiceModelToSwagger2Mapper mapper() {
return new ServiceModelToSwagger2MapperImpl() {
public Swagger mapDocumentation(Documentation from) {
System.out.println("\n\n\n\n\n\n\n\n\n\n\n\n\n******************** Override works!!!\n");
return super.mapDocumentation(from);
}
};
}
}
It is also simpler, arguably.
EDIT
It seems not to work for the OP, so I investigated a bit further.
Note that you do not need the @Primary annotation on the bean, wierdly enough.
2016-01-26 08:50:26.594 INFO 58548 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization completed in 22 ms
******************** Override works!!!
"Simple" solutions like adding @BeanNameAware or @AnnotationConfigDriven will not do. IMO OP bumped into a Spring Java Config bug or limitation; I do not see any reason why his solution does not work.
Upvotes: 1
Reputation: 9648
Try putting @AnnotationDrivenConfig
on your class and try this:
@EnableWebMvc
@Configuration
@AnnotationDrivenConfig
@Import({Swagger2DocumentationConfiguration.class})
public class ApplicationSwaggerConfig {
@Bean
public Docket swaggerApi() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("rest-api")
.select()
.build()
.pathMapping("/rest-api");
}
@Bean
@Primary
public MyServiceModelToSwagger2Mapper mapper() {
return new MyServiceModelToSwagger2Mapper();
}
}
MyServiceModelToSwagger2Mapper Class:
public class MyServiceModelToSwagger2Mapper extends ServiceModelToSwagger2MapperImpl {
@Override
public Swagger mapDocumentation(Documentation from) {
System.out.println("\n\n\n\n\n\n\n\n\n\n\n\n\n******************** Override works!!!\n");
return super.mapDocumentation(from);
}
}
Upvotes: 0