Error with repository injection in kafka consumer class - spring-boot

Im trying to run a simple spring boot application that just takes a message from kafka and saves in a db2 database.
The problem comes up when im trying to inject my repository in the consumer class!
#Service
#Slf4j
#AllArgsConstructor
public class KafkaConsumer {
private PortalOneRepository portalOneRepository;
private ObjectMapper objectMapper;
#KafkaListener(topics = "topicout")
public void consumeEventHubMessage(String consumerMessage) {
log.info("Received message from kafka queue: {}", consumerMessage);
//Convert string message to java object
try {
DocumentONE[] documentOne = objectMapper.readValue(consumerMessage, DocumentONE[].class);
//Salvar cada mensagem no db2
portalOneRepository.saveAll(Arrays.asList(documentOne));
} catch (JsonProcessingException e) {
log.error("Error receiving message: " + e.getMessage());
}
}
}
And this is my repository:
#Repository
public interface PortalOneRepository extends JpaRepository<DocumentONE, Long> {
}
So after run it shows the following error message:
*************************** APPLICATION FAILED TO START
Description:
Parameter 0 of constructor in
br.examplestream.eventhub.KafkaConsumer required a
bean of type
'br.examplestream.repository.PortalOneRepository'
that could not be found.
Action:
Consider defining a bean of type
'br.examplestream.repository.PortalOneRepository' in
your configuration.
I tried the config solution class but it shows a cyclic dependency injection problem:
> ***************************
APPLICATION FAILED TO START
***************************
Description:
The dependencies of some of the beans in the application context form a cycle:
kafkaConsumer defined in file [Z:\Users\romulo.domingos\IdeaProjects\portal-one-stream\target\classes\br\examplestream\eventhub\KafkaConsumer.class]
┌─────┐
| getPortalOneRepository defined in class path resource [br/examplestream/config/PortalOneConfig.class]
└─────┘
Action:
Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true.
This is the config class that i´ve tried :
#Configuration
public class PortalOneConfig {
private PortalOneRepository portalOneRepository;
#Autowired
ApplicationContext context;
#Bean
public PortalOneRepository getPortalOneRepository(){
return context.getBean(PortalOneRepository.class);
}
}
What is the correct way to inject my repository into my consumer class?

Problem solved.
The problem is caused by a property in application.yml file
autoconfigure: delete:
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
After removing the application starts to run normally again.

Related

JUnit not Initializing Services Parameters

I have a SpringBoot application, basically with a structure similar to the following:
application:
#SpringBootApplication
public class MyApplication {
#Autowired
MainService mainService;
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
#KafkaListener(topics = "myTopic")
public void listen(String message) {
this.graphicService.performWork();
}
}
first service:
#Service
public MainService {
#Autowired MyService myService;
public performWork() {
this.myService.doStuff();
}
}
second service:
#Service
public class MyService {
// server.param1 and server.param2 are defined in application.properties file
#Value("${server.param1}")
private String param1;
#Value("${server.param2}")
private String param2;
#PostConstruct
public void initService(){
}
public void doStuff() {
// do stuff assuming the parameters param1 and param 2 of this autowired service have already been initialized
}
}
I have a junit like the following:
#SpringBootTest(classes = MyApplication.class)
class MyServiceTest {
#Test
void testMyService() {
MyService myService = new MyService();
myService.doStuff();
}
}
When I execute testMyService, I get an exception thrown, essentially like this:
java.lang.IllegalStateException: Failed to load ApplicationContext
.
.
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'myApplication': Unsatisfied dependency expressed through field 'mainService';
.
.
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'mainService': Unsatisfied dependency expressed through field 'myService'
.
.
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myService': Injection of autowired dependencies failed
.
.
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'server.param1' in value "${server.param1}"
The application works fine operationally. I thought that the way I set up the junit, the springboot app would simply fire up and the parameters found in the application.properties file would simply be available to MyService service as are they when I run the application itself (not the junit).
Obviously I am doing something wrong, and the application context is not available the way I have this junit set up. I would be grateful for any ideas for getting this to work properly.
Thanks!
Wire your class under test in the Junit test like in any production code class.
The #SpringBootTest will autodetect the #SpringBootApplication, so no extra parameter is needed. Just wire the needed dependencies like you would in the application classes.
The test will use the src/test/resources/application.properties (or yml) file, if present. If not present, the src/main/resources/application.properties is used. So if you use environment variables in your production application.yml copy this file to the test resources and fill the parameters with dummy parameters for test.
#SpringBootTest
class MyServiceTest {
#Autowired MyService myService;
#Test
void testMyService() {
myService.doStuff();
}
}
If you like you can add the parameters in the test class with #TestPropertySource(properties
#SpringBootTest
#TestPropertySource(properties = {
"server.param1=srv1",
"server.param2=srv2"
})
class MyServiceTest {
...
Make sure you have spring-boot-starter-test in your dependencies.
Maven Example:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.7.5</version>
<scope>test</scope>
</dependency>

Error with using #ComponentScan on multiple packages in Spring Boot

Here's my issue--I have a service that relies on an external library. I was trying to autowire the service so I can use it but was not able to
import org.keycloak.admin.client.token.TokenService;
public class SimpleService {
#Autowired
private TokenService keycloakTokenSvc; // Could not autowire, no beans of type 'TokenService' found
public void execute() {
keyCloakTokenSvc.doSomething();
}
}
I then added this to my SpringBootApplication and got it working:
#SpringBootApplication
#ComponentScan({"org.keycloak.admin.client.token"})
public MyApp {}
Sweet -- all good now, right? Nope. It seems like this overrides some of my auto configuraitons like my security config, so I was no longer to make RESTful requests to my application while it was running. I then did this next:
#SpringBootApplication
#ComponentScan({"org.keycloak.admin.client.token", "com.project.pkg"})
public MyApp {}
Still nothing. I get the same error as before:
Field keycloakTokenSvc in com.mark43.jms.services.TokenRefreshService required a bean of type 'org.keycloak.admin.client.token.TokenService' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'org.keycloak.admin.client.token.TokenService' in your configuration.
I'm new to Spring Boot so not sure what to do here. Is there a way to use the TokenService without Autowiring? Is there a way to scan both packages?
It seems to me that you need to create a TokenService bean as follows:
#Configuration
public class TokenConfig {
#Bean
public TokenService tokenService() {
return new TokenService(); // Or whatever you need to instantiate it
}
}
This will register a TokenService object as a Spring-managed bean so that it can be autowired into SimpleService.

Optional bean created after dependent service

I'm trying to inject an optional bean into a service. The bean is successfully created but consistently after the dependent service. Any thoughts why this goes wrong?
Spring Boot 2.5.0 is used. Without using the Optional, everything works fine.
Application.java
#SpringBootApplication
#Configuration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
#Bean
public Optional<SomeClass> someClass() {
System.out.println("creating bean");
return Optional.of(new SomeClass("someName"));
}
}
SomeClass.java
#Value
public class SomeClass {
String name;
}
SomeService.java
#Service
public class SomeService {
public SomeService(Optional<SomeClass> some) {
System.out.println(
some.map(SomeClass::getName).orElse("empty")
);
}
}
Output:
empty
creating bean
When autowiring dependencies the Optional should be used at the injection point, to indicate that a bean might or might not be available. The bean cannot be available for different reasons (conditional configuration, or just a setup error leading to null for a bean).
Creating an Optional bean is something different then using Optional for the injection point.
Ideally, you would just create the bean, which would be created eagerly, if processing can fail, handle it and return null. Now when using Optional at the injection point it will see null and Optional.empty() will automatically be injected.

A bean with that name has already been defined in class path resource [path] and overriding is disabled

I have the java configuration for the Spring Data Elaticsearch(using Transport Client) and ESTemplate.
Here some except:
#Configuration
#EnableElasticsearchRepositories(basePackages = "subpackage-in-this-project")
#PropertySource("file:path-to-file")
public class ESConfig {
#Bean
ElasticsearchTemplate elasticsearchTemplate(Client client) {
return new ElasticsearchTemplate(client);
}
#Bean
Client client() {
// configuration of the ES client
}
}
And I have a config that extends the one above in the different project.
#Configuration
#ComponentScan("package-prefix-that-matches-packages-in-both-projects")
#EnableElasticsearchRepositories(basePackages = "subpackage-in-this-project")
#PropertySource("file:same-path-to-file-as-in-the-config-above")
public class ExtendedESConfig extends ESConfig {
#Value("index-name")
private String indexName;
#Bean
public String indexName() {
return indexName;
}
}
Upon executing a third Spring Boot application, which uses the dependency on the project with ExtendedESConfig, I get this and I can't quite understand why does it happen, started to happen after upgrading to 2.2.9.RELEASE from 2.0.5.RELEASE Spring Boot version.
***************************
APPLICATION FAILED TO START
***************************
Description:
The bean 'elasticsearchTemplate', defined in class path resource [my/package/ESConfig.class], could not be registered. A bean with that name has already been defined in class path resource [my/other/package/ExtendedESConfig.class] and overriding is disabled.
Action:
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
2020-08-30 16:49:46 ERROR [main] org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter:40 -
Important remark from my comment:
... sadly, I am not the one who wrote this ES config and built the whole infrastructure around it. ...
At the time of this question, I don't own ExtendedESConfig nor can change it.
Or you can add the next property to your application.properties :
spring.main.allow-bean-definition-overriding=true
The default behaviour of overriding bean has been disabled in Spring Boot 2.1. Spring Boot 2.1 Release Notes
Since you don't own / or don't want to modify both configuration classes. You can exclude parent configuration form your SpringBootApplication class using #ComponentScan
#SpringBootApplication
#ComponentScan(excludeFilters =
{#ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = ESConfig.class)})
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
I had a similar problem with my custom springSecurityFilterChain method, in my #Configuration class. The application told me it couldn't create a Bean named springSecurityFilterChain since it was defined elsewhere (in my case, in a Spring Security package, which, as is your case, I couldn't modify).
I found the solution here and it amounted to simply changing my custom method's name; I chose customFilterChain. So it went from
#Bean
public SecurityFilterChain springSecurityFilterChain(HttpSecurity http) throws Exception {
return http
.csrf().disable()
// etc
}
to:
#Bean
public SecurityFilterChain customFilterChain(HttpSecurity http) throws Exception {
return http
.csrf().disable()
// etc
}
Amazingly it worked. Like the article says, Spring builds the bean using the method's name by default. Hope it helps.
find in your modul: resources/application.properties and write:
spring.main.allow-bean-definition-overriding=true
it help you, you need to enable the beans override mechanism.

Spring factory - NoUniqueBeanDefinitionException:

I am trying to implement factory pattern to get producer from a list of available ones. While doing it i am getting the below exception. Not able to figure out the issue with the code. Can you please let me know what i am missing.
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.test.interfaces.Producer] is defined: expected single matching bean but found 2: A,B
Please find the code below
public interface Producer<T> {
public void start();
public List<T> produce() throws CEHServiceException;
public void stop();
}
#Component("A")
public class ProducerA extends Producer {
//Autowire Services & Properties
}
#Component("B")
public class ProducerB extends Producer {
//Autowire Services & Properties
}
#Configuration
public class AgentConfiguration {
#Bean
public ServiceLocatorFactoryBean createProducerFactoryBean(){
ServiceLocatorFactoryBean bean = new ServiceLocatorFactoryBean();
bean.setServiceLocatorInterface(ProducerFactory.class);
return bean;
}
}
public interface ProducerFactory {
Producer getProducer(String producerName);
}
#Component
public class AdvancedAgentProcessor {
#Autowired
private ObjectFactory<AdvancedRunnerImpl> runnerFactory;
public void init(){
AdvancedRunnerImpl runner = runnerFactory.getObject();
runner.setProducerName("A");
runner.start();
}
}
#Component
#Scope("prototype")
public class AdvancedRunnerImpl implements Runner {
#Autowired private ProducerFactory producerFactory;
private Producer producer;
private String producerName;
public void start() {
producer = producerFactory.getProducer(this.producerName);
}
}
Full stack tracke
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.test.etl.interfaces.Producer] is defined: expected single matching bean but found 2: A,B
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:365)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:331)
at org.springframework.beans.factory.config.ServiceLocatorFactoryBean$ServiceLocatorInvocationHandler.invokeServiceLocatorMethod(ServiceLocatorFactoryBean.java:377)
at org.springframework.beans.factory.config.ServiceLocatorFactoryBean$ServiceLocatorInvocationHandler.invoke(ServiceLocatorFactoryBean.java:363)
at com.sun.proxy.$Proxy34.getProducer(Unknown Source)
at com.test.runner.AdvancedRunnerImpl.start(AdvancedRunnerImpl.java:54)
at com.test.app.AdvancedAgentProcessor.init(AdvancedAgentProcessor.java:48)
at com.test.app.DataAgentApplication.main(DataAgentApplication.java:25)
Spring does not know which component to autowire. It seems that the problem is in the ProducerFactoryImplementation but we cannot see it.
There are three possible solutions:
Use Qualifiers so you can tell Spring which specific implementation you want.There is an example in StackOverflow
here
Use the Primary annotation (See more here3). That means that in case of ambiguity Spring will give priority to the #Primary annotated component
Autowire a list of beans. Something like:
#Autowired private List<Producer> myAvalilableProducers;
public Producer getByName(name){
for( Producer producer: myAvalilableProducers){
if(producer.getName().equals(name)){ return producer; }
}
throw new RuntimeException("No producer with name " + name " found");
}
This third option more useful when you do not know the specific instance at compile time or if you really want to inject a list of components.
You have two beans that extend Producer. Somewhere you are trying to autowire a Producer. Spring does not know which Producer to use.
This happens when the dynamic proxy is not able to pick the correct Bean. Please check whether this.producerName is null or empty.

Resources