简体   繁体   中英

Constructor Dependency Injection in Spring with abstract classes

I want to use Constructor Dependency Injection in my application.

I have created this controller:

public abstract class BonanzaCloudController {


    protected final UserService userService;

    protected BonanzaCloudController(UserService userService) {
        this.userService = userService;
    }

...
}

and this

@Controller
public class AppErrorController extends BonanzaCloudController implements ErrorController {

    private final ErrorAttributes errorAttributes;    

    private final EmailService emailService;

    public AppErrorController(ErrorAttributes errorAttributes, EmailService emailService) {
        this.errorAttributes = errorAttributes;
        this.emailService = emailService;
    }
...
}

but I have this compilation error:

There is no default constructor available in BonanzaCloudController

AppErrorController is a subclass of BonanzaCloudController , so the constructor of AppErrorController has to call the constructor of BonanzaCloudController (by the rules defined by java).

Therefore the constructor of AppErrorController has to be

public AppErrorController(UserService userService, ErrorAttributes errorAttributes, EmailService emailService) {
    super(userService);
    this.errorAttributes = errorAttributes;
    this.emailService = emailService;
}

Although the userService doesn't have to be the first parameter, only the super() call has to be first.

This is not a Spring DI issue but an issue with your class hierarchy. To construct a AppErrorController , the JVM will need to construct a basic instance of its superclass but you have not provided a way for it to do that. You will need to create a default constructor or explicitly call super(...) and pass through an instance of UserService too.

This has nothing to do with Spring. It's Java.

You have base class BonanzaCloudController . You declare constructor there with 1 argument, means no-arg constructor won't be there anymore:

protected BonanzaCloudController(UserService userService) { }

Now you have a child class:

public class AppErrorController extends BonanzaCloudController {

    public AppErrorController(ErrorAttributes errorAttributes, EmailService emailService) {
        // this is how your constructor looks, super is implicit there
        // means that you don't need to add it, it will be there anyway.
        super();
        this.errorAttributes = errorAttributes;
        this.emailService = emailService;
    }

}

There is my small comment in the code above. When an instance of a child class is created - base class constructor is called first to instantiate the "base" part of the object. In our case, it is super(); and here it refers to no-arg constructor in the base class (because it is just super() , no args) and you simply don't have it in your base class.

So to fix this, you basically have 2 options. First, you can call your constructor with param which you have in your base class:

public AppErrorController(ErrorAttributes errorAttributes, EmailService emailService) {
    // the first call should be an explicit call of super(...)
    // as a param you need instance of UserService
    super(userService);
    this.errorAttributes = errorAttributes;
    this.emailService = emailService;
}

Or you can add no-arg constructor to your base class and then you don't need to call super at all.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM