Spring Boot Annotation #Autowired of Service fails - spring

I'm trying to use #Autowired annotation for a Service class in Spring Boot application, but it keeps throwing No qualifying bean of type exception. However, if I change the service class to a bean, then it works fine. This is my code:
package com.mypkg.domain;
#Service
public class GlobalPropertiesLoader {
#Autowired
private SampleService sampleService;
}
package com.mypkg.service;
#Service
public class SampleService{
}
And this is my SpringBoot class:
package com.mypkg;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
#SpringBootApplication
#EnableJpaRepositories
#Import(RepositoryRestMvcConfiguration.class)
#EnableTransactionManagement
public class TrackingService {
private static final Logger LOGGER = LoggerFactory.getLogger(TrackingService.class);
static AnnotationConfigApplicationContext context;
public static void main(String[] args) throws Exception {
SpringApplication.run(TrackingService.class, args);
context = new AnnotationConfigApplicationContext();
context.refresh();
context.close();
}
}
When I try to run this, I get the following exception:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.mypkg.service.SampleService] 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)}
But when I remove the #Service annotation from the SampleService class, and add it as a bean in my AppConfig class as below, it works fine:
#Configuration
public class AppServiceConfig {
public AppServiceConfig() {
}
#Bean(name="sampleService")
public SampleService sampleService(){
return new SampleService();
}
}
The classes are in different packages. I am not using #ComponentScan. Instead, I'm using #SpringBootApplication which does that automatically. However, I tried with ComponentScan as well but that didn't help.
What am I doing wrong here?

You are using two ways to build a Spring's bean. You just need to use one of them.
#Service over the POJO
#Service
public class SampleService
#Bean in the configuration class which must be annotated with #Configuration
#Bean
public SampleService sampleService(){
return new SampleService();
}
#Autowired is resolved by class type then #Bean(name="sampleService") is not needed is you have only one bean with that class type.
EDIT 01
package com.example
#SpringBootApplication
public class Application implements CommandLineRunner {
public static void main(String... args) {
SpringApplication.run(Application.class);
}
#Autowired
private UserRepository userRepository;
#Autowired
private UserService userService;
#Override
public void run(String... strings) throws Exception {
System.out.println("repo " + userRepository);
System.out.println("serv " + userService);
}
}
package com.example.config
#Configuration
public class AppConfig {
#Bean
public UserRepository userRepository() {
System.out.println("repo from bean");
return new UserRepository();
}
#Bean
public UserService userService() {
System.out.println("ser from bean");
return new UserService();
}
}
package com.example.repository
#Service
public class UserRepository {
#PostConstruct
public void init() {
System.out.println("repo from #service");
}
}
package com.example.service
#Service
public class UserService {
#PostConstruct
public void init() {
System.out.println("service from #service");
}
}
Using this code you can comment the AppConfig class and then you will see how UserRepository and UserService are autowired. After that comment #Service in each class and un-comment AppConfig and classes will be autowired too.

Related

Using transactional in spring boot with hibernate

I am getting the error while using hibernate in spring boot application No qualifying bean of type TransactionManager' available
I am using the following config class:
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
#org.springframework.context.annotation.Configuration
#EnableTransactionManagement
public class Config {
#Bean
public SessionFactory sessionFactory() {
Configuration configuration = new Configuration();
configuration.configure();
configuration.addAnnotatedClass(Ct.class);
configuration.addAnnotatedClass(St.class);
SessionFactory sessionFactory = configuration.buildSessionFactory();
return sessionFactory;
}
}
#RestController
public class RestAPIController {
#Autowired
private SessionFactory sessionFactory;
#PutMapping("/addS")
#Transactional
public void addSt(#RequestParam("cc") String cc,#RequestParam("st") String st) {
CC cc1= new CC();
CC.setCode(cc);
State state = new State(cc,st);
sessionFactory.getCurrentSession().save(state);
}
}
}
The main reason I added the #Transactional in the addSt method is due to error: The transaction was still an active when an exception occurred during Database.
So I turned to use spring boot for managing transactions. I am not sure what to do here.
--------------------UPDATED CODE--------------------
#Repository
public interface StateRepository extends CrudRepository<State, String> {}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.ArrayList;
import java.util.List;
#Service
#Transactional
public class StateService {
#Autowired
private StateRepository stateRepository;
public void save(State state) {
stateRepository.save(state);
}
public List<State> findAll() {
List<State> states = new ArrayList<>();
stateRepository.findAll().forEach(states::add);
return states;
}
}
For starters use proper layers and write a service and use JPA instead of plain Hibernate. If you want a Session you can always use EntityManager.unwrap to obtain the underlying Session.
#Service
#Transactional
public StateService {
#PersistenceContext
private EntityManager em;
public void save(State state) {
em.persist(state);
}
Use this service in your controller instead of the SessionFactory.
#RestController
public class RestAPIController {
private final StateService stateService;
RestAPIController(StateService stateService) {
this.stateService=stateService;
}
#PutMapping("/addS")
public void addSt(#RequestParam("cc") String cc, #RequestParam("st") String st) {
CC cc1= new CC();
CC.setCode(cc);
State state = new State(cc,st);
stateService.save(state);
}
}
Now ditch your Config class and restart the application.
NOTE
When using Spring Data JPA it is even easier, define a repository extending CrudRepository and inject that into the service instead of an EntityManager. (I'm assuming that Long is the type of primary key you defined).
public interface StateRepository extends CrudRepository<State, Long> {}
#Service
#Transactional
public StateService {
private final StateRepository states;
public StateService(StateRepository states) {
this.states=states;
}
public void save(State state) {
states.save(state);
}
}

#Autowired is Null in Spring Boot but same is accessible through Application Context

Through #Autowired i am not able to access the #Component/#Service/#Respository/#Controller class objects in other java files which has #Component annotation (Step 1: Approach) with the Step 1 approach getting Null pointer Exception, but same i could achieve using (Step 2: Approach).
Can anyone please tell me why i am not able to achieve using Step 1 approach:
FYI- I've searched in my entire project i have not used/called/initialized the #Component classes using new method for the autowired class still i getting the issue as "Null Pointer Exception"
Step 1: Using #Autowired Annotation
#Component
public class Processor {
#Autowired
PropertyConfigurator propconfigrator; --> Getting here as null pointer Exception
public void getDetails(){
System.out.println ("Application URL +propconfigrator.getProperties().getProperty("appURL"));
}
}
Step 2: Using ApplicationContext Interface with/without #AutoWired annotation . I am able to get the property value from PropertyConfigurator java file
#Component
public class Processor {
#Autowired
PropertyConfigurator propconfigrator = ApplicationContextHolder.getContext().getBean(PropertyConfigurator.class);
public void getDetails(){
System.out.println ("Application URL +propconfigrator.getProperties().getProperty("appURL"));
}
}
ApplicationContextHolder.java
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
#Component
public class ApplicationContextHolder implements ApplicationContextAware {
private static ApplicationContext context;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
public static ApplicationContext getContext() {
return context;
}
}
PropertyConfigurator.java file
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
#Service
#Configurable
public class PropertyConfigurator {
private final Properties properties;
public Properties getProperties () {
return properties;
}
public PropertyConfigurator(){
properties = new Properties();
try {
properties.load(getClass().getClassLoader().getResourceAsStream("dbconfig.properties"));
} catch (IOException e) {
Logger.getLogger(getClass().getName()).log(Level.SEVERE, e.getMessage(), e);
}
}
}
Why did you use #Configurable annotation? In the code you postet, it doesn't make sense. #Configurable is only needed in cases when instances of this class are not createt by spring.
I have changed into Constructor Injection Autowiring as below with the step 1 approach of above (Not using Step 2. It resolved my issue finally.
Not sure why Spring is not able to inject the bean without using the Constructor Autowiring.
Step 1: Using #Autowired Annotation with Constructor
#Component
public class Processor {
#Autowired
public Processor (PropertyConfigurator propconfigrator) {
this.propconfigrator = propconfigrator;
}
public void getDetails(){
System.out.println ("Application URL +propconfigrator.getProperties().getProperty("appURL"));
}
}

Is #Autowired annotation mandatory on constructor in Spring boot

Is it mandatory to put #Autowired if I am using constructor DI?
Is #Autowired annotation mandatory for a constructor?
No.
As of Spring 4.3 if your class has only single constructor then there is no need to put #Autowired.
Before Spring 4.3:
package com.example.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
#Service
public class DatabaseAccountService implements AccountService {
private final RiskAssessor riskAssessor;
#Autowired
public DatabaseAccountService(RiskAssessor riskAssessor) {
this.riskAssessor = riskAssessor;
}
// ...
}
After:
#Service
public class DatabaseAccountService implements AccountService {
private final RiskAssessor riskAssessor;
public DatabaseAccountService(RiskAssessor riskAssessor) {
this.riskAssessor = riskAssessor;
}
// ...
}
Extra: With Lombok, after Spring 4.3
With Lombok you can use #RequiredArgsConstructor to make the code even cleaner:
#Service
#RequiredArgsConstructor
public class DatabaseAccountService implements AccountService {
private final RiskAssessor riskAssessor;
}

How to get Neo4jTemplate in SDN4

I am using Spring Data Neo4j 4(SDN4) from the example project SDN4-northwind(https://github.com/amorgner/sdn4-northwind),when I try to get the Neo4jTemplate bean,I get the error message like this.
Does anyone know how to get the Neo4jTemplate bean from SDN4?
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.data.neo4j.template.Neo4jTemplate] is defined
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:371)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:331)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:968)
at org.neo4j.example.northwind.Run.main(Run.java:34)
Here is the Configuration file
package org.neo4j.example.northwind;
import org.neo4j.ogm.session.Session;
import org.neo4j.ogm.session.SessionFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.neo4j.config.Neo4jConfiguration;
import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;
import org.springframework.data.neo4j.server.Neo4jServer;
import org.springframework.data.neo4j.server.RemoteServer;
import org.springframework.transaction.annotation.EnableTransactionManagement;
#Configuration
#EnableNeo4jRepositories("org.neo4j.example.northwind.repository")
#EnableTransactionManagement
public class AppContext extends Neo4jConfiguration {
public static final String NEO4J_HOST = "http://localhost:";
public static final int NEO4J_PORT = 7474;
#Override
public SessionFactory getSessionFactory() {
System.setProperty("username", "neo4j");
System.setProperty("password", System.getProperty("password","osp"));
return new SessionFactory("org.neo4j.example.northwind.model");
}
#Bean
#Override
public Neo4jServer neo4jServer() {
return new RemoteServer(NEO4J_HOST + NEO4J_PORT);
}
#Bean
#Override
//#Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public Session getSession() throws Exception {
return super.getSession();
}
}
Assdd
#Bean
public Neo4jOperations getNeo4jTemplate() throws Exception {
return new Neo4jTemplate(getSession());
}
to AppContext and then #Autowired Neo4jOperations neo4jTemplate;

Why is #Autowired working differently in application and test?

I made a sample program revealing my question:
package test;
public interface InterfaceA {
}
package test;
public class ClassA implements InterfaceA {
}
package test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class Application {
#Bean
public InterfaceA beanA() {
return new ClassA();
}
#Autowired
private ClassA beanA;
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext
= new AnnotationConfigApplicationContext(Application.class);
}
}
#Autowired doesn't work with the concrete class in this application code.
package test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = Application.class)
public class ApplicationTest {
#Autowired
ClassA beanA;
#Test
public void di() {
System.out.println(beanA);
}
}
But #Autowired works with the concrete class in this test code.
Why is #Autowired working differently in application and test?
I shared the above code at:
https://github.com/izeye/SpringTest
You're using your application context in the main entry point of the application. Make an additional 'Main' class and wire in your context like so:
#Autowired
Application context;
In your test, you're taking the time to start up the application context when you use the annotation: #ContextConfiguration(classes = Application.class).
In your concrete example you're referencing the context in the same class that you're trying to use it in. When you initialize the context in the main, the instance of Application that is running the code has already been instantiated, and did not get autowired, because at the time of its instantiation there wasn't any context for it to use.
It is a bit tricky:
Solution would be to make beanA static method and annotate Application with #Lazy or #DependsOn(value="beanA") annotations. I.e. something like this:
#Configuration
#Lazy
public class Application {
#Bean
public static InterfaceA beanA() {
return new ClassA();
}
#Autowired
private ClassA beanA;
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext
= new AnnotationConfigApplicationContext(Application.class);
}
}
Reason: for actual beanA bean creation spring need to instantiate Application class first. And while trying to resolve reference to a beanA the only information container has about this future bean is its type (InterfaceA) since there is no actual implementation exists.
However in a case of test class context was already initialized and bean can be resolved by actual implementation class which physically was already created. Same would be if you will try to reference beanA by class from any other spring component.

Resources