Does spring bean self injection works in new spring versions? - spring

#Service
public class UserService implements Service{
#Autowired
private Service self;
}
Does the code above works fine in Spring new versions (5.*)?
( I could check by myself but I wanna know 100%, but myself I may screw it up somehow )
Also I know workarounds:
#Service(value = "someService")
public class UserService implements Service{
#Resource(name = "someService")
private Service self;
}
OR
#Autowired
private ApplicationContext applicationContext;
So I'm not just asking for nothing, I need to know 100%
I need an advice from professionals, I don't believe to myself experiments, because I'm not so much experienced in Spring ( e.g. there are much nebulous configs there for me) . Hope this clarifies why I'm asking rather than experiment.

Ok I found the answer:
With Spring 4 it's possible to Self autowired
#Service
#Transactional
public class UserServiceImpl implements UserService{
#Autowired
private UserRepository repository;
#Autowired
private UserService userService;
#Override
public void update(int id){
repository.findOne(id).setName("ddd");
}
#Override
public void save(Users user) {
repository.save(user);
userService.update(1);
}
}

Related

What will happen if i remove #Autowired from field/constructor injection but injecting that bean in another class

Suppose i have a class as,
#Repository
public class StudentServiceDao{
private final StudentClient client;
private final StudentValidator validator;
#Autowired <----
public StudentServiceDao(StudentClient studentClient){
client = studentClient;
validator = new StudentValidator(studentClient.getIdentifier());
}
public List<Student> getStudent(Request request){
StudentRS studentRS= client.getStudentList(request);
validator.validate(studentRS);
return StudentMapper.map(studentRS);
}
}
Now i have another class as,
#Component
public class StudentServiceDaoImpl{
#Autowired
private StudentServiceDao studentServiceDao;
public list<Student> retrieveStudent (Request request){
return studentServiceDao.getStudent(request);
}
}
Now if i remove #Autowired from StudentServiceDao what will happen and why ?
Autowiring can happen multiple ways.
For a few years now (currently 2020) all of these are valid ways to autowire dependencies:
Explicit constructor autowire annotation:
#Repository
public class StudentServiceDao {
private final StudentClient client;
private final StudentValidator validator;
#Autowired
public StudentServiceDao(StudentClient studentClient){
client = studentClient;
validator = new StudentValidator(studentClient.getIdentifier());
}
}
Implicit constructor autowire:
#Repository
public class StudentServiceDao {
private final StudentClient client;
private final StudentValidator validator;
public StudentServiceDao(StudentClient studentClient){
client = studentClient;
validator = new StudentValidator(studentClient.getIdentifier());
}
}
Explicit field autowire:
#Repository
public class StudentServiceDao {
#Autowired
private final StudentClient client;
#Autowired
private final StudentValidator validator;
}
Pick which ever one makes the most sense for you. I personally like implicit constructor. I think it makes instantiating the bean for testing easier with mocks. All types are valid.
5 or 6 years ago, before java config took over, there were other requirements like getters/setters needing to be present, xml files needing to specify all the beans, etc. But those are mostly gone and if you are working on a modern spring app you won't encounter them.
As to why, I have no idea, this is just how it is.

Injecting one MockBean into another

I have a typical SpringApplication which I am trying to test via MockMvc. The application contains some database calls and some thridparty api calls, and I want to mock all of them, while testing end to end flow, except thirdparty
This is what I have created -
Controller class
public class PortfolioController {
private final PortfolioService portfolioService;
}
Service Class
public class PortfolioService {
private final PortfolioTransactionRepository portfolioTransactionRepository;
private final AlphavantageService alphavantageService;
}
AlphaVantageService
public class AlphavantageService {
private ApiConfig apiConfig;
private final RestTemplate restTemplate;
public Map<String, List<Candle>> getStockQuotes(List<String> symbols) {
return symbols.stream().collect(Collectors.toMap(symbol -> symbol, symbol -> getQuotes(symbol)));
}
}
Now comes the test -
#ExtendWith(SpringExtension.class)
#WebMvcTest(controllers = PortfolioController.class)
class PortfolioControllerTest {
private List<PortfolioTransaction> transactions;
#MockBean
private AlphavantageService alphavantageService;
#MockBean
private PortfolioService portfolioService;
#Autowired
private PortfolioController portfolioController;
#Autowired
private MockMvc mockMvc;
}
The problem is, when I try to execute any mvc call on server, AlphaVantageService is not injected inside PortfolioService, so till level1, I get the beans injected, but on further levels, I dont get the same.
Is it by design or I am missing something? How should we test such test-cases?
Actually After trying some options here and there, I found a solution.
Just like #MockBean, spring also have a notion called #SpyBean. That solved my problem. So now my test looks like below
#ExtendWith(SpringExtension.class)
#WebMvcTest(controllers = PortfolioController.class)
#MockBeans(value = {#MockBean(AlphavantageService.class),
#MockBean(PortfolioTransactionRepository.class)})
#SpyBeans(value = {#SpyBean(PortfolioService.class)})
class PortfolioControllerTest {
private List<PortfolioTransaction> transactions;
#Autowired
private AlphavantageService alphavantageService;
#Autowired
#SpyBean
private PortfolioService portfolioService;
#Autowired
private PortfolioController portfolioController;
#Autowired
private MockMvc mockMvc;
}
This works like a charm and I can use full fledged dependency Injection in the tests.

#Autowired not working in spring boot

I am working on spring-boot application. In that application #Autowired is not working for some classes.
I have below classes in spring boot application:
#Component
public class SessionUser {
private static final String SESSION_PRINCIPAL = "session.principal";
#Autowired
private HttpSession httpSession;
//more code
}
#RestController
public class RefreshUserPermissionsRequestHandler {
#Autowired
TaskTrigger taskTrigger;
#Autowired
private SessionUser sessionUser;
}
public class LocalFileUserProviderImpl {
#Autowired
private SessionUser sessionUser;
//more code
}
In RefreshUserPermissionsRequestHandler, the SessionUser bean is injecting properly, but in LocalFileUserProviderImpl it's not working. Even I tried to annotate LocalFileUserProviderImpl with #RestController and #Controller but both are not working.
Can anyone help me what is going wrong here? Please let me know if any further info is required.

Spring MVC Repository Factory

Approach 1:
Below are the two service classes which are using same 2 repositories.
#org.springframework.stereotype.Service(value = "userService")
public class UserServiceImpl implements UserService {
#Autowired
private CounterRepository counterRepository;
#Autowired
private SessionRepository sessionRepository;
}
#org.springframework.stereotype.Service(value = "projectService")
public class UserServiceImpl implements UserService {
#Autowired
private CounterRepository counterRepository;
#Autowired
private SessionRepository sessionRepository;
}
So in above classes, as you see that CounterRepository & SessionRepository are using two times each in UserServiceImpl & ProjectServiceImpl services.
Is this is correct approach or I can make One Factory Class and use it to get required repo.
Approach 2:
class RepoFactory{
#Autowired
private CounterRepository counterRepository;
#Autowired
private SessionRepository sessionRepository;
public <T> T getRepo(Class<T> entityClass) {
if (entityClass == CounterRepository .class) {
return (T) appMessageRepository;
} else if (entityClass == SessionRepository.class) {
return (T) auditTrailRepository;
}
}
And I use like below
#org.springframework.stereotype.Service(value = "userService")
public class UserServiceImpl implements UserService {
#Autowired
private RepoFactory repoFactory;
public void someMethod(){
repoFactory.getRepo(CounterRepository.class);
.....
}
public void someMethod2(){
repoFactory.getRepo(SessionRepository.class);
.....
}
}
#org.springframework.stereotype.Service(value = "projectService")
public class ProjectServiceImpl implements ProjectService {
#Autowired
private RepoFactory repoFactory;
public void someMethod(){
repoFactory.getRepo(CounterRepository.class);
.....
}
public void someMethod2(){
repoFactory.getRepo(SessionRepository.class);
.....
}
}
Could you please help me out which approach is better according to performance and memory consumption.
If you don't configure it explictly, all spring beans are singleton, it will not affect memory at all! http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-factory-scopes
The first approach is easy to go, recommended!!
The second approach is totally unnecessary, if you want to, you can always autowire applicationContext and use applicationContext.getBean(Mybean.class)
If you have to save some memory on application start, you can have a look at #Lazy, but from my point of view, it is also not necessary.

Spring Security custom PermissionEvaluator configurations does not work properly

I have a problem with my custom Spring Security PermissionEvaluator. So,
the CustomPermissionEvaluator needs that service to do its work.
#Service
public class MyService {
// methods....
}
And here's the evaluator itself.
public class CustomPermissionEvaluator implements PermissionEvaluator {
private MyService service;
public CustromPermissionEvaluator( MyService service ) {
this.service = service;
}
// hasPermission methods...
}
And here's configurations
#Configuration
#EnableGlobalMethodSecurity( prePostEnabled = true )
public class MethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
#Autowired
private MyService service;
#Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
CustomPermissionEvaluator permissionEvaluator = new CustomPermissionEvaluator( service );
DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
expressionHandler.setPermissionEvaluator( permissionEvaluator );
return expressionHandler;
}
}
So when #PreAuthorize( "hasPermission( ... )" ) should be invoked, nothing happens. But when I put that dependency straight to the CustomPermissionEvaluator's constructor, without ApplicationContext and autowiring, everything works perfect. I have printed service object to the log file and it is not null. So, what is wrong?
I had this same problem and had to use the #Lazy annotation:
#Lazy #Autowired
private MyService service;
It appears the security stuff is bootstrapped before the rest of the Spring config. I guess #Lazy allows a reference to be injected but not actually resolved until used.
After spending hours , this is the only solution solution worked for me. thanks #hvgotcodes.
so what i did is
annotate the CustomPermissionEvaluator with #component.
and annotate MyService with #Lazy #Autowired
#Component
Class CustomPermissionEvaluator {
#Lazy #Autowired
private MyService service;
}
If I user the #Lazy #Autowired in configuration MethodSecurityConfiguration then it does not worked

Resources