Spring Crud Repository - Unsatisfied dependency expressed - Cant inject model - java

i seem to be unable to get Spring to recognize the native CrudRepository and use it, because spring isn not able to inject / use the actual class that my generic CrudRepository needs to implement when i put it in a different package than the one with the main method.
My Project structure is pretty straight forward.
Leaving the structure like this works just fine!
I want however Author to be inside the model package, like this:
However Spring always throws the error:
Error creating bean with name 'demoApplication': Unsatisfied dependency expressed through field 'authorRepository'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'authorRepository' defined in service.AuthorRepository defined in #EnableJpaRepositories declared on DemoApplication: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Not a managed type: class model.Author
I definately dont want to use a configuration through an application.properties.xml file. I want it to be programmatically configured within java code.
The Author.java :
#Data
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table(name = "authors")
public class Author {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(nullable = false)
private String name;
}
The AuthorRepository that implements the CrudRepository:
#Repository
public interface AuthorRepository extends CrudRepository<Author, Integer> {
}
If it is of any importance here is the Config class where i define my DataSource. The #Bean with Author seems not important, since it works without it too when i leave the Author inside the com.example.demo package.
#Configuration
public class Config {
#Bean
public DataSource dataSource(){
DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
dataSourceBuilder.url("jdbc:mysql://localhost:3306/sks");
dataSourceBuilder.username("sks");
dataSourceBuilder.password("technikum1");
return dataSourceBuilder.build();
}
#Bean
public Author author(){
return new Author();
}
}
And finally my Main method:
#SpringBootApplication
#ComponentScan(basePackages = {"config"})
#EnableJpaRepositories(basePackages = {"service"})
public class DemoApplication implements CommandLineRunner {
#Autowired
private AuthorRepository authorRepository;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
#Override
#Transactional
public void run(String... args) throws Exception {
Iterable<Author> authors = authorRepository.findAll();
System.out.println(authors);
}
}
I tried annotating the AuthorRepository with a #ComponentScan(basePackages = {"model"}) and annotated the Author.java with #Component because i thought it might not recognize it as bean or something if i put it in another package ( which would be strange anyway since i dont need the component annotation when i leave it in the main package) but nothing worked so far.
Generally struggling hard with project structure and Spring....
Also i have tried to change the #ComponentScan(basePackages = {"config"}) in DemoApplication to #ComponentScan(basePackages = {"config","model"}).
Nothing worked so far !
I need some help ...

Related

Spring Boot Application not registering #Repository

I'm creating a simple SpringBoot application with spring-data-jpa for learning purposes.
My problem is when I try to #Autowire a #Repository the application always fails to start with the error:
APPLICATION FAILED TO START
***************************
Description:
Field pedidoRepository in com.pedidos.services.PedidoService required a bean of type 'com.pedidos.repositories.PedidoRepository' 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.pedidos.repositories.PedidoRepository' in your configuration.
All the answers that i have found so far tells me to do something that is already done in my application. I'm probably missing something and I can't find out what it is.
This is how my application is now (imports are omitted):
Application:
package com.pedidos;
#SpringBootApplication
public class PedidosApplication {
public static void main(String[] args) {
SpringApplication.run(PedidosApplication.class, args);
}
}
Repository:
package com.pedidos.repositories;
#Repository
public abstract class PedidoRepository implements JpaRepository<Pedido, UUID> {
}
Service:
package com.pedidos.services;
#Service
public class PedidoService {
#Autowired
private PedidoRepository pedidoRepository;
public Optional<Pedido> findById(UUID id){
return pedidoRepository.findById(id);
}
public Pedido save(Pedido pedido){
return pedidoRepository.save(pedido);
}
}
Controller:
package com.pedidos.controllers;
#Controller("/pedido")
public class PedidoController {
#Autowired
private PedidoService pedidoService;
#GetMapping("/{id}")
public Pedido get(#PathVariable(name = "id") UUID id){
return pedidoService.findById(id).get();
}
}
Here is my Project structure
If do not inject the repository the application runs fine.
The entire code is in this GitHub repo: https://github.com/brunomokan/pedidos
Like what ILya Cyclone say. A Spring-Data Repository should be an interface which get a proxy at runtime. Something like this. Its fine if you extend from another interface.

How to use spring #autowired annotation in the class having void methods?

I have an interface and service implements it. It has some void methods.
I am using spring java bean configuration. But unable to create bean object because of void methods.How to handle this problem.
I tried to use #PostConstruct instead of #Bean after reading some blogs, but it didn't work out.
public interface MyInterface {
void someData(List<MyClass> list, String somedata);
}
#Service("myInterface")
public DummyClass implements MyInterface {
public void someData(List<MyClass> list, String somedata){
// my business logic
}
}
public AppConfig {
#Bean
public MyInterface myInterface {
return new DummyClass(); // but gives error void cannot return value
}
}
My Junit looks like this
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(
classes = {AppConfig.class},
loader = AnnotationConfigContextLoader.class
)
public class MyTest {
#Autowired
DummyClass dummyClass;
// If I don't use AppConfig and simply autowire then I get
"Error creating bean name, unsatisfied dependency
}
How do I achieve dependency injection here?
Use #Configuration annotation on AppConfig class, with this all the beans defined on this class will be loaded on spring context.
If you use #Service annotation on DummyClass, you do not need to declare #Bean annotation because you are already saying to spring to detect this class for dependency injection. On the other hand use #Bean annotation to specify the instantiation of the class. Normally I let the #Bean to complex classes for dependency injection or to override configurations.

Spring Boot defining bean in configuration problem

I'm working on a project on my sparetime, on this project I have been asked to work with Spring Boot. I'm not familiar with Spring Boot from before, and I have tried searching here on stackoverflow and Google, but I can't seem to understand how the different solutions for my problem works.
First of all, this is my error message:
Parameter 0 of constructor in com.project.example.controller.VerverController required a bean of type 'com.project.example.dao.VerverDao' that could not be found.
Action:
Consider defining a bean of type 'com.project.example.dao.VerverDao' in your configuration.
After some reading, I understood that this could be because of Spring Boot don't scan this class / interface. So I tried to add ComponentScan, with no luck.
I tried to convert VerverDao from interface to class and register a bean with bean annotation. Still no luck. I tried to move the VerverDao from the dao package to the root package (the same as the Main class) and still no luck.
So if someone could please help me understand the error message, it would make my day.
This is my structure:
This is my code:
Probably some of the annotation is wrong as well, since I'm not used to Spring Boot, in advance thanks for correcting me on the use of these
It is also worth mentioning that I'm using Lombok as well on this project.
Main.java
#ComponentScan("com.gambinomafia")
#SpringBootApplication
public class Main extends SpringBootServletInitializer {
public static void main(String[] args) {
new Main().configure(new SpringApplicationBuilder(Main.class)).run(args);
}
}
Configuration.java
#Component
public class Configuration extends ResourceConfig {
public Configuration() {
register(VerverResourceImpl.class, VerverResource.class);
register(VerverController.class);
register(VerverDao.class);
}
}
VerverResource.java
#Resource
#Path("verver")
public interface VerverResource {
#GET
#Path("/{userid}")
#Produces(MediaType.APPLICATION_JSON)
String getRefferingUrl(#PathParam("userid") int userid);
}
VerverResourceImpl.java
#AllArgsConstructor(onConstructor = #__({#Inject}))
public class VerverResourceImpl implements VerverResource {
private VerverController controller;
#Override
public String getRefferingUrl(int userid) {
log.info("Collection reciever url for user id: {}", userid);
return controller.getRefferingUrl(userid);
}
}
VerverController.java
#Controller
#AllArgsConstructor
public class VerverController {
private VerverDao ververDao;
public String getRefferingUrl(int userid) {
User user = ververDao.getUsername(userid);
if (user.getUsername().isEmpty()) {
throw new NotFoundException("Did not find any user with id " + userid);
}
return "<url-to-site>/?verv=" + user.getUsername();
}
}
VerverDao.java
#AllArgsConstructor
public class VerverDao {
#Value("spring.datasource.url")
private String dbcon;
public User getUsername(int userid) {
Jdbi jdbi = Jdbi.create(dbcon);
return jdbi.withHandle(handle -> handle.createQuery(
"SELECT id, brukernavn FROM t_user WHERE id = :id")
.bind("id", userid)
.mapToBean(User.class)
.findOnly());
}
}
Feel free to ask for more information, if there is missing some information in the topic. I will try to answer as fast as possible.
First at all, you're setting a #ComponentScan with a wrong package in your Application class.
#ComponentScan("com.gambinomafia")
#SpringBootApplication
And, according to the picture, it has to be:
#ComponentScan("com.project.example")
#SpringBootApplication
EDIT: the use of #ComponentScan by #M.Deinum
Because of the Application Class is in the root package and #SpringBootApplication already contains #ComponentScan, It isn't needed to declare #ComponentScan.
Second, instead of use a DAO you can use Repositories. There is more information here: Spring Boot Repositories.
Third, to inject your objects you can use #Autowired over the constructor.
#Controller
public class VerverController
private VerverDao ververDao;
#Autowired
public VerverController(VerverDao ververDao) {
this.ververDao = ververDao;
}
}
There is more information here.
Log clearly says
VerverController required a bean of type 'com.project.example.dao.VerverDao' that could not be found.
It means there is no bean of type com.project.example.dao.VerverDao
Add #Repository on top of VerverDao to resolve the issue.
#Repository
#AllArgsConstructor
public class VerverDao {
}
Note: Ensure VerverDao is in component scanning path as per your package structure.

Autowiring :expected at least 1 bean which qualifies as autowire candidate for this dependency

Okay, I know that there are many questions asked around the same topic. But I cant seem to make anything work. It also might be the case that I am yet to completely understand the auto wiring concept.
My Problem:
I am able to get to the required page, but whenever I click on the any button to perform an action I get Null pointer exception which seems obvious as I dont think spring is able to properly map the bean needed.
So, when I add #autowired=true , it gives me the above given exceptionn.
I am not sure what needs to be done.. Hope someone can help me out with this. Would love an explanation as well:)
Code:
#Entity
#Table(name="userDetails")
public class UserDetailModel {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
public int user_id;
public String password;
public String user_name;
public String active_status;
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getUser_name() {
return user_name;
}
public void setUser_name(String user_name) {
this.user_name = user_name;
}
public int getUser_id() {
return user_id;
}
public void setUser_id(int user_id) {
this.user_id = user_id;
}
public String getActive_status() {
return active_status;
}
public void setActive_status(String active_status) {
this.active_status = active_status;
}
}
Controller:
#RestController
public class UserDetailController {
private Logger logger = (Logger) LoggerFactory.getLogger(UserDetailController.class);
#Autowired(required = true)
private UserRepository userRepository;
#RequestMapping(value="/login", method = RequestMethod.POST)
public #ResponseBody String addNewUser (#RequestBody UserDetailModel user) {
// #ResponseBody means the returned String is the response, not a view name
// #RequestParam means it is a parameter from the GET or POST request
logger.debug("in controller");
UserDetailModel userDtl = new UserDetailModel();
userDtl.setUser_id(user.user_id);
userDtl.setUser_name(user.user_name);
userDtl.setActive_status(user.active_status);
userDtl.setPassword(user.password);
userRepository.save(userDtl);
return "Saved";
}
}
Repository:
#Repository
public interface UserRepository extends CrudRepository<UserDetailModel, Long> {}
Stack Trace:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userDetailController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.springBoot.usl.repo.UserRepository com.springBoot.usl.controller.UserDetailController.userRepository; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.springBoot.usl.repo.UserRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:292)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1185)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:703)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:120)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:683)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:313)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:944)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:933)
at com.springBoot.usl.controller.WebAppInitializer.main(WebAppInitializer.java:18)
Solved based on the responses
Answer:
I made some modifications based on Jay and Luay's answers. And changed the annotations as follows in my ApplicationConfig file:
#Configuration
#ComponentScan("my.basepackage.*")
#EnableJpaRepositories(basePackages = {"my.basepackage.*"})
#EntityScan("my.basepackage.*")
#EnableAutoConfiguration
Hope this helps some one.
But I am not sure if * is the right way to go.
I am able to run your application with some changes on annotation side.
I have used same classes which are given in question. Please see below structure and configuration used.
Directory Structure
I have used packages as below and added your classes,
com.rcmutha.usl.controller
com.rcmutha.usl.repository
#SpringBootApplication
#ComponentScan({"com.rcmutha*"})
#EntityScan("com.rcmutha*")
#EnableJpaRepositories("com.rcmutha*")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
For complete code :
click here for code
I think your application is not able to scan the UserRepository class, If you are using Spring Boot then you should put the main class on top of your package hierarchy.
You should also use #EnableJpaRepositories and tell it the base package of your repos to enable the repository functionality
#EnableJpaRepositories(basePackages ={"com.springBoot.usl.repo"})
UserRepository is simply not defined in the current Spring Context.
Make sure that your class is defined in a package that is scanned by Spring. You will need to use #ComponentScan("org.my.pkg") in your Configuration class to make Spring scan the package.
If you're using Spring Boot, make sure you locate your main application class which is annotated with #SpringBootApplication in a root package above other classes, as it contains #ComponentScan.
You need to enable the JPA repositories in your config class, specify the package that contains the repositories as below
#Configuration
#EnableJpaRepositories(basePackages = {
"com.springBoot.usl.repo"
})
public class ApplicationConfig {
}
Example of ApplicationConfig:
#Configuration
#EnableJpaRepositories(basePackages = {"com.springBoot.usl.repo"})
#EnableTransactionManagement
public class ApplicationConfig {
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/xxxx");
dataSource.setUsername("xxxx");
dataSource.setPassword("xxxx");
return dataSource;
}
#Bean
public EntityManagerFactory entityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(true);
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("xx.xxxx.xxxx.xxxx.domain");
factory.setDataSource(dataSource());
factory.afterPropertiesSet();
return factory.getObject();
}
#Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory());
return txManager;
}
I know that the problem was solved, but as it can be problem for someone else like I had, I decided to share my problem and the solution.
I got exactly the same error message, but the problem was the lack of the annotation #Service in a class and hence an object of this type couldn't autowire. After putting this annotation, everything worked fine.
Below is the object of the mentioned class:
#Autowired
private JwtUserDetailsService jwtUserDetailsService;
Just this annotation caused the same problem and can pass unnoticed:
#Service // annotation that was missing
public class JwtUserDetailsService implements UserDetailsService { ...
We had a similar problem in a kotlin + spring boot application and could solve it thanks to this solution slightly modified:
#SpringBootApplication
#ComponentScan("package.path*")

Spring boot #Autowired can't initialise class

I have following class as:-
#SpringBootApplication
#ComponentScan("com.ma.demospringboot")
public class DemoSpringBootApp {
public static void main(String[] args) {
SpringApplication.run(DemoSpringBootApp.class, args);
}
}
I have following class as:-
#Service
public class TopicService {
// if I comment out following autowired, then it is ok.
#Autowired
private TopicRepository topicRepository;
}
I have following interface as:-
public interface TopicRepository extends CrudRepository<Topic, String> {
}
I have following class as:-
#Entity
public class Topic {
#Id
private String id;
private String name;
private String description;
public Topic() {
}
}
I got following error when try to execute:-
APPLICATION FAILED TO START
Description:
Field topicRepository in com.ma.demospringboot.service.TopicService
required a bean of type
'com.ma.demospringboot.repository.TopicRepository' that could not be
found.
Action:
Consider defining a bean of type
'com.ma.demospringboot.repository.TopicRepository' in your
configuration.
Spring container is not finding your repository classes during the scan, add #EnableJpaRepositories to explicitly specify the packages of where your repository classes exist, as shown below:
#SpringBootApplication
#ComponentScan("com.ma.demospringboot")
#EnableJpaRepositories("com.ma.demospringboot.repository")
#EntityScan(basePackages = "com.ma.demospringboot.domain")
public class DemoSpringBootApp {
//your current code here
}
UPDATE1:
Not a managed type: class com.ma.demospringboot.domain.Topic
Now, your Topic entity class not found, so you need to #EntityScan(basePackages = "com.ma.demospringboot.domain") to scan the entity classes (as show above).
UPDATE2:
I did exactly as you suggested, but NOT working
There is a problem with the way that you are packaging the classes, double check on that, also ensure that the latest classes have been compiled/built & used by the server.
Your Spring container is unable to find and identify your JPA repositories.
Add #EnableJpaRepositories("com.ma.demospringboot.repository") on your DemoSpringBootApp class
#SpringBootApplication
#ComponentScan("com.ma.demospringboot")
#EnableJpaRepositories("com.ma.demospringboot.repository")
public class DemoSpringBootApp {
public static void main(String[] args) {
SpringApplication.run(DemoSpringBootApp.class, args);
}
}
add following code in your ApplicationContext.xml
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />

Categories