Autowiring a interface work without annotating it - java

I am working on Spring and hibernate project. For database communication we have conventional two layered implementation (i.e DAO layer and Service layer). I have following files:
DemoDao.java
package net.dao;
import java.util.List;
import net.domain.Demo;
public interface DemoDao
{
public List<Demo> get();
}
DemoDaoImpl.java
package net.dao;
import java.util.List;
import net.domain.Demo;
import org.hibernate.SessionFactory;
import org.hibernate.classic.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
#Repository
public class DemoDaoImpl implements DemoDao
{
#Autowired
SessionFactory sessionFactory;
public List<Demo> get()
{
Session session=sessionFactory.openSession();
List<Demo> list=session.createQuery("from Demo").list();
session.close();
return list;
}
}
That was DAO layer
Follwing is from service layer:
DemoManager.java
package net.service;
import java.util.List;
import net.domain.Demo;
public interface DemoManager
{
public List<Demo> get();
}
DemoManagerImpl.java
package net.service;
import java.util.List;
import net.dao.DemoDao;
import net.domain.Demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
#Service
public class DemoManagerImpl implements DemoManager
{
#Autowired
DemoDao demoDao;
public List<Demo> get()
{
List<Demo> list=demoDao.get();
return list;
}
}
Follwing is my controller
FromDualLayerView.java
package net.spring;
import java.util.List;
import net.domain.Demo;
import net.service.DemoManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
#Controller
public class FromDualLayerView
{
#Autowired
DemoManager demoManager;
#RequestMapping("/dualLayer")
public ModelAndView toResult(ModelMap map)
{
List<Demo> list=demoManager.get();
map.addAttribute("listData", list);
return new ModelAndView("result");
}
}
My Question
Actually everything works fine, but my question over here is that i am not annotating the DemoDao and DemoManager interface, but i am autowiring them. According to the autowiring definition the entities which are annotated are injected.
The how come the dependency is injected by Spring container?
And how does it work like an Impl class?
Thanks in advance.

DemoManagerImpl is annotated as a service and is the only qualifying bean to be injected in the FromDualLayerView class, as it's the only component which is instance of DemoManager. I suppose you have the component scan turned on as well.

The #Repository annotation and the #Service annotation mean you are annotating them. It's actually a spring best practice to annotate the implementations and not the interfaces.
Your spring config file is scanning the classpath, thus those beans are detected. Turn spring logging up to TRACE and you'll probably see output along the lines of:
"scanning classpath, found target DemoDaoImpl"

Related

Consider defining a bean of type 'com.fsse2207.project_backend.service.ProductService' in your configuration

Basically, I have created all of the pojo and layers(including the repository layer) necessary for Spring Boot to automatically implement MySql commands. When I trying to run the programme, I get the following command:
Description:
Parameter 0 of constructor in com.fsse2207.project_backend.api.ProductApi required a bean of type 'com.fsse2207.project_backend.service.ProductService' that could not be found.
Action:
Consider defining a bean of type 'com.fsse2207.project_backend.service.ProductService' in your configuration.
It turns out there's sth wrong about the bean in my ProductApi. It says "
Could not autowire. No beans of 'ProductService' type found." How do I fix it?
The following is the interface under the service layer:
package com.fsse2207.project_backend.service;
import com.fsse2207.project_backend.data.ProductCreateData;
import com.fsse2207.project_backend.data.ProductDetailData;
import com.fsse2207.project_backend.exception.ProductFoundByIdException;
import org.springframework.stereotype.Service;
public interface ProductService {
ProductDetailData createProductData (ProductCreateData productCreateData) throws ProductFoundByIdException;
}
The following is the service class:
package com.fsse2207.project_backend.service.impl;
import com.fsse2207.project_backend.data.ProductCreateData;
import com.fsse2207.project_backend.data.ProductDetailData;
import com.fsse2207.project_backend.data.entity.ProductEntity;
import com.fsse2207.project_backend.exception.ProductFoundByIdException;
import com.fsse2207.project_backend.repository.ProductRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
#Service
public class ProductServiceImpl {
private ProductRepository productRepository;
#Autowired
public ProductServiceImpl(ProductRepository productRepository){
this.productRepository=productRepository;
}
public ProductDetailData createProductData (ProductCreateData productCreateData) throws ProductFoundByIdException {
ProductEntity productEntity=new ProductEntity(productCreateData);
if(productRepository.existsById(productEntity.getpId())){
throw new ProductFoundByIdException();
}
return new ProductDetailData(productRepository.save(productEntity));
}
}
The following is the Api:
package com.fsse2207.project_backend.api;
import com.fsse2207.project_backend.data.ProductCreateData;
import com.fsse2207.project_backend.data.ProductDetailData;
import com.fsse2207.project_backend.data.dto.CreateRequestDto;
import com.fsse2207.project_backend.data.dto.CreateResponseDto;
import com.fsse2207.project_backend.exception.ProductFoundByIdException;
import com.fsse2207.project_backend.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class ProductApi {
private ProductService productService;
#Autowired
public ProductApi(ProductService productService){
this.productService=productService;
}
#PostMapping
public CreateResponseDto createResponseDto(#RequestBody CreateRequestDto createRequestDto) throws ProductFoundByIdException {
ProductCreateData productCreateData=new ProductCreateData(createRequestDto);
ProductDetailData productDetailData =productService.createProductData(productCreateData);
return new CreateResponseDto(productDetailData);
}
}
I found the problem:
I didn't add the implements keyword in the class definition of ProductServiceImpl so it was not connected to the bean, aka the interface, aka the service layer.
First of all you should not add annotation #Service for ProductService interface.
Moreover this can happen when you have your Class Application in "another package".
You can solve the problem using annotation #ComponentScan (basePackages = {"your.company.domain.package"})

Keep Getting "Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled" in Spring Boot

Whenever I start a spring boot project I keep getting this error, This question has been asked multiple times on stakeoverflow I have tried all the solutions but nothing works for me. My first questions are what is the reason for this error, and how can I fix it.
FilterApplication.java
package com.example.filter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication()
public class FilterApplication {
public static void main(String[] args) {
SpringApplication.run(FilterApplication.class, args);
}
}
FilterConnector.java
package com.example.filter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
#RestController
public class FilterConnector {
#Autowired
private FilterService filterService;
#GetMapping("/home")
public List<Filter> home()
{
return this.filterService.getData();
}
}
FilterService.java
package com.example.filter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
#Service
public class FilterService {
#Autowired
private FilterDao filterDao;
public List<Filter> getData() {
System.out.println("----------------------HERE-------------");
return this.filterDao.findAll();
}
}
FilterDao.java
package com.example.filter;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface FilterDao extends JpaRepository<Filter, Integer> {
}
Spring framework relies on ApplicationContext to inject dependencies into the dependent object. For example your FilterDao will be inject into FilterService object.
To do this Spring will try to initialized instances of these classes at the start of the Application, but if it fails you will see this error message.
The problem with your code is related to FilterDao class, Spring can't initialize an instance of this class because it requires the Database to be configured correctly.
To fix this error:
you need to check your database connection is correct.
make sure there is a table corresponding to Filter class.
check the primary key (ID) is actually of type Integer.
If you provide full error stack I can give you a specific solution.
Note:
The issues is not related to FilterService or FilterConnector, because you are using #Autowired annotation implying the dependencies are optional and they will be injected after the bean initialization.

I keep getting this #bean error when trying to run my spring boot app with dynamodb and graphql

This is the error which i am getting:
Description:
Field andiRepository in com.service.datafetcher.AllAndisDataFetcher required a bean of type 'com.repositories.AndiRepository' 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.repositories.AndiRepository' in your configuration.
This is the data fetcher file which is requiring a bean:
import com.models.Andi;
import com.repositories.AndiRepository;
import graphql.schema.DataFetcher;
import graphql.schema.DataFetchingEnvironment;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
#Component
public class AllAndisDataFetcher implements DataFetcher<List<Andi>> {
#Autowired
AndiRepository andiRepository;
#Override
public List<Andi> get(DataFetchingEnvironment dataFetchingEnvironment) throws Exception {
return andiRepository.findAll();
}
}
this is the main method which resides in "com".
package com;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
#SpringBootApplication
#ComponentScan("com.repositories")//to scan repository files
#EntityScan("com.models")
#EnableJpaRepositories("com.repositories.AndiRepository")
public class DynamoDBApplication {
public static void main(String[] args) {
SpringApplication.run(DynamoDBApplication.class, args);
}
}
The models, repositories, service, packages are inside the main com package.
This is the repository file:
package com.repositories;
import com.andiskillsmaxmodels.Andi;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface AndiRepository extends CrudRepository<Andi, Integer> {
}
Thank you
Correct your package names. They're all over the place. You have imported classes from different packages it seems. Make sure that AndiRepository is in the com.repositories package. And Andi class in your com.models package. After correcting these mistakes do the following.
Remove #ComponentScan("com.repositories"). You don't need this, since #SpringBootApplicationautomatically does it for you.
And replace #SpringBootApplication with #SpringBootApplication(scanBasePackages = "com")

Spring doesn't scan packages

I have a repository, annotated with #Repository
package com.jeppa.interfaces;
import com.jeppa.entities.User;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface UserRepository extends CrudRepository<User, String> {
User findByUserEmailIgnoreCase(String useremail);
}
Part of my controller:
package com.jeppa.controllers;
import com.jeppa.entities.ConfirmationToken;
import com.jeppa.entities.User;
import com.jeppa.interfaces.TokenRepository;
import com.jeppa.interfaces.UserRepository;
import com.jeppa.mail.EmailSenderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
#Controller
public class UserAccountController {
#Autowired
private UserRepository userRepository;
#Autowired
private TokenRepository tokenRepository;
#Autowired
private EmailSenderService emailSenderService;
#RequestMapping(value = "/register", method = RequestMethod.GET)
public ModelAndView displayRegistration(ModelAndView modelAndView, User user){
modelAndView.addObject("user", user);
modelAndView.setViewName("register");
return modelAndView;
}
//////////////
And, finnaly, my #SpringBootApplication:
package com.jeppa;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class RunApplication {
public static void main(String[] args) {
SpringApplication.run(RunApplication.class, args);
}
}
and i keep getting this error
*************************** APPLICATION FAILED TO START
Description:
Field userRepository in com.jeppa.controllers.UserAccountController
required a bean of type 'com.jeppa.interfaces.UserRepository' 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.jeppa.interfaces.UserRepository'
in your configuration.
what am i doing wrong? here's my project structure:
structure
With Spring Boot, you should generally rely on Spring Boot starters to autoconfigure your dependencies. In case of Spring Data add:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
into your pom file to autoconfigure Spring Data instead of directly relying on Spring Data (spring-data-jpa), which requires further manual configuration.
Also don't forget to add and configure an actual implementation as well (h2, jdbc, etc.)

Interface object on a spring controller

I saw a tutorial of spring but I have some doubts about it
If I had a interface like this
package com.journaldev.spring.service;
import java.util.List;
import com.journaldev.spring.model.Person;
public interface PersonService {
public void addPerson(Person p);
public void updatePerson(Person p);
public List<Person> listPersons();
public Person getPersonById(int id);
public void removePerson(int id);
}
and a class which implements the interface
package com.journaldev.spring.service;
import java.util.List;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.journaldev.spring.dao.PersonDAO;
import com.journaldev.spring.model.Person;
#Service
public class PersonServiceImpl implements PersonService {
private PersonDAO personDAO;
public void setPersonDAO(PersonDAO personDAO) {
this.personDAO = personDAO;
}
.
.
.
}
and the controller which use the service
package com.journaldev.spring;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.journaldev.spring.model.Person;
import com.journaldev.spring.service.PersonService;
#Controller
public class PersonController {
private PersonService personService;
#Autowired(required=true)
#Qualifier(value="personService")
public void setPersonService(PersonService ps){
this.personService = ps;
}
.
.
.
}
Why the controller has a PersonService object (that in an interface) instead of an PersonServiceIml(class which implements the interface) object????
The idea is that designing to interfaces is good practice : What does "program to interfaces, not implementations" mean?
It makes creating a new implementation easy and refactoring is simpler. An interface also ensures mocking is straightforward.
In practice you can get rid of the interface, mockito/powermock etc handle simple classes fine, and in lots of cases you won't need a new implementation or any refactoring.
Not sure whether the question is,
Why to use interface or
How the methods are called of the implemented class.
Assuming that, you want to know how the implemented methods are called, please check your dependency injection file. You will see that you have injected your implemented class.
Say for example, it might look something like this,
<bean id="personService" class="com.somethimg.service.impl. PersonServiceImpl">
</bean>

Categories

Resources