1

I'm making a banking application where a user can create a bank account, this account can be a savings account with a monthly income or a current account with a monthly upkeep, the classes of both types of account inherit a regular account class.

Is it possible to make a API endpoint "overload" with the same method (Post) and endpoint ("/account") that can receive both a SavingsAccount or a CurrentAccount Object as its RequestBody?

New contributor
user31885720 is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
0

1 Answer 1

0

No, Java allows it, but @RestController does not.

While this is valid Java code...

    @PostMapping("/account")
    public ResponseEntity<Void> postAccount(SavingsAccount account) {
        log.info("savings account posted");
        // process savings account
        return ResponseEntity.ok().build();
    }

    @PostMapping("/account")
    public ResponseEntity<Void> postAccount(CurrentAccount account) {
        log.info("current account posted");
        // process current account
        return ResponseEntity.ok().build();
    }

...you will get an error like this at startup, because you can not have two methods with the same path and method:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'requestMappingHandlerMapping' defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]: Ambiguous mapping. Cannot map 'demoController' method 
org.example.restdemo.DemoController#postAccount(SavingsAccount)
to {POST [/account]}: There is already 'demoController' bean method
...
Caused by: java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'demoController' method 
org.example.restdemo.DemoController#postAccount(SavingsAccount)
to {POST [/account]}: There is already 'demoController' bean method
org.example.restdemo.DemoController#postAccount(CurrentAccount) mapped.

What you can do is use inheritance, meaning you let your method receive a common base class of SavingsAccount and BankAccount and add a discriminator property, so Spring is able to use the corresponding type automatically (it won't work without it). This is equivalent to using oneOf with discriminator in an OpenAPI definition.

A minimal example for the base class with an accountType discriminator could look like this (the annotations are from package com.fasterxml.jackson.annotation):

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "accountType")
@JsonSubTypes({
  @JsonSubTypes.Type(value = CurrentAccount.class, name = "currentAccount"),
  @JsonSubTypes.Type(value = SavingsAccount.class, name = "savingsAccount")
})
public interface BaseAccount {
    public String getAccountType();
}

Your SavingsAccount and BankAccount would need to have implements BaseAccount.

And a minimal example of the corresponding postAccount method:

    @PostMapping(value = "/account", consumes = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<Void> postAccount(BaseAccount account) {
        if (account instanceof SavingsAccount savingsAccount) {
            // process savingsAccount
        }
        else if (account instanceof CurrentAccount currentAccount) {
            // process currentAccount
        }
        else {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST);
        }
        return ResponseEntity.ok().build();
    }

However, personally, I do not recommend to do it that way. It bears the risk of accidental invalid submissions from your API consumers, if validation is not implemented carefully. Since your API consumers should know which account type they want to submit, they should be able to call a distinct endpoint /savingsAccount or /currentAccount respectively.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.