Create a bean from PathVariable in Spring - java

In my controller, i get a Pathvariable called "realm".
I want to use this variable in service layer. I don't want to set realm in every method.
This is my controller:
#RestController
#RequestMapping("/user-managment/{realm}/")
#PreAuthorize("#someBean.test(#requestHelper.getPathVariableByName('realm'))")
public class KeycloackUserController {
#Autowired
private KeyCloakAdminAPIService keyCloakAdminAPIService;
As you can see, i get a "realm" in request. I tried to initialize a new bean with that variable to use it in service but it didn't work.
This is my service:
#Service
public class KeyCloakAdminAPIService {
#Autowired
#Value("${someBean.test}")
private String realm;
I get an error:
Error creating bean with name 'keycloackUserController': Unsatisfied dependency expressed through field 'keyCloakAdminAPIService';
Do you have any advice for this problem?

Related

How to initialize bean method defined in Main class into test context

I have created a bean method in the main class:
#SpringBootApplication
#EnableScheduling
public class SpringApplication{
#Bean
Public String getCronValue(ServiceImpl service){
return service.getConfig().get("cron duration");
}
}
using this bean in a scheduled task:
#Component
public Class MySch{
#Scheduled(cron="#{getCronValue}")
public void schedulerMethod(){
//Do something
}
}
Now the problem is when I try to run JUnit tests #Bean GetCronValue is not initialized in test context and #Scheduled annotation throws an exception:
Update:-
It throws an exception:-
BeanCreationException: Error creating bean with name
'SchedulerMethod' : Initialization of bean failed; nested
exception is ' org. springframework.beans.
factory.Beanexpressio exception: Expression parsing
failed; nested exception is org. springframework.
expression.spel.SpelEvaluationException: EL1021E: A
problem occurred whilst attempting to access the
property ' getCronValue' : Error creating bean with name
'getCronValue' : Unsetisfied dependency expressed
through method 'getCronValue' parameter 0; nested
exception is org. springframework. beans. factory.
NoSuchBeanDefinitionException: No qualifying bean of
type 'com.pkg.service.ServiceImpl' available: expected at
least 1 bean which qualifies as a autowire candidate.
Dependemcy annotations: {}'
My Controller test class looks like:-
#Transactional
public class ControllerTest{
#MockBean
private Service service;
.
.
// test cases
}
How to resolve this issue.
I assume that you're using #SpringBootTest annotation.
When you test a Controller you may want narrow the tests to only the web layer by using #WebMvcTest. Any other dependencies required by the controller will be then mocked using #MockBean.
When #WebMvcTest is used Spring Boot instantiates only the web layer rather than the whole context. In an application with multiple controllers, you can even ask for only one to be instantiated for example.
#WebMvcTest(controllers =Controller.class)
public class ControllerTest{
#MockBean
private Service service;
#Autowired
private MockMvc mockMvc;
// test cases
}
I noticed that you have the #Transactional annotation in your example. This can indicate that you maybe giving too match responsibilities to your controller and may consider passing Database access related logic to a service/repostory/DAO
See https://spring.io/guides/gs/testing-web/

If an instance is shown in both autowired and bean, which one Spring will use

Originally, there was a service instance to access the database and now we want to add a readonly instance. So I add the serviceReadonly in my configuration.
#Configuration
public class Config {
#Bean Service service() {...};
#Bean Service serviceReadonly() {...};
#Bean Proxy proxy() {return new Proxy(serviceReadonly())}; // replace the original Proxy(service())
}
But, the service is also autowired to Proxy
#Component
public class Proxy {
#Autowired
public Proxy(Service service) {this.service = service;}
}
I am confused which Service is injected in my API? service or serviceReadonly?
#Component
public class API {
#Autowired
public API(Proxy proxy) {this.proxy = proxy;}
}
The Proxy and API classes are in another shared library and avoiding change to the library is preferred. Also, the service is autowired to other components.
Short answer: #Bean Service service()
Explanation: Excerpt from the Spring documentation here
Autowiring by property name. Spring looks for a bean with the same
name as the property that needs to be autowired. For example, if a
bean definition is set to autowire by name, and it contains a master
property (that is, it has a setMaster(..) method), Spring looks for a
bean definition named master, and uses it to set the property.
I assume it will be #Bean Service service() because the Spring would find the bean with same name as the property i.e. Service as defined in official Spring guide.
You may also need to look into #Qualifier annotation. It is because if there is not exactly one bean of the constructor argument type in the container, a fatal error is raised, as mentioned in Spring documentation here. Have you checked if you receive this error of NoUniqueBeanDefinitionException? In that case you can use #Qualifer annotation to specify the bean you want.

#RefreshScope can't get along with #Bean

I have a controller which need refresh config from config server so I add #RefreshScope on it. Meanwhile this controller need to calling a backend API so that I defined the restTemplate Bean. But once I start this application, exception occur. Can anyone tell me why these two annotation make circulate reference?
Error: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'scopedTarget.frontEndApplication':
Unsatisfied dependency expressed through field 'restTemplate'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'restTemplate': Requested bean is currently in creation: Is there an unresolvable circular reference?
#SpringBootApplication
#RestController
#EnableDiscoveryClient
#RefreshScope
public class FrontEndApplication {
#Value("${msg:Hello default}")
private String message;
public static void main(String[] args) {
SpringApplication.run(FrontEndApplication.class, args);
}
#Bean
RestTemplate restTemplate() {
return new RestTemplate();
}
#Autowired
RestTemplate restTemplate;
}
First, don't put #RefreshScope on the controller. Typically you'd want to do it in a class that stores state. If it's a configuration property it's better to use a #ConfigurationProperty annotation on a POJO and call #EnableConfigurationProperties.
Also your main class does everything, can you please just separate it into separate classes and try again? It's not a good idea to have your main class also be a controller, repository and a service at the same time.

two conversionService bean created

I am getting an error while trying to up my application
Description:
Field conversionService in com.profectus.dashboard.service.impl.DashBoardSettingsServiceimpl required a single bean, but 2 were found:
- mvcConversionService: defined by method 'mvcConversionService' in class path resource [org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfiguration.class]
- defaultConversionService: defined by method 'defaultConversionService' in class path resource [org/springframework/data/rest/webmvc/config/RepositoryRestMvcConfiguration.class]
Action:
Consider marking one of the beans as #Primary, updating the consumer to accept multiple beans, or using #Qualifier to identify the bean that should be consumed
Why 2 beans are created and how to keep only one converter, I just want only spring core converter who can convert entity to pojo or pojo to entity.
I am stuck because of this issue, any lead would be helpful.
Service class code:-
import org.springframework.core.convert.ConversionService;
//other imports
#Service
public class DashBoardSettingsServiceimpl implements DashBoardSettingsService {
#Autowired
private DashBoardSettingJpaRepository dashBoardSettingRepo;
#Autowired
private ConversionService conversionService;
#Override
public DashBoardSettingResponse save(UserInfo userInfo, DashBoardSettingRequest request) {
//other coded
DashBoardSettigEntity entity = conversionService.convert(request.getDashBoardSetting(),
DashBoardSettigEntity.class);
DashBoardSettigEntity entityRetrieve = dashBoardSettingRepo.save(entity);
DashBoardSetting setting = conversionService.convert(entityRetrieve, DashBoardSetting.class);
DashBoardSettingResponse response = new DashBoardSettingResponse();
response.addDashBoardSetting(setting);
return response;
}
}
Autowire type DefaultConversionService instead of ConversionService
Seems like it has something to do with spring data rest having its own ConversionService instance.
Can you try this:
#Autowired #Qualifier("mvcConversionService") ConversionService conversionService;
It worked for me.
Don't forget to add your converters to a WebMvcConfigurer implementation.

Call service method from non controller class

In HomeController i am doing the following
#Controller
public class HomeController {
#Autowired
private EUserService userDao;
#RequestMapping(value = "/")
public String setupForm(Map<String, Object> map) {
User user=(User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
EUser currentUser = userDao.findUserByName(user.getUsername());
System.out.println(currentUser.getUserName());
}
}
It works fine and shows me the output properly. Now If I do the same thing in a non controller type class like following
public class Utility {
#Autowired
private EUserService userDao;
public void getLoggedUser() {
User user = (User) SecurityContextHolder.getContext()
.getAuthentication().getPrincipal();
EUser currentUser = (EUser) userService.findUserByName(user
.getUsername());
System.out.println(currentUser.getUserName());
}
}
it gives me the following NullPointerException
SEVERE: Servlet.service() for servlet [spring] in context with path [/Ebajar] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause
java.lang.NullPointerException
How to fix this??
The problem is not that you are calling this not from controller. The problem is that your are calling this from class that is not managed by Spring, so the userDao is not injected here.
It think that "right" solution is to turn your utility to Spring bean, e.g. marking it as #Service and call it via Spring. Alternatively you can retrieve it programmatically using ApplicationContext.getBean() (see here for details)
you should declare/annotate your Utility class as a spring bean so that let other bean get injected. in this case, it is EUserService
try adding #Component to your Utility class. I assumed your package is involved by spring annotated bean scanning settings.
Only Spring managed bean can autowire an instance. Read here
You annotate Utility with #Component.

Categories

Resources