Dependcy injection in abstract controller failed - java

I have a base abstract controller class that contains a generic functionality. I also have a set of subclasses.
The abstract class has a property that i would like to Dependency inject. This property is common to all subclasses therefore i don't want it to be set on all the subclasses. but when I call abstract controller's function in subclass ,it turns out to be the property in abstract controller is null. I want to know why and how to fix it.Below is the code snippet:
Abstract Controller:
#Controller
public abstract class WebAPIBaseController {
#Resource
private IPermissionService permissionService;
public void validPermission(int user,String code){
permissionService.valid(user,code);
}
}
SubController
#Controller
#RequestMapping("/order")
public class OrderController extends WebAPIBaseController {
public String XXX(){
validPermission(1,"code");//it will throw a NullPointerException
}
}
besides,if I remove abstract controller(like below example) , it works good.
Remove abstract controller
#Controller
#RequestMapping("/order")
public class OrderController{
#Resource
private IPermissionService permissionService;
public void validPermission(int user,String code){
permissionService.valid(user,code);
}
public String XXX(){
validPermission(1,"code");//it works good
}
}

I don't think you need to inject the permissionService in the subclass, doing this you are hiding that of the superclass.

Have a look at this thread Spring can you autowire inside an abstract class? . You'll also find two other threads in one of the replies about this topic.

You could use #Autowired over the subclass constructor:
public abstract class WebAPIBaseController {
private final IPermissionService permissionService;
public WebAPIBaseController(IPermissionService permissionService) {
this.permissionService = permissionService;
}
public void validPermission(int user, String code){
permissionService.valid(user,code);
}
}
#Controller
#RequestMapping("/order")
public class OrderController extends WebAPIBaseController {
#Autowired
public OrderController(IPermissionService permissionService) {
super(permissionService);
}
public String XXX(){
validPermission(1,"code");//it will throw a NullPointerException
}
}

Related

How to automatically inject implementation based on Generics

I have a Service class defined like this,
#RequiredArgsConstructor
class SomeService<T extends AbstractResponse> {
private final ValidationService<T> validationService;
....
}
And I have two kinds of AbstractResponse, ResponseA and ResponseB and have a validation service defined for both of them.
#Service("aValidationService");
class AValidationService<ResponseA> implements ValidationService<ResponseA> {
....
}
and
#Service("ValidationService");
class BValidationService<ResponseB> implements ValidationService<ResponseB> {
....
}
Right now spring is throwing an error because it's not able to deduce the implementation of ValidationService to use in SomeService as there are two implementations of it. How do I make spring deduce the correct implementation based on the type of AbstractResponse?
Hope that I understood your requirements.
You can not automatically inject, when you have (2) of the same kind. In this case ValidationService.
You could inject #ValidationServiceA, or #ValidationServiceB, or a List<ValidationServiceI> and then return the one you want based on a <T> type you care about:
The solution below highlights that.
The method getGenericParameter() is used to return the <T> parameter. This is to avoid the use of Reflection.
The method methodWhichDeterminesWhichServiceToUseBasedOnResponseType to used to determine which ValidationService to use based on the input that you require.
You can find the complete solution below, including a verification Test.
import org.springframework.stereotype.Service;
#Service
public class ValidationServiceA implements ValidationServiceI<ResponseA>{
#Override public Class<ResponseA> getGenericParameter() {
return ResponseA.class;
}
public void print(){
System.out.println("Service A");
}
}
#Service
public class ValidationServiceB implements ValidationServiceI<ResponseB>{
#Override public Class<ResponseB> getGenericParameter() {
return ResponseB.class;
}
public void print(){
System.out.println("Service B");
}
}
public interface ValidationServiceI<T>{
Class<T> getGenericParameter();
void print();
}
#Service
public class ServiceWhichCallsOthers {
#Autowired
private List<ValidationServiceI> validationServices;
public <T> ValidationServiceI<T> methodWhichDeterminesWhichServiceToUseBasedOnResponseType(T responseType){
Optional<ValidationServiceI> validationServiceSupportingResponse = validationServices.stream().filter(validationServiceI -> validationServiceI.getGenericParameter().equals(responseType)).findFirst();
return validationServiceSupportingResponse.get();
}
public void callValidationServiceA(){
methodWhichDeterminesWhichServiceToUseBasedOnResponseType(ResponseA.class).print();
}
public void callValidationServiceB(){
methodWhichDeterminesWhichServiceToUseBasedOnResponseType(ResponseB.class).print();
}
}
#SpringBootTest
public class ServiceWhichCallsOthersIT {
#Autowired
private ServiceWhichCallsOthers serviceWhichCallsOthers;
#Test
public void validateBasedOnResponseType(){
Assertions.assertEquals(ValidationServiceA.class, serviceWhichCallsOthers.methodWhichDeterminesWhichServiceToUseBasedOnResponseType(ResponseA.class).getClass());
Assertions.assertEquals(ValidationServiceB.class, serviceWhichCallsOthers.methodWhichDeterminesWhichServiceToUseBasedOnResponseType(ResponseB.class).getClass());
serviceWhichCallsOthers.callValidationServiceA();
serviceWhichCallsOthers.callValidationServiceB();
}
}

JMockit Deencapsulation to set multiple fields of parameterized interfaces

I have a service Impl class which has the following 2 fields autowired:
#Service
public class OServiceImpl implements OService {
#Autowired
private MessageSender<EntityA> messageBrokerEventProducerA;
#Autowired
private MessageSender<EntityB> messageBrokerEventProducerB;
I want to write junits where I can mock implementation of above 2 interfaces using jmockit.
public class TestClass {
#Autowired
OService oService;
private static class MockMessageBrokerEventProducerA implements MessageSender<EntityA> {
#Override
public void sendMessage(EntityA message) {
System.out.println("mock A called");
}
}
private static class MockMessageBrokerEventProducerB implements MessageSender<EntityB>{
#Override
public void sendMessage(EntityB message) {
System.out.println("mock B called");
}
}
private MessageSender<A> mockMessageBrokerEventProducerA;
private MessageSender<B> mockMessageBrokerEventProducerB;
#BeforeEach
public void mockSetuUp() {
mockMessageBrokerEventProducerB = new MockMessageBrokerEventProducerB();
mockMessageBrokerEventProducerA = new MockMessageBrokerEventProducerA();
Deencapsulation.setField(oService, mockMessageBrokerEventProducerA);
Deencapsulation.setField(oService, mockMessageBrokerEventProducerB);
}
The above set up does not work, it throws an error :
java.lang.IllegalArgumentException: More than one instance field to which a value of type ....can be assigned exists in the class.
It works well whenever there is only one interface autowired in impl class and mocking that one. Above error is thrown whenever there is autowiring of more than 1 interface (same interface with generics) in impl class. How should I solve this ?
I solved it with following:
Deencapsulation.setField(oService, "messageBrokerEventProducerA",
mockMessageBrokerEventProducerA);

How to get Service from another class?

I'm creating telegram bot with Spring-Boot. I have AscractState class:
public abstract class AbstractState {
boolean isInputIndeed = Boolean.FALSE;
public abstract void handleInput(BotContext context);
//another parts
}
And there is extend which is
#Slf4j
public class AgeInputState extends AbstractState {
#Autowired
ClientService clientService;
public AgeInputState(boolean isInputIndeed) {
super(isInputIndeed, State.AGE_INPUT);
}
#Override
public void handleInput(BotContext context) {
context.getClient().setAge(Integer.parseInt(context.getInput()));
clientService.updateUser(context.getClient());
}
}
But i have touble with ClientService. Which annotations on class i need to add for autowiring this fiels?
Since this class has a constructor which only accepts a boolean, I assume you're needing to make lots of them.
Spring won't know you're wanting to load these as spring beans if you call this constructor directly. So creating these through a factory of some sort would be one way to go. Something like:
#Configuration
public class AgeInputStateFactory {
private #Autowired ClientService clientService;
#Bean
#Scope("prototype") // Makes a new one each time...
public AgeInputState create(final boolean isInputIndeed) {
return new AgeInputState(this.clientService, isInputIndeed);
}
}
Along with a newly designed AgeInputState constructor which also takes the ClientService field.
public class AgeInputState extends AbstractState {
private final ClientService clientService;
// Package private constructor so that no one outside
// of this package will call it. This means you can
// (try your best to) limit the construction to the
// factory class.
AgeInputState(final ClientService clientService,
final boolean isInputIndeed) {
super(isInputIndeed, State.AGE_INPUT);
this.clientService = clientService;
}
}
And then all you would do is wherever you need to create these AgeInputState Objects, you would #Autowire the AgeInputStateFactory instance, and call the create method whenever you need one.

Passing variable from #Controller to #ControllerAdvice in SpringMVC

I created #ControllerAdvice that has to set me some model attribute.
#ModelAttribute
public void globalAttributes(Model model) {
model.addAttribute("pageId", PAGE_ID);
}
This is a generic example of what I need, and PAGE_ID represents some variable that actual controller has to set. Since #ControllerAdvice is running before controller, how can I declare this variable and use it in Advice? If that's even possible.
I think a better solution would been using some kind of abstract-class-pattern for your controller
public abstract class AbstractController {
#ModelAttribute
public void globalAttributes(Model model) {
model.addAttribute("pageId", getPageId());
}
abstract String getPageId();
}
public class MyController extends AbstractController {
#Override
public String getPageId() {
return "MyPageID"
}
//..your controller methods
}

PostContruct annotation on superclass

I want to refactor a method annotated with #PostContruct in a common class of all my controller.
public abstract class Controller {
#PostConstruct
protected void PostContruct() { ..}
}
public class AuthController extends Controller {}
public class CartController extends Controller {}
But spring doesn't seems to call my inherit method. What is the pattern to use in this situation ?
This works with Spring 4.2.0 and Spring Boot 1.2.5
public abstract class AbstractController {
#PostConstruct
protected void postConstruct() {
System.out.println("post construct");
}
}
#Controller
public class ConcreteController extends AbstractController {
}
It also works if you mark the method as abstract, keep the #PostConstruct in the parent and implement it in the child.
It does NOT work if #Controller is in the parent.

Categories

Resources