How to keep duplicate spring bean in container. [ConflictingBeanDefinitionException] - java

I am working on an application which uses some third java libraries which are build on top of core spring framework.
Now when my application uses these libraries I am getting ConflictingBeanDefinitionException because two libraries have the same bean name.
Now as these libraries are external I cannot change the bean name. Is there a way by which in my application I can use both the beans in same container?
#Component
class ApplicationLogic {
#Autowire FetcherAndResolver fetchFromLibraryA;
#Autowire FetcherAndResolver fetchFromLibraryB; //Because both bean names are same here comes the exception.
}

I think this would require a bit of a hack.
First of all, structure your packages in a way so that external beans are not added automatically.
So, if external class is located in package a.b. Then you have to move your own classes in either a.c or a.b.c. THis will ensure that you are in control of how beans are initialized.
Once this is done, you can add a #Configuration class where you can create Beans of both type:
#Configuration
public class ExternalBeanConfiguration {
#Bean("internal-resolver" )
public FetcherAndResolver internalResolver() {
return new FetcherAndResolver();
}
#Bean("external-resolver" )
public a.b.c.FetcherAndResolver externalResolver() {
return new a.b.c.FetcherAndResolver();
}
}
I am assuming that FetcherAndResolver is a class rather than an interface. If it is an interface, it is easier to do it as you won't have to use fully-qualified name for classes.
Then you can simply autowire with qualifiers.
#Component
public class SomeComponent {
#Qualifier( "internal-resolver" )
FetcherAndResolver internalResolver;
#Qualifier( "external-resolver" )
FetcherAndResolver externalResolver;
}

First component from third java libraries:
package com.example.component1;
import org.springframework.stereotype.Component;
#Component
public class MyComponent {
public String makeSomeWork() {
return "Component 1";
}
}
Second component from third java libraries:
package com.example.component2;
import org.springframework.stereotype.Component;
#Component
public class MyComponent {
public String makeSomeWork() {
return "Component 2";
}
}
Controller:
package com.example.controller;
import com.example.component1.MyComponent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class MyController {
#Autowired
private MyComponent myComponent;
#Autowired
private com.example.component2.MyComponent myComponent2;
#RequestMapping("/components")
public String getComponents() {
return myComponent.makeSomeWork() + "_" + myComponent2.makeSomeWork();
}
}

Related

spring boot constructor parameter could not be found

I am working on spring boot app with tutorial. I did everything like guy from tutorial but still have problem with some constructor:(
The error is:
Parameter 0 of constructor in com.wewtorek.shop.controllers.AdminController required a bean of type 'com.wewtorek.shop.models.data.PageRepository' that could not be found.
Code is:
package com.wewtorek.shop.controllers;
import com.wewtorek.shop.models.data.Page;
import com.wewtorek.shop.models.data.PageRepository;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.List;
#Controller
#RequestMapping("/admin")
public class AdminController {
private PageRepository pageRepository;
public AdminController(PageRepository pageRepository) {
this.pageRepository = pageRepository;
}
#GetMapping
public String admin(Model model) {
List<Page> pages = pageRepository.findAll();
model.addAttribute("pages", pages);
return "admin";
}
}
PageRepository:
package com.wewtorek.shop.models.data;
import org.springframework.data.jpa.repository.JpaRepository;
public interface PageRepository extends JpaRepository<Page, Integer> {
}
Application:
package com.wewtorek.shop;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class ShopApplication {
public static void main(String[] args) {
SpringApplication.run(ShopApplication.class, args);
}
}
First :
#Repository is missing
#Repository
public interface PageRepository extends JpaRepository<Page, Integer> {
}
Doc : https://www.baeldung.com/spring-data-repositories
You dont have to create an constructor in controller :
It should be something like this :
public class AdminController{
#Autowired
private PageRepository pageRepository;
--- Code ---
}
#Autowired instanciate a service, you dont have to build it
BUT you have to put #Repository or #Service to use #Autowired
I take this example from my school project :
Controller
In my LoanService i call another server but u can replace it by u'r repository
Service
And last tips i promise :D, a complete NoSQL school project i did
https://github.com/juju630/ClientServeurNoSQL
( sry not native )
Without looking at your project, this is going to be hard to give a definitive solution.
What is happening is when spring tries to create the bean AdminController it can not find a unique bean as the dependency PageRepository.
A few things to look at to try to solve this
Is the bean JpaRepository<Page, Integer> annotated correctly for spring to pick it up and create an instance?
Is the bean JpaRepository<Page, Integer> being scanned by spring?
What is your package structure? this can be very important for the default scanning of spring beans.
To investigate you could add a default constructor to allow it to ignore the dependency, then debug out all beans on startup of your app using the answers
Here
I hope this helps.

Spring Boot Application can not inject Bean from another module

I have the following 3 modules in my spring-boot application:
web (Entry point / Main Application class annotated with #SpringBootApplication
persistence
service
I'm now trying to inject a service in the web module which comes from the service. In the service I'm injecting the repository which comes from the persistence module. When I start the application the following error shows up:
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in com.project.service.images.ImageService required a bean of type 'com.project.persistence.repositories.ImageRepository' that could not be found.
Action:
Consider defining a bean of type 'com.project.persistence.repositories.ImageRepository' in your configuration.
ImageService class:
package com.project.service.images;
import com.project.common.entities.Image;
import com.project.persistence.repositories.ImageRepository;
import com.project.service.AbstractService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.persistence.EntityNotFoundException;
import java.util.Date;
import java.util.List;
#Component
public class ImageService extends AbstractService {
private final ImageRepository imageRepository;
#Autowired
public ImageService(ImageRepository imageRepository) {
this.imageRepository = imageRepository;
}
public Image getImage(Long id) {
return imageRepository.findById(id).orElseThrow(EntityNotFoundException::new);
}
public List<Image> getAll() {
return imageRepository.findAll();
}
public List<Image> getAll(Date from) {
return imageRepository.findByDateRange(from, null);
}
public List<Image> getAll(Date from, Date to) {
return imageRepository.findByDateRange(from, to);
}
public List<Image> getAllForDay(Date day) {
return imageRepository.findAll();
}
}
ImageRepository class:
package com.project.persistence.repositories;
import com.project.common.entities.Image;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.util.Date;
import java.util.List;
#Repository
public interface ImageRepository extends JpaRepository<Image, Long> {
#Query("SELECT i FROM Image i WHERE i.created > :from AND i.created < :to")
public List<Image> findByDateRange(#Param("from") Date from, #Param("to") Date to);
}
And that's how I inject the service into my class in the web module:
#Autowired
private ImageService imageService;
So on I was searching throught the internet and saw some people with similar problems. Then I got the tip that I should add the scanBasePackages to the SpringBootApplication annotation at my application class. So I did this:
package com.project.web;
#SpringBootApplication(scanBasePackages = "com.project.service")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
But it's still not working. If I add the specific package for scanning to the annotation com.project.service.images the injection of the ImageService works but then it can't find the ImageRepository in it.
What am I doing wrong?
I know that so many modules doesn't make sense for such a small application but I have to because it's for my apprenticeship and we need to make multiple modules.
What normally should do is to have this structure in your app
app
SpringBootApp.java
app.repositories
Repository.java
app.services
Service.java
If you are not following that package structure, then you need to have
#EnableJpaRepositories
And watch out for your entities which may have the same issue, in that case take a look at:
#EntityScan
Just try to change scanBasePackages to "com.project". Repository is in a different package.
eg:
#SpringBootApplication(scanBasePackages = "com.project")
Spring is not able to scan your repository class as it resides in different package.
As per your response in comments, your Application class in under
com.project.web
, so by default Spring will scan all classes under this packages and subpackages. So you need to put all your spring components under the same package/sub package where your application resides.
Create a config class , and define all you beans in that one location , in this case you need the bean for ImageRepository, Something like...
#Configuration
#ComponentScan
public class Config {
#Bean
public ImageRepository getImageRepository() {
// return the image repository object
}
}

Field in required a bean of type that could not be found consider defining a bean of type in your configuration

I'm getting the following error when trying to run my app:
Field edao in com.alon.service.EmployeeServiceImpl required a bean of
type 'com.alon.repository.EmployeeRepository' 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
'com.alon.repository.EmployeeRepository' in your configuration.
Project structure:
EmployeeRepository:
package com.alon.repository;
import com.alon.model.Employee;
import org.springframework.stereotype.Repository;
import java.util.List;
#Repository
public interface EmployeeRepository {
List<Employee> findByDesignation(String designation);
void saveAll(List<Employee> employees);
Iterable<Employee> findAll();
}
EmployeeServiceImpl:
package com.alon.service;
import com.alon.model.Employee;
import com.alon.repository.EmployeeRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
#Service
public class EmployeeServiceImpl implements EmployeeService {
#Autowired
private EmployeeRepository edao;
#Override
public void saveEmployee(List<Employee> employees) {
edao.saveAll(employees);
}
#Override
public Iterable<Employee> findAllEmployees() {
return edao.findAll();
}
#Override
public List<Employee> findByDesignation(String designation) {
return edao.findByDesignation(designation);
}
}
MyApplication:
package com.alon;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class MyApplicataion {
public static void main(String[] args) {
SpringApplication.run(MyApplicataion.class, args);
}
}
As you have added spring-boot tag I guess you are using sprig data jpa. Your repository interfaces should extend org.springframework.data.repository.Repository (a marker interface) or one of its sub interfaces (usually org.springframework.data.repository.CrudRepository) for instructing spring to provide a runtime implementation of your repository, if any of those interfaces are not extened you'll get
bean of type 'com.alon.repository.EmployeeRepository' that could not
be found.
I assume you try to use spring data JPA. What you can check / debug is:
Is JpaRepositoriesAutoConfiguration executed? You can see this in the start up log in the debug log level
Does something change if you addionally add #EnableJpaRepositories with the corresponding basepackages.
Add #ComponentScan with the corresponding packages, normally #SpringBootApplication should do it, but just in case.
you can also check the autconfig documentation: https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-auto-configuration.html
EDIT: see comment from #ali4j: I did not see that it is the generic spring Repository interface and not the spring data interface
regards,WiPu

get a null object after used #autowired to DI

I have a utils class that use #Autowired to inject a repository using spring-boot-starter-data-jpa. But when I used this repository to access the database, it said the repository is null. I used the same method in my controller and it works well. And here is my Utils.class
package com.example.controller;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;
import com.example.dao.RuleRepository;
import com.example.model.Project;
import com.example.model.Rule;
public class Judge {
#Autowired
RuleRepository ruleRepository;
public boolean ageJudge(Project project) {
try {
if (ruleRepository == null)
{
System.out.println("yes");
}else {
System.out.println("false");
}
return false;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
}
}
Here is my Application.java
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
#SpringBootApplication
#ComponentScan(basePackages = {"com.example"})
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
This is the RuleRepository.java
package com.example.dao;
import org.springframework.data.jpa.repository.JpaRepository;
import com.example.model.Project;
import com.example.model.Rule;
public interface RuleRepository extends JpaRepository<Rule, Integer>{
Rule findById(Integer id);
Rule findByRuleName(String ruleName);
}
It is the directory.
The RuleRepository works well in controller. So, what is the problem?
Your util class Judge is a plain POJO not a Spring bean and you can only inject Spring beans inside another Spring beans not Plain POJOs.
If you wish to use your ruleRepository bean inside Judge then make it a Spring component using #Component annotation:
#Component
public class Judge {
#Autowired
RuleRepository ruleRepository;
..............................
}
User #Service annotation of Judge class is acting as business logic implementation class.
Your Judge should be annotated #Component
#Component
public class Judge{
// ...
}
so that Spring will instantiate a Judge bean and it will be available for injection. You can then use that judge bean in any managed bean (e.g: a controller)
// SomeController
#Autowired
Judge judge;
But if you instantiate judge object your self, like this:
Judge judge2 = new Judge();
your repository will be null, be cause Spring have nothing to do with judge2 object, it is not managed by Spring.
You need to make your Judge class at least a #Component of your project, which will make your class managed by Spring, therefore your RuleRepository will be instantiated.
If it doesn't work on first try, you will have to add your com.example.controller package in the list of packages to scan, in the #ComponentScan annotation
First as everyone mention your class Judge does not have #Component annotations.
The other thing is, maybe my Spring is getting little bit rusty.
But as far as I remember, I think your repository also require to have #Component or #Repository annotation

Using Java configuration and constructor injection

I have a spring bean class with a constructor with multiple parameters and #Inject annotation.
Is there a way to use spring Java configuration class to create a bean for the class without actually writing code for creating the object? Something like using #Bean on a field?
#Bean(MyClassName.class) private MyInterfaceName myBean;
Or maybe by making the configuration class abstract and the bean method abstract, like:
#Bean(MyClassName.class) abstract MyInterfaceName myBean();
It's quite annoying (and pointless) to write each time the whole method that only creates a new object if you know that you only have 1 implementation of the class and you want to use auto wiring and constructor injection.
You can use #Component annotation. According to Spring documentation:
#Component indicates that an annotated class is a "component". Such classes are
considered as candidates for auto-detection when using
annotation-based configuration and classpath scanning.
Use the #Component annotation.
Indicates that an annotated class is a "component". Such classes are
considered as candidates for auto-detection when using
annotation-based configuration and classpath scanning. Other
class-level annotations may be considered as identifying a component
as well, typically a special kind of component: e.g. the #Repository
annotation or AspectJ's #Aspect annotation.
Here is an example:
import org.springframework.stereotype.Component;
#Component
public class CustomerDAO
{
#Override
public String toString() {
return "Hello , This is CustomerDAO";
}
}
A DAO class:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component
public class CustomerService
{
#Autowired
CustomerDAO customerDAO;
#Override
public String toString() {
return "CustomerService [customerDAO=" + customerDAO + "]";
}
}
And a runner class:
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App
{
public static void main( String[] args )
{
ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] {"Spring-AutoScan.xml"});
CustomerService cust = (CustomerService)context.getBean("customerService");
System.out.println(cust);
}
}
And your output:
CustomerService [customerDAO=Hello , This is CustomerDAO]

Categories

Resources