Failed to start bean 'documentationPluginsBootstrapper' Spring boot Swagger implementation using Spring Fox? - spring-boot

I am using springfox-boot-starter dependency for swagger UI in my spring boot application but when I try to run the application I am getting below error
Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NoSuchMethodError: org.springframework.plugin.core.PluginRegistry.getPluginFor(Ljava/lang/Object;)Ljava/util/Optional;
at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:184)
at org.springframework.context.support.DefaultLifecycleProcessor.access$200(DefaultLifecycleProcessor.java:52)
at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:356)
at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:157)
at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:121)
at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:885)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.finishRefresh(ServletWebServerApplicationContext.java:161)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:553)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:759)
my config file:
#Bean
public Docket productApi() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("com.swagger.demo.controller"))
.paths(regex("/student.*"))
.build()
.enableUrlTemplating(true)
.produces(DEFAULT_PRODUCES_AND_CONSUMES)
.consumes(DEFAULT_PRODUCES_AND_CONSUMES)
.apiInfo(apiEndPointsInfo());
}
private ApiInfo apiEndPointsInfo() {
return new ApiInfoBuilder()
.title("demo")
.description("demo")
.version("1.0")
.build();
}
Below is the dependency which I am using.
pom.xml file:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
</dependencies>
Why I am getting above error I don't get anything. Any help would be highly appreciated. Thanks in advance.

I had a similar issue and found the solution here.
Basically you have to include in the file application.properties the following configuration:
spring.mvc.pathmatch.matching-strategy=ant-path-matcher
As it seems Spring Boot 2+ set as default the PathPathern-based matcher, while Spring Fox expects the Ant-based matcher.
The problem with this solution is that you cannot use Spring Actuator, since it uses PathPattern based URL matching. In this case, check this Spring Fox issue.

SwaggerConfig.java
#Configuration
//Enable Swagger
#EnableSwagger2
public class SwaggerConfig
{
//creating bean
#Bean
public Docket api()
{
//creating constructor of Docket class that accepts parameter DocumentationType
return new Docket(DocumentationType.SWAGGER_2).select().apis(RequestHandlerSelectors.basePackage("com.example.demo.controller")).paths(PathSelectors.regex("/api.*")).build();
}
}
And Application.properties file :
spring.mvc.pathmatch.matching-strategy=ant-path-matcher

Related

Why does Spring Boot app start when two #Bean methods are present for restTemplate

I have this dependency:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.0.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
And I have this config:
#Configuration
public class AppConfig {
#Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
#Bean
public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) {
return restTemplateBuilder
.setConnectTimeout(ofMillis(3000))
.setReadTimeout(ofMillis(3000))
.build();
}
}
I wonder why Spring does not fail on start. It never inits first restTemplate but inits second one. I would expect Spring to fail.
This is a valid case, you are defining two bean definitions with same name of same bean, then the last bean defined will replace then first one bean defined.
If you want to an exception is thrown when two beans are defined by same name then you can configure by using setAllowBeanDefinitionOverriding(boolean allowBeanDefinitionOverriding) method from DefaultListableBeanFactory is who overrides whether it should be allowed to override bean definitions by registering a different definition with the same name.

Spring Data REST Endpoints Not Generating In Swagger UI

I've implemented a controller using #BasePathAwareController which also takes advantage of Spring Data REST (for finds to expose sort/size etc.)
along with some custom endpoints (for updates etc.). The application is working as expected and the endpoints Spring
Data REST generates are working as expected and I can see the self links appear in the responses, however, i can't see
these endpoints in Swagger UI. I can just see my custom endpoints
defined in my Controller.
According to this post I need to use Swagger 3.0.0-SNAPSHOT with #EnableSwagger2WebMvc
Here's my configurations:
My app.yml:
spring:
data:
rest:
basePath: /api/v1
My POM file:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.8.RELEASE</version>
<relativePath/>
</parent>
<properties>
<springfox.swagger.version>3.0.0-SNAPSHOT</springfox.swagger.version>
</properties>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${springfox.swagger.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${springfox.swagger.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-data-rest</artifactId>
<version>${springfox.swagger.version}</version>
</dependency>
Swagger Config File:
#Configuration
#Import(SpringDataRestConfiguration.class)
#EnableSwagger2WebMvc
public class SwaggerConfig {
#Bean
public Docket api(ServletContext servletContext) {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("my.package.name"))
.paths(PathSelectors.any())
.build().apiInfo(apiEndPointsInfo());
}
private ApiInfo apiEndPointsInfo() {
return new ApiInfoBuilder().title("My App REST API's")
.description("My App REST API's")
.version("1.0").build();
}
}
My repo:
#RepositoryRestResource(exported=true, collectionResourceRel="group", path="group")
public interface GroupRepository extends JpaRepository<Group, Long>, JpaSpecificationExecutor<Group> {
}
Why can't i see the default endpoints that Spring Data REST produces?
I found the issue to my problem. I wasn't aware that Spring Data REST doesn't expose the generated endpoints under the controller package name I had specified here:
.apis(RequestHandlerSelectors.basePackage("my.package.name"))
so when I changed the above line to:
.apis(RequestHandlerSelectors.any())
and I could see the JPA respository endpoints.

application.yaml spring.activemq.broker-url not set

I'm trying to set my spring app to listen to a JMS queue.
I try to set the broker-url in my application.yml but it always seems to default back to "localhost:61616".
The application.yml file is loaded from another application, but I don't think that matters since other properties in the file are read (the name of the queues for example)
Here is the message I get :
o.a.a.t.failover.FailoverTransport;Failed to connect to [tcp://localhost:61616] after: 40 attempt(s) continuing to retry.
What I tried
I've tried following the answer to this question : Camel ActiveMQ + Spring boot not reading spring activemq configurations
Which is my exact issue
But when I try adding the dependency and creating that class I get this error :
Parameter 0 of method createComponent in xxx.xxxxx.xxxx.configuration.ActiveMQComponentConfig required a bean of type 'javax.jms.ConnectionFactory' that could not be found.
I'm quite new to Spring boot / ActiveMQ and don't really know what to do about this.
Here's the relevant part of my pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath />
</parent>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-spring-boot-starter</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-camel</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-broker</artifactId>
</exclusion>
</exclusions>
</dependency>
And my application.yml :
spring:
aop:
proxy-target-class: true
cache:
ehcache:
config: classpath:ehcache.xml
activemq:
broker-url: tcp://foo:12345
pool:
enabled: true
max-connections: 5
Any help would be greatly appreciated, I already spent a fair amount of time on this and not making any progress
This is what I ended up doing to get it to work again. I still don't know why Spring's autoconfig stopped working but that solved it
#Configuration
public class JmsConfig {
#Value("${spring.activemq.broker-url}")
String BROKER_URL;
#Value("${spring.activemq.user}")
String BROKER_USERNAME;
#Value("${spring.activemq.password}")
String BROKER_PASSWORD;
#Bean
public ActiveMQConnectionFactory connectionFactory(){
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory();
connectionFactory.setBrokerURL(BROKER_URL);
connectionFactory.setUserName(BROKER_USERNAME);
connectionFactory.setPassword(BROKER_PASSWORD);
return connectionFactory;
}
#Bean
public JmsTemplate jmsTemplate(){
JmsTemplate template = new JmsTemplate();
template.setConnectionFactory(connectionFactory());
return template;
}
#Bean
public DefaultJmsListenerContainerFactory jmsListenerContainerFactory() {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(connectionFactory());
factory.setConcurrency("1-1");
return factory;
}
}

Error creating bean with name 'gemfireCache': FactoryBean threw exception on object creation

I am trying to create an "employee" Region and put some data into it. But, I am getting Exception below:
[warn 2018/12/27 17:15:46.518 IST tid=0x1] Exception
encountered during context initialization - cancelling refresh
attempt: org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'gemfireConfiguration': Injection of
resource dependencies failed; nested exception is
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'gemfireCache': FactoryBean threw exception on
object creation; nested exception is java.lang.NoClassDefFoundError:
it/unimi/dsi/fastutil/ints/Int2ObjectOpenHashMap
[warn 2018/12/27 17:15:46.519 IST tid=0x1] Invocation of
destroy method failed on bean with name 'gemfireCache':
org.apache.geode.cache.CacheClosedException: A cache has not yet been
created.
[error 2018/12/27 17:15:46.522 IST tid=0x1] Caught exception
while allowing TestExecutionListener
[org.springframework.test.context.web.ServletTestExecutionListener#c667f46]
to prepare test instance
[com.gemfire.demo.Gemfire1ApplicationTests#48bfb884]
Domain class
#Region("employee")
public class Employee {
#Id
public String name;
public double salary;
...
}
Repository class
#Repository
public interface EmployeeRepository extends CrudRepository<Employee, String> {
Employee findByName(String name);
}
Configuration class
#Configuration
#ComponentScan
#EnableGemfireRepositories(basePackages = "com.gemfire.demo")
public class GemfireConfiguration {
#Autowired
EmployeeRepository employeeRepository;
#Bean
Properties gemfireProperties() {
Properties gemfireProperties = new Properties();
gemfireProperties.setProperty("name", "SpringDataGemFireApplication");
gemfireProperties.setProperty("mcast-port", "0");
gemfireProperties.setProperty("log-level", "config");
return gemfireProperties;
}
#Bean
#Autowired
CacheFactoryBean gemfireCache() {
CacheFactoryBean gemfireCache = new CacheFactoryBean();
gemfireCache.setClose(true);
gemfireCache.setProperties(gemfireProperties());
return gemfireCache;
}
#Bean(name="employee")
#Autowired
LocalRegionFactoryBean<String, Employee> getEmployee(final GemFireCache cache) {
LocalRegionFactoryBean<String, Employee> employeeRegion = new LocalRegionFactoryBean<String, Employee>();
employeeRegion.setCache(cache);
employeeRegion.setClose(false);
employeeRegion.setName("employee");
employeeRegion.setPersistent(false);
employeeRegion.setDataPolicy(DataPolicy.PRELOADED);
return employeeRegion;
}
}
POM.XML
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-gemfire</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.9.0</version>
</dependency>
Adding additional tips with your above GemFire/Spring JavaConfig configuration class above.
Given you are using Spring Data Kay (implied by your use of the Spring Boot 2.0.x parent POM, i.e. org.springframework.boot:spring-boot-dependencies; see here), then you could be using Spring Data GemFire's (relatively) new and convenient Annotation-based configuration model.
By doing so, your GemfireConfiguration class above would become...
#PeerCacheApplication
#EnableGemfireRepositories(basePackages = "com.gemfire.demo")
class GemfireConfiguration {
#Bean(name="employee")
LocalRegionFactoryBean<String, Employee> getEmployee(GemFireCache cache) {
LocalRegionFactoryBean<String, Employee> employeeRegion =
new LocalRegionFactoryBean<String, Employee>();
employeeRegion.setCache(cache);
employeeRegion.setClose(false);
employeeRegion.setDataPolicy(DataPolicy.PRELOADED);
return employeeRegion;
}
}
A few things to keep in mind:
#PeerCacheApplication is meta-annotated with #Configuration so you do not need the explicit Spring #Configuration annotation on the configuration class.
#PeerCacheApplication allows you to adjust the GemFire log-level (along with other logging configuration) using the logLevel annotation attribute. Similarly, you can set the log-level using the corresponding property, spring.data.gemfire.cache.log-level in a Spring Boot application.properties file (see here). There are many other attributes and corresponding properties (e.g. name) you can use to adjust and customize other configuration.
While String-based package names are supported on #EnableGemfireRepositories and similar annotations, we generally prefer and recommend users to use the type-safe variant basePacakgeClasses. You only need to refer to a single type from each top-level package where your application Repositories are kept.
The explicit #Autowired annotation is not needed on your bean definitions. You do not need to explicit inject the EmployeeRepository in the configuration class to have it initialized; just inject it into the #Service class where it will be used.
For convenience, the name ("employee") of the Region bean definition on your LOCAL "employee" Region, will also be used as the name of the Region, so employeeRegion.setName("employee") is unnecessary.
You should not combine LocalRegionFactoryBean.setPersistent(:boolean) with LocalRegionFactoryBean.setDataPolicy(:DataPolicy) since the DataPolicy is going to take precedence.
While #ComponentScan is perfectly acceptable and even convenient in development, I generally do not prefer nor recommend users to use component-scanning. It is usually always better to be explicit.
As stated in the comments, you chould remove <relativePath/> from your parent definition in your application Maven POM file.
Final note, as of this post, Spring Boot 2.0.8.RELEASE is the latest release.
As for your classpath issues, if you are using Maven correctly, then Maven should take care of pulling in the correct transitive dependencies.
You can refer to the many examples I have in this repo for further clarification.
Hope this helps!
As mentioned in comments, the error shows some dependencies (java.lang.NoClassDefFoundError: it/unimi/dsi/fastutil/ints/Int2ObjectOpenHashMap) are missing. Please add corresponding dependencies in your pom.xml

Swagger 2 + spring integration

I'm trying to expose rest API with Spring Integration and document it with swagger. Is it even possible ? I cannot find any docs or example to make it work.
My swagger docket bean:
Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build();
And simple flow:
#Bean
public IntegrationFlow inbound() {
return IntegrationFlows.from(Http.inboundGateway("/foo")
.requestMapping(m -> m.methods(HttpMethod.GET))
.requestPayloadType(String.class))
.channel("httpRequest")
.get();
}
I use spring boot:2.0.1 and springfox-swagger2 : 2.8.0
Thank in advance,
Mateusz
Spring Integration is currently not supported by springfox, although they have provided a generalization which seems to make it possible, based upon IntegrationRequestMappingHandlerMapping:
https://github.com/springfox/springfox/issues/550
They are asking for a PR which would implement this:
https://github.com/springfox/springfox/issues/797
This is my sample code.
Maven
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.6.1</version>
</dependency>
Configuration
#Configuration
#EnableSwagger2
public class SwaggerConfig {
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2).select().apis(RequestHandlerSelectors.any())
.paths(PathSelectors.ant("/open/api/**")).build();
}
}

Resources