#Resource outside the #Controller on Spring Boot - java

I want to access an #Resource from an pojo class, but i cant. I allways get NullPointer. Im using Spring Boot framework, 1.4.2.RELEASE version.
Is it possible? Here is part of my code:
#Service
public class CvFacade implements Cvitae{
#Resource
private CvRepository cvDao;
//....
}
public interface CvRepository extends CrudRepository<Cv, Long>{
#Query("select c from Cv c where c.idiom = :idiom")
public List<Cv> listarCv(#Param("idiom") EnumIdiom idiom);
#Query("select c from Person c where c.idPerson=1")
public List<Person> listarPerson();
}
my Application:
#SpringBootApplication(scanBasePackages = { "com.xxxxxx.cv.controller","com.xxxxxx.cv.facade","com.xxxxxx.cv.repository"})
#EnableJpaRepositories(basePackages = {"com.xxxxxx.cv.repository"}, entityManagerFactoryRef = "emf")
#PropertySource(value = { "classpath:application.properties" })
#EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class })
public class Application extends SpringBootServletInitializer {
//...
}

Your CvRepository interface should be annotated as a Repository:
#Repository
public interface CvRepository extends CrudRepository<Cv, Long>{
#Query("select c from Cv c where c.idiom = :idiom")
public List<Cv> listarCv(#Param("idiom") EnumIdiom idiom);
#Query("select c from Person c where c.idPerson=1")
public List<Person> listarPerson();
}
This will expose CvRepository to the Spring context, making it available to inject into your CvFacade class.

You need to do couple of configurations in your application,
Add #Repositry annotation on all your Repository components so that they are available for component scan.
#Repository
public interface CvRepository extends CrudRepository<Cv, Long>{
#Query("select c from Cv c where c.idiom = :idiom")
public List<Cv> listarCv(#Param("idiom") EnumIdiom idiom);
#Query("select c from Person c where c.idPerson=1")
public List<Person> listarPerson();
}
You need to define your repository package to be scanned in #EnableJpaRepositories on your configuration class.
e.g. #EnableJpaRepositories("your_package")

In standard Spring style, you annotate a field, constructor or setter on the Service with #Autowired (or #Inject):
#Service
public class CvFacade implements Cvitae {
private CvRepository cvDao;
#Autowired
public CvFacade(CvRepository cvDao) {
this.cvDao = cvDao;
}
//....
}
That should then allow you to get access to it within the service. You do not need to place #Repository on the repository if it already extends one of the Spring Data repository classes.

Related

Spring Boot Common JPA repository class

I have a number of JPA repositories classes and I want to create one common class where I will create a getter method of a respective repository and I will use that common class in the service layer.
So Can you please guide me with best practices that how can I achieve this?
Here I am sharing my idea by using sample code,
JPA repository
#Repository
public interface IConfigRepository extends JpaRepository<Config, Integer> {
}
public interface IBusinessRepository extends JpaRepository<Business, Integer> {
}
Repo Factory (Common Class for all repositories)
public class RepoFactory {
#Autowired
private IConfigRepository configRepo;
#Autowired
private IBusinessRepository businessRepo;
public IConfigRepository getConfigRepository() {
return configRepo;
}
public IBusinessRepository getBusinessRepository() {
return businessRepo;
}
}
Service Class
#Service
public class ServiceA {
public final RepoFactory repoFactory;
public ServiceA(RepoFactory repoFactory) {
this.repoFactory = repoFactory
}
#Transactional(rollbackOn = Exception.class)
public void saveOrUpdate(Config config) {
repoFactory.getConfigRepository().save(config);
}
}
#Service
public class ServiceB {
public final RepoFactory repoFactory;
public ServiceB(RepoFactory repoFactory) {
this.repoFactory = repoFactory
}
#Transactional(rollbackOn = Exception.class)
public void saveOrUpdate(Business reqBusiness) {
repoFactory.getBusinessRepository().save(reqBusiness);
}
}
Thanks, everyone for helping me in advance.
It looks like, you're trying to do something the #Profile annotation can help you with. If I were you, I would keep a common interface (not class) and make the IConfigRepository extend it. Then you can mark IConfigRepository with the #Profile annotation. If in the future, you have to write an analogue interface, you should also mark it with the #Profile annotation and you can switch between these interfaces anytime you want by setting the appropriate profile to active.
#Repository
#Profile("config")
public interface IConfigRepository extends CommonRepository, JpaRepository<Config,Integer> {
}
public interface CommonRepository {
}
#Service
public class ServiceA {
public final CommonRepository commonRepository;
public ServiceA(CommonRepository commonRepository) {
this.commonRepository = commonRepository
}
...
}

JPA repository with single table inheritance (hibernate)

I have created two entites (RegularEmployee and ContactEntity) that extends the Employee entity.
#Entity
#Table(name="employees")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.STRING)
#DiscriminatorValue(value="employee")
public class Employee {
#Id
#GeneratedValue
private Long id;
private String name;
...
Im using SINGLE_TABLE inheritance for this implementations, and created a generic JpaRepository for manipulating data:
#Repository
public interface EmployeeRepository<T extends Employee> extends JpaRepository<T, Long> {
}
I've created also the Service class that autowire three instance of these generic repositories, and specific methods for each class.
#Service
public class EmployeeService {
#Autowired
private EmployeeRepository<Employee> employeeRepo;
#Autowired
private EmployeeRepository<RegularEmployee> regularRepo;
#Autowired
private EmployeeRepository<ContractEmployee> contractRepo;
public List<Employee> getAllEmployee() {
return employeeRepo.findAll();
}
public List<RegularEmployee> getAllRegularEmployee(){
return regularRepo.findAll();
}
public List<ContractEmployee> getAllContractEmployee() {
return contractRepo.findAll();
}
...
My problem is, that when I try to find all regular employees or contract employees, I always get all type of employees (employees, regular employees and contract employees all together).
I do not know why it behaves like this, even though the method's signature says it returns the appropriate type.
One option is to use #Query in EmployeeRepository:
public interface EmployeeRepository<T extends Employee> extends JpaRepository<T, Long> {
#Query("from RegularEmployee")
List<RegularEmployee> findAllRegularEmployees();
}
A second option is to create an additional repository for each subclass of Employee. For RegularEmployee would be:
public interface RegularEmployeeRepository extends EmployeeRepository<RegularEmployee>{}
This is how to use both options in EmployeeService:
#Service
public class EmployeeService {
#Autowired EmployeeRepository<Employee> employeeRepo;
#Autowired EmployeeRepository<RegularEmployee> regularRepoT;
#Autowired RegularEmployeeRepository regularRepo;
#PostConstruct
public void init(){
employeeRepo.save(new ContractEmployee("Mark"));
employeeRepo.save(new RegularEmployee("Luke"));
employeeRepo.findAll().forEach(System.out::println); // prints Mark and Luke
regularRepo.findAll().forEach(System.out::println); // prints only Luke
regularRepoT.findAllRegularEmployees().forEach(System.out::println); // prints only Luke
}
//...
}
Also you can omit #Repository on top of EmployeeRepository. Spring already knows that is a Repository because it extends JpaRepository.
Side note: if you don't need EmployeeRepository to be created by Spring add #NoRepositoryBean on top of its class.
I've been able to replicate what you've encountered using your generic EmployeeRepository. As an alternative I created two separate repositories: ContractualEmployeeRepository and RegularEmployeeRepository.
public interface ContractualEmployeeRepository extends JpaRepository<ContractualEmployee, String> {
}
public interface RegularEmployeeRepository extends JpaRepository<RegularEmployee, String> {
}
Then, I created an integration test.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {Main.class})
#TestExecutionListeners({DependencyInjectionTestExecutionListener.class,
TransactionalTestExecutionListener.class,
DbUnitTestExecutionListener.class})
#TestPropertySource(locations="classpath:application-test.properties")
#DatabaseSetup("classpath:SingleTableDataSet.xml")
public class IntegrationTest {
#Autowired
private RegularEmployeeRepository regularEmployeeRepository;
#Autowired
private ContractualEmployeeRepository contractualEmployeeRepository;
#Test
public void test() {
Assert.assertEquals(6, regularEmployeeRepository.findAll().size());
Assert.assertEquals(4, contractualEmployeeRepository.findAll().size());
}
}
and it works.
As for the usage and limitations of Generics in Spring Data JPA repositories: https://stackoverflow.com/a/19443031/14180014 He had done a great job explaining it.

Instantiate Java Spring repository interface without #Autowire

This is my Spring repository interface.
#Repository
public interface WebappRepository extends CrudRepository<myModel, Long> {
}
In my controller, I can instantiate the WebappRepository even though it's an interface, because of Spring annotation magic.
public class controller{
#Autowire
WebappRepository repo;
public controller(){
}
}
But this variant, using the constructor, does not work, and rightly so, because WebappRepository is an interface.
public class controller{
WebappRepository repo;
public controller(){
this.repo = new WebappRepository();
}
}
Olivier Gierke himself advocates to avoid #Autowire fields at all costs. How can I "instantiate" the repository interface in my Spring application while avoiding the #Autowire?
Inject dependencies in constructor:
#Component
public class Controller{
WebappRepository repo;
#Autowire
public Controller(WebappRepository repo){
this.repo = repo;
}
}
If you're on Spring 4.3+ and your target class has just one constructor, you can omit autowired annotation. Spring will inject all the needed dependencies for it.
So writing just below constructor would suffice:
public controller(WebappRepository repo){
this.repo = repo;
}
Reference: https://docs.spring.io/spring/docs/4.3.x/spring-framework-reference/htmlsingle/#beans-autowired-annotation

Spring boot: Consider defining a bean of type 'com.repository.services.interfacename' in your configuration

I've deployed an spring boot application, where i created an interface and implement it with two classes.
public interface interfacename {
LinkedHashSet<String> names(String path);
}
And implemented classes are
#Component
public class class1 implements interfacename {
......
}
#Component
public class class2 implements interfacename {
......
}
Now i try to create an instance for both the classes using interface name,
#Autowired
#Qualifier("class1")
interfacename imp1;
#Autowired
#Qualifier("class2")
interfacename imp2;
It is the configuration class,
#Configuration
public class interfacenameConfig {
#Bean
#ConditionalOnProperty(name = "class1", matchIfMissing = true)
public interfacename class1Service() {
return new class1();
}
#Bean
#ConditionalOnProperty(name = "stanfordname")
public interfacename class2Service() {
return new class2();
}
}
My Project structure is,
com.repository
application.java(#SpringApplcation)
com.repository.controller
applicationcontroller.java(#RestController)
com.repository.services
interfacename.java
interfacenameconfig.java(#configuration)
class1.java(#component)
class2.java(#component)
It throws the following error
Action:
Consider defining a bean of type 'com.repository.services.interfacename' in your configuration.
please someone guide me to solve this.
Thanks in advance
In you're usage you're saying that you want beans with the ids / names class1 and class2respectively:
#Autowired
#Qualifier("class1")
interfacename imp1;
#Autowired
#Qualifier("class2")
interfacename imp2;
But in the configuration you gave them different names:
#Configuration
public class interfacenameConfig {
#Bean
#ConditionalOnProperty(name = "class1", matchIfMissing = true)
public interfacename class1Service() {
return new class1();
}
#Bean
#ConditionalOnProperty(name = "stanfordname")
public interfacename class2Service() {
return new class2();
}
}
Namely: class1Service and class2Service. Those Ids are derived from the name of the function instantiating the beans
Two possible fixes:
Give them the names you want with #Bean("class1") and #Bean("class2").
OR
Use the names they have in the qualifier, that is: #Qualifier("class1Service") and #Qualifier("class2Service")
In your configuration class you should have an annotation to prompt for component scanning to the package that your interface interfacename belongs.
E.g.:
#ComponentScan({"com.repository.services"})
In Spring-boot you usually have this annotation in the Spring boot application class
e.g.
#SpringBootApplication
#ComponentScan({"com.repository.services"})
public class MyApplication {
}
UPDATE
If you have multiple classes implementing an interface you can use the value attribute when annotating them as #Component
#Component(value="class1")
public class class1 implements interfacename
#Component(value="class2")
public class class2 implements interfacename
and then #Autowire them with #Qualifier as you already do.
Based on your last update, since the #SpringBootApplication is in the parent directory of your spring-managed beans I think you can omit the #ComponentScan annotation. Spring will scan by default all the sub-packages below com.repository.
However I still believe that the interfacenameconfig class is redundant. Why are you declaring the same beans as the ones you have annotated as #Component? Either #Component or #Bean, there is no reason having both for the same beans as far as I know and it could probably be the source of your problem.
You need to add #Service annotation above interface implementation.
e.g. #Component
public interface interfacename {
LinkedHashSet<String> names(String path);
}
#Service
public class interfaceDefinition implements interfacename{
LinkedHashSet<String> names(String path){
// write code here
}
}
I have add the qualifier annotation along with #Component annotation. Then i ensure the application it is working fine.
#Component
#Qualifier("class1")
public class class1 implements interfacename {
......
}
Thanks for the reply

#DAO and #Service beans clarification

I have a basic question. I've been reading through some tutorials about spring and hibernate integration and in most of them there are DAO and Service layers like below:
public interface TeamDAO {
public void addTeam(Team team);
public void updateTeam(Team team);
public Team getTeam(int id);
public void deleteTeam(int id);
public List<Team> getTeams();
}
Then the implementation of the DAO is provided using the SessionFactory. For example:
#Repository
public class TeamDAOImpl implements TeamDAO {
#Autowired
private SessionFactory sessionFactory;
//Implementation follows..
}
And then there's another service interface the same as the DAO interface like below:
public interface TeamService {
public void addTeam(Team team);
public void updateTeam(Team team);
public Team getTeam(int id);
public void deleteTeam(int id);
public List<Team> getTeams();
}
And the service implementation:
#Service
#Transactional
public class TeamServiceImpl implements TeamService {
//HERE IS MY QUESTION
#Autowired
private TeamDAO teamDAO;
//implementation follows
}
In the service implementation above where I marked "here is my question" I see that we inject only the interface TeamDAO which doesn't have the implementation of the TeamDAOImpl class. So how does the interface and its implementations get injected together in the service layer provided we only inject the interface TeamDAO and not TeamDAOImpl?
When you use #Autowired on an interface, Spring searches a bean instance whose class implements that interface. If it doesn't find any such bean, it fails. If it finds more than one class that implement the interface, it fails. Please refer to Spring #Autowired documentation for further details.
Spring injects TeamDAOImpl because it gets register as spring bean when you mark it as #Repository

Categories

Resources