Spring-boot bean name conflict between two dependent retrofit clients - spring-boot

My maven springboot app has a dependency on two Retrofit clients whose code I have no control over. Both of these clients have a #Configuration class called ClientConfig. When I try to run my application, I get this error:
ConflictingBeanDefinitionException: Annotation-specified bean name 'clientConfig' for bean class [a.b.c.client.config.ClientConfig] conflicts with existing, non-compatible bean definition of same name and class [a.b.c.config.ClientConfig]
How can I fix this? Is there any way I can override the bean names for these classes? This is my maven configuration:
<dependency>
<groupId>a.b</groupId>
<artifactId>lib1-client</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>a.b</groupId>
<artifactId>lib2-client</artifactId>
<version>1.2.55</version>
</dependency>

Only thing I could think of is to exclude them from component scan:
#SpringBootApplication
#ComponentScan(excludeFilters = {"a.b.lib1-client",...})

Related

Cannot construct instance of `reactor.core.publisher.Mono` Spring Cloud OpenFeign and Spring boot 2

Goal: migration from Spring Boot 1.x (webMvc) to version 2 (webFlux) and Spring Cloud Edgware SR2 to FinchleyM8 (awaiting release version).
Problem: Feign -> OpenFeign. OpenFeign under the hood uses RxJava but WebFlux - Reactor3. At the current moment when I using Mono as returned type, I have got an error:
Caused by: org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class reactor.core.publisher.Mono]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of reactor.core.publisher.Mono (no Creators, like default construct, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
Code example:
#FeignClient(name = "thirdpartyresource", url = "${third.party.resource.url}")
public interface ThirdPartyResource {
#PostMapping(value = "/validate", consumes = APPLICATION_FORM_URLENCODED_VALUE)
Mono<ValidationResultDto> validate(MultiValueMap multiValueMap); // WORKS BAD
// Single<ValidationResultDto> validate(MultiValueMap multiValueMap); WORKS WELL
}
Question:
Do I need to create my own converter Single to Mono or it's some problems of spring-cloud-starter-openfeign and all should work OOTB?
The reactor.core.publisher.Mono belongs to the spring-boot-starter-webflux jar.
Get the latest version of it from the mvn repository.
Then add it to your pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<version>2.5.3</version>
</dependency>
Also do remove spring-boot-starter-web from your pom.xml, just in case if you have it.
<!--<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>-->
This fixed the issue!
You can use those methods to adapt:
For Single<T> rxJavaSingle
Mono.from(RxReactiveStreams.toPublisher(rxJavaSingle))
For Completable rxJavaCompletable
Mono.from(RxReactiveStreams.toPublisher(rxJavaCompletable))

Using a RestTemplate in a non Web app in SpringBoot app

I have a Spring Boot app that is not a web app, that has this piece of code
ResponseEntity<GeolocationAddress> response = new RestTemplate().getForEntity(urlStringConnection,
GeolocationAddress.class);
But then I have this error:
The import org.springframework.web cannot be
resolved
so I added this dependency
<!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>3.0.2.RELEASE</version>
</dependency>
But then when I start the app I got this error:
Could not evaluate condition on org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration due to org/springframework/web/context/support/StandardServletEnvironment not found. Make sure your own configuration does not rely on that class. This can also happen if you are #ComponentScanning a springframework package (e.g. if you put a #ComponentScan in the default package by mistake)
I may be a little late, but I had similar issues. By default Spring Boot tries to deduce the type of the application context to use by examining the class path. If it finds either javax.servlet.Servlet or org.springframework.web.context.ConfigurableWebApplicationContext, it instantiates a WebApplicationContext.
To avoid the error you got, I had to do the following in the main method of the app:
#SpringBootApplication
public class App {
public static void main(String[] args) {
new SpringApplicationBuilder(App.class)
.contextClass(AnnotationConfigApplicationContext.class).run(args);
}
}
I also excluded any unwanted AutoConfigure classes in the application.properties :
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration,org.springframework.boot.actuate.autoconfigure.TraceWebFilterAutoConfiguration,org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration,org.springframework.boot.autoconfigure.web.HttpEncodingAutoConfiguration,org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration,org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration,org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration,org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration,org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration,org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration,org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration,org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,org.springframework.boot.autoconfigure.mobile.DeviceDelegatingViewResolverAutoConfiguration,org.springframework.boot.autoconfigure.mobile.SitePreferenceAutoConfiguration,org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,org.springframework.boot.autoconfigure.social.SocialWebAutoConfiguration,org.springframework.boot.autoconfigure.social.FacebookAutoConfiguration,org.springframework.boot.autoconfigure.social.LinkedInAutoConfiguration,org.springframework.boot.autoconfigure.social.TwitterAutoConfiguration,org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,org.springframework.boot.actuate.autoconfigure.CrshAutoConfiguration

How SpringBoot #ConditionalOnClass work?

For example, HttpEncodingAutoConfiguration is annotated with #ConditionalOnClass(CharacterEncodingFilter.class).
What I know about #ConditionalOnClass is to promise the CharacterEncodingFilter in classpath, but if the class not in classpath how could it get through at compile or class loading time.
Thanks a lot.
The javadoc on ConditionalOnClass.value gives the answer:
The classes that must be present. Since this annotation is parsed by
loading class bytecode, it is safe to specify classes here that may
ultimately not be on the classpath, only if this annotation is
directly on the affected component and not if this annotation is used
as a composed, meta-annotation. In order to use this annotation as a
meta-annotation, only use the name attribute.
Also at compile time you do have to have such classes on the classpath to use the value attribute of ConditionalOnClass.
Spring-boot uses optional dependencies to achieve this. In maven this looks like this:
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-jdbc</artifactId>
<version>4.0.4</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
In gradle you usually use compileOnly to achieve this.

JMX on Spring Boot project

I have annotated a class as follows:
#ManagedResource(objectName="com.myproject.bean.jmx:name=JMXSolrIndexerBean",
description="Index Solr Operations")
public class JMXSolrIndexerBean {
....
}
My pom has the following dependencies
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-jmx</artifactId>
<version>4.1.6.RELEASE</version>
</dependency>
I can't find my MBean in the JConsole... are there any configuration steps I am missing?
Two things:
You don't need the spring-integrtation-jmx dependency to make that work, the actuator starter is enough
Your class needs to be a spring bean if you want Spring Boot to auto-detect JMX annotation on them. So adding #Component on your JMXSolrIndexerBean is all that's needed as long as it is located in a package that is processed by component scan
In other words, that class of yours is just a pojo that spring know nothings about. #ManagedResource is not a stereotype that turns that class in a Spring Bean.

SpatialRepository not autowiring

Does anyone know how to get SpatialRepository #Autowiring in a spring boot app? I have put the additional dependency in my classpath
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-spatial</artifactId>
<version>0.9</version>
</dependency>
with the following configuration options
#SuppressWarnings("unused")
#Configuration
#EnableAutoConfiguration
#EnableTransactionManagement
#EnableNeo4jRepositories(basePackages = {"com.eanda.prototype", "test.com.eanda.prototype"})
#ComponentScan({"com.erranda.prototype", "org.springframework.data.neo4j"})
I have tried it all but no avail. My domain class is this:
public interface ErrandRepository extends GraphRepository<Errand>, SpatialRepository<Errand> {}
I get the following exception when running a query on the spatial repo
java.lang.IllegalArgumentException: No index provider 'spatial' found. Maybe the intended provider (or one more of its dependencies) aren't on the classpath or it failed to load.
Are you introducing the spatial engine to an existing database?
Have you installed the spatial extension in the plugin directory?
Lorenzo

Resources