APPLICATION FAILED TO START due to same bean - java

I have a Spring Webflux application where I am trying to load a dependency from an old module (old module is on Spring WebMVC framework).
When the application is launched, this error is thrown -
***************************
APPLICATION FAILED TO START
***************************
Description:
The bean 'requestMappingHandlerAdapter', defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class], could not be registered. A bean with that name has already been defined in class path resource [org/springframework/web/reactive/config/DelegatingWebFluxConfiguration.class] and overriding is disabled.
Action:
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
I want all the beans from webflux package to be initiated, so I can't set spring.main.allow-bean-definition-overriding=true.
Also tried excluding all classes within org.springframework.boot at the time of component scan - #ComponentScan(excludeFilters = #Filter(type = FilterType.REGEX, pattern = "org.springframework.boot*").
Also tried excluding all spring packages in pom.xml of my webflux project like this -
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
Since I cannot modify the older dependency project to webflux, are there any options I could use the make the code work ?

In your springboot startup class , the #EnableAutoConfiguration annotation will auto configure the mvc part (WebMvcAutoConfiguration will fail due to same bean name in DelegatingWebFluxConfiguration)
So try ti exclude this from auto config and try as below
#SpringBootApplication
#EnableAutoConfiguration(exclude = {WebMvcAutoConfiguration.class })
public static void main(String[] args) {
...
SpringApplication.run(MyApp.class, args);
}

If I understand correctly you have some Web-related dependencies on the classpath but aren't building a web application, you can explicitly tell SpringApplication that you don't want a web application:
app.setWebEnvironment(false);
This is the way to disabling Web-related auto-configuration as it means you don't need to know what those auto-configuration classes are and lets Spring Boot take care of it for you.

As mentioned in your problem description, Using dependencies of Spring MVC in Spring Webflux can cause this issue. I have solved this issue by excluding the group "org.springframework.boot" while including the old dependency.
In gradle.build i have did something like below:
implementation("dependency-using-spring-mvc") {
exclude(group= "org.springframework.boot")
}

Related

Spring boot custom starter - Cannot import custom starter class

I am developing a spring boot custom starter which pom contains some dependencies (other starters, libraries) and this starter does some config about jwt filtering to allow the filter at security level. The issue is when I add my custom starter as a pom dependency in another project (starter-consumer), it seems it detects the class I want to import but IntelliJ does nothing.
Maybe I didn't packaged the starter correctly, or at least the classes that I coded inside. The other dependencies that the starter contains in the pom are successfully added as a dependencies of the starter-consumer. For example, I use some jwt utils which dependency is in the parent starter. So that thing works ok.
import io.jsonwebtoken.impl.DefaultClaims;
The problem is when I try to import a custom class which I coded in the starter. This is my package structure:
I want to use the JwtConfig class in my starter-consumer. It appears but I can't import. It does nothing.
And then If I manually check package availability I see this:
Pepito is missing :( and theinit is the package name of the starter-consumer. The jar is installed in the local m2 so I get the dependency like this:
<dependency>
<groupId>com.pepito</groupId>
<artifactId>starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
Any insights on this?
Edit 1:
I removed the boot maven plugin as a you said, it seems now it is not packaged as boot app and my starter-consumer can import the clases I coded . One additional thing, what happens with beans? Does the autoconfigure starts the bean by itself or the starter-consumer needs to declare it?
Edit 2:
So as part of the solution of this post, I am trying to inject a bean from the starter into the starter-consumer.
Apart from another beans, here we have the jwtTokenAuthenticationFilter which I want to inject into my starter-consumer security config.
#Configuration
#ConditionalOnProperty(name = "security.jwt-enabled", havingValue = "true")
public class JwtAutoConfiguration extends AbstractHttpConfigurer<JwtAutoConfiguration, HttpSecurity> {
#Bean
public JwtConfig jwtConfig() {
return new JwtConfig();
}
#Bean
public FilterRegistrationBean registration(#Qualifier("jwtFilter") JwtTokenAuthenticationFilter filter) {
FilterRegistrationBean registration = new FilterRegistrationBean(filter);
registration.setEnabled(false);
return registration;
}
#Bean
public JwtTokenAuthenticationFilter jwtFilter() {
return new JwtTokenAuthenticationFilter(jwtConfig());
}
#Override
public void init(HttpSecurity http) throws Exception {
// initialization code
}
}
This is my spring.factories
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.pepito.starter.configuration.security.jwt.JwtAutoConfiguration
And in the starter-consumer I have the following
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private JwtTokenAuthenticationFilter jwtFilter;
And here is where I see the error in intellij that can't autowire that bean because it does not exist. I suppose is because of something about scan but in my starter-consumer I have #SpringBootApplication which is suppose it contains componentscan annotation.
I believe A couple of issues that I see here and some clarifications will help you to find an answer:
Module with starter is a regular jar. The only thing that differs is that it has META-INF/spring.factories which I see exist.
Having said that - I see in the Pepito starter module class SpringBootMicroserviceStarterApplication. This is wrong. If the starter is a spring boot application, then the chances are that you're using spring boot maven plugin to prepare it as an application.
But the jar created by this plugin is not really a Jar, more specifically it stores other jars in BOOT-INF lib and in general can't be considered a Jar build-tool-wise and IDE-wise.
To put it simple you cannot declare a dependency on something that gets packaged as a spring boot application!
Update 1
To address your OP's question in comments:
The starter is not a spring boot application. It should not have a method annotated with #SpringBootApplication, it should not be packaged as spring boot application and so forth.
The best way to view the starter is as an self-contained "feature" or "facility" (trying to find the most appropriate word in English) that can be used by Spring boot applications by importing the starter module.
In terms of testing, #SpringBootTest should not be used in starter's module because it mimics the startup of spring boot application which obviously does not exist here.
Its possible to test it with Unit Test or with Spring Testing Framework:
#RunWith(SpringRunner.class)
#ContextConfiguration(<here comes the class of AutoConfiguration in starter)
One last thing to clarify here:
In spring Factories you can specify the autoconfiguration that in turn declares a series of beans required by the starter.
These beans are resolved by spring boot application just like other beans, the difference is that the Configuration is identified out of spring.factories file and not by package structure or explicit configuration.
So to answer your question:
Would you know if I can declare a bean in the starter and then autowire it in the consumer?
Yes, as long as the starter gets loaded by spring boot application, you can autowire (or inject in any other way) beans from starter into the beans of the spring boot application itself.

Stop Spring Boot from loading #Configuration file from dependency module (jar)

I'm implementing a Spring boot application with a dependency to another spring module (jar) containing an #Configuration (AmcConfiguration.class) file I do NOT want loaded into the context. I've tried many variations of exclude examples
a few of which are as follows:
//exclude problem configuration class
#SpringBootApplication(exclude={AmcConfiguration.class})
and...
//exclude problem bean from within problem configuration class
#EnableAutoConfiguration
#Configuration
#ComponentScan(excludeFilters = #Filter(type = FilterType.ASSIGNABLE_TYPE, classes = IAmsClient.class))
and...
//exclude problem configuration class package
#EnableAutoConfiguration
#Configuration
#ComponentScan(excludeFilters = #Filter(type = FilterType.REGEX, pattern="com.prot.mtrx.amc.config.*"))
Also, I've made sure there are no package naming collisions.
spring boot root = "com.prot.am.*
dependency = "com.prot.mtrx.amc.*"
I've been searching examples for a few days now and am running out of options. I went down the auto-configuration path but that seems much too complicated a solution to tell spring boot to not run one simple configuration class.
From my logs, it looks like it might be embedded tomcat:
DEBUG o.a.tomcat.util.digester.Digester - New match='mbeans-descriptors/mbean/operation/parameter'
DEBUG o.s.c.a.ClassPathBeanDefinitionScanner - Identified candidate component class: file [C:\TestSuite\workspace-dev\MAMClient\target\classes\com\prot\mtrx\amc\config\AmcConfiguration.class]
What am I missing?

Sharing common Spring Boot configuration between projects

The app I'm working on has a maven dependency on a common module containing a dozen spring-boot #Configuration beans specifying datasources, LDAP contexts, security modules, property sources etc which I often want to suppress.
My app and this common module are part of a spring-boot maven multi-module project. My sub-project needs about 6 of the 12 configuration beans.
I have got quite a long way using #Import and #SpringBootApplication#exclude and #ImportAutoConfiguration:
#Import({PropertySpringConfig.class,
LdapConfig.class,
SecurityConfig.class,
JpaDataConfiguration.class,
RestConfiguration.class,
WebConfigurer.class})
#SpringBootApplication(exclude = {
RefDataSourceConfig.class,
ElasticsearchAutoConfiguration.class,
CamelAutoConfiguration.class,
ElasticsearchDataAutoConfiguration.class})
public class MyRestApplication {
public static void main(String[] args) {
SpringApplication.run(MyRestApplication.class, args);
}
}
and a test configuration bean that all my JPA tests import (I have others, e.g. for REST tests):
#Configuration
#OverrideAutoConfiguration(enabled = false)
#ImportAutoConfiguration(value = {
CacheAutoConfiguration.class,
JpaRepositoriesAutoConfiguration.class,
DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
HibernateJpaAutoConfiguration.class,
TransactionAutoConfiguration.class,
TestDatabaseAutoConfiguration.class,
TestEntityManagerAutoConfiguration.class })
public class TestJpaConfiguration {}
The whole codebase was set up with Spring 1.3.x. I upgraded it to Spring 1.4.x.
Take for example one of the datasources, a configuration bean in the shared dependency - I don't need it, and it prevents Spring Boot autoconfiguration because it's marked with #Primary (possibly unnecessarily).
I don't want Spring Boot in my sub-project to see it when it runs autoconfiguration, but how do I share it from the common module with the other Spring Boot sub-projects that do need it?
I could split it out into its own maven project and only have it as a dependency in the sub-projects that needed it. But there are 11 other similar configuration beans! It could be seen as overkill although I like this approach - but I have 5 colleauges to convince.
I can just struggle on using #SpringBootApplication#excludes for the code and #ImportAutoConfiguration for the tests - but then I miss out on the Spring Boot benefits like #DataJpaTest or #JsonTest test slices
I could repeat the configuration beans in each project where they are needed - a bit of cut & paste - but I like this option the least.
Is there a 4?

Spring boot RESTful service as WAR not JAR

I am in the process of creating a Java REST application, using Spring-boot. I have successfully loaded the example here and I have tried to convert the JAR file to the WAR file as presented on the Spring-boot site. I've modified my pom.xml file, adding:
<!-- other pom.xml conf -->
<packaging>war</packaging>
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
Then I've modified the Application.java class to initialize the servlet (this is for what Spring-boot uses to replace the web.xml file):
public class Application extends SpringBootServletInitializer {
// public static void main(String[] args) {
// new SpringApplicationBuilder(Application.class).run(args);
// }
#Bean
public ServletRegistrationBean jerseyServlet() {
ServletRegistrationBean registration = new ServletRegistrationBean(new ServletContainer(), "/*");
registration.addInitParameter(ServletProperties.JAXRS_APPLICATION_CLASS, JerseyInitialization.class.getName());
return registration;
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
}
I got my .WAR file generated, but when I deploy it on Tomcat the services are returning 404. The Tomcat logs aren't showing any errors either.
So I am not sure what it might be the problem. If you have any idea please, do share. Thanks!
Update:
Initially it wasn't working because beside the SpringBootApplication annotation to the Application class I was having other annotations too. Took those out and now Tomcat logs are showing this error.
SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
java.lang.IllegalStateException: Cannot initialize context because there is already a root application context present - check whether you have multiple ContextLoader* definitions in your web.xml!
I am not sure what other ContextLoader is there.
UpdateToUpdate:
Okay, after updating the jars to the latest version, using the annotation #SpringBootApplication for Application.java class, the application starts but when I am calling one of the services I receive:
java.lang.ClassNotFoundException: org.glassfish.jersey.process.internal.RequestExecutorFactory
A google search said that I should add the jersey-common and jersey-core jars, I did, but it didn't fix it. It looks like the RequestExecutorFactory.class is not packaged in the jersey-common-2.19.jar for some reason.
why do you have so many annotation in your Application class here ?
#SpringBootApplication should be sufficient to enable automatic configuration.
Try removing the others.
And put back the main method.
I think you mixed two configuration tw create a war : pre 3.0 and post 3.0 servlet container (as per the Spring Boot documentation)
EDIT :
I've found this question related to your problem.
Jersey is loading a Spring ApplicationContext. See this line of log : Spring WebApplicationInitializers detected on classpath: [com.jersey.Application#148ac084, org.glassfish.jersey.server.spring.SpringWebApplicationInitializer#7807c6d3]
Would it be possible for you to update your Spring Boot version ?
At least 1.20 so you will be able to use the spring-boot-starter-jersey. It will be a lot more easier to integrate Spring and Jersey.
You can find an example here (Spring Boot official examples).
Or you have to exclude the org.glassfish.jersey.server.spring.SpringWebApplicationInitializer of initializers

How can I #Autowire a spring bean that was created from an external jar?

I have a module/jar that I've created and am using as a util library. I created a service in there like so:
#Service
public class PermissionsService { ... }
... where this resides in a package here: com.inin.architect.permissions and in my main application, I'm referencing/loading this jar (i.e. set as a dependency in the maven POM.xml file for the app) like so:
<dependency>
<groupId>com.inin.architect</groupId>
<artifactId>permissions</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
and within the application I want to use that service like:
#Autowired
PermissionsService permissions
In the application's spring setup, I've got this:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = { "com.inin.generator", "com.inin.architect.permissions" })
public class WebConfig extends WebMvcConfigurerAdapter implements ServletContextAware { }
However when I run my application under tomcat, it complains that there isn't a bean for the PermissionsService: "org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type ..."
So, how can I bring over the bean from the lib into my application? Surely there's a way. Do you have to set the library up as a full blown spring MVC application so that this can work? i.e. do you have to have #Configuration and #ComponentScan setup in the lib as well?
You have to scan at least the package containing the class you want to inject. For example, with Spring 4 annotation:
#Configuration
#ComponentScan("com.package.where.my.class.is")
class Config {
...
}
It is the same principle for XML configuration.
Just a note on this, but you could decouple your dependency from spring. In your #Configuration class create
#Bean public PermissionsService permissionsService(){
return new PermissionsService()
}
This will also allow it to be injected. Not that you have to remove your spring annotation, just an option making it potentially usable outside of spring.
Ok - i had exactly the same problem - i wanted to autowire a mongo db repository interface from an external jar.
I could autowire every bean from that jar with using
#SpringBootApplication(scanBasePackages = {"com.myrootpackage"})
However - autowiring the interface always failed with "Could not find blablabla..."
But the interface was in the same package as the beans i could import.
It turned out that searching for the mongo db interfaces is NOT taking the scanBasePackages from the #SpringBootApplication into consideration!
It has to be explicitly configured via
#EnableMongoRepositories(basePackages = {"com.myrootpackage"})
Or you could move the main class "up" so the default searching works also for the mongo interfaces. So i understood the problem and found a solution. But i am still a bit unhappy because i need to configure the same lookup path twice. I find it stupid honestly.
I faced the same issue while scanning other classes from other project dependencies, The scanning solution depends on the type of classes you need to scan as follows:
if they are normal #Component, #Service annotations use
#ComponentScan({"com.mypackge1","com.mypackage2"})
If the type of classes are domain objects based on entities use
#EntityScan("com.mypackge1.domain")
If JPA repository classes
#EnableJpaRepositories(basePackages = {"com.mypackage.repository"})
If Redis repository classes use
#EnableRedisRepositories(basePackages = {"com.mypackage.repository"})
Same for Mongo, etc.
You can import application-context.xml for com.inin.architect.permissions in the following manner inside your main application.
<import resource="classpath:/permissionApplicationContext.xml" />
This will enable you to autowire beans from com.inin.architect.permissions that you have defined.

Categories

Resources