I am working on a bank application using Spring Boot 2.4.0 and Gradle 6.7 and I want to document and test my API using Swagger 3.0.0. I have four controllers for now: EmployeeController, ClientController, BankAccountController, TransactionController. Every controller has 5 end points:
GET /{entities}
GET /{entities}/{id}
POST /{entities}
PUT /{entities}/{id}
DELETE /{entities}/{id}
where {entities} is used here as a placeholder for the entities the specific controller is responsible for: employees, clients, accounts, transactions, respectively.
The problem is that Swagger displays all the 5 endpoints only for BankAccountsController. For the other controllers only GET /{entities}, POST /{entities}, PUT /{entities}/{id} are displayed. Endpoints GET /{entities}/{id}, DELETE /{entities}/{id} are missing, despite of the fact all controllers are implemented analogically. I tested endpoints in Postman and they work properly.
Here is the working BankController:
#Slf4j
#RestController
#RequestMapping("/accounts")
#Api(value = "Operations related to bank accounts", tags = {"Bank Accounts"})
#SwaggerDefinition(tags = {#Tag(name = "Bank Accounts", description = "Operations related to bank accounts") })
public class BankAccountController {
private final BankAccountService bankAccountService;
public BankAccountController(BankAccountService bankAccountService) {
this.bankAccountService = bankAccountService;
}
#ApiOperation(
value="Find a bank account by id",
notes = "Provide an id to lookup specific bank account from the database")
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Success"),
#ApiResponse(code = 404, message = "Not found", response = ErrorStub.class),
#ApiResponse(code = 500, message = "Server failure", response = ErrorStub.class)
})
#GetMapping(value = "/{id}", produces = {"application/json"})
public ResponseEntity<BankAccount> getBankAccountById(#PathVariable Long id) {
return ResponseEntity.of(bankAccountService.getBankAccountById(id));
}
#ApiOperation(
value="Retrieve all bank accounts",
notes = "Used to fetch all bank accounts from the database")
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Success"),
#ApiResponse(code = 404, message = "Not found", response = ErrorStub.class),
#ApiResponse(code = 500, message = "Server failure", response = ErrorStub.class)
})
#GetMapping(value = "/", produces = {"application/json"})
public ResponseEntity<List<BankAccount>> getAll() {
return ResponseEntity.of(
Optional.of(bankAccountService.getAll()));
}
#ApiOperation(
value="Add a new bank account",
notes = "Used to insert new bank account in the database")
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Success"),
#ApiResponse(code = 404, message = "Not found", response = ErrorStub.class),
#ApiResponse(code = 500, message = "Server failure", response = ErrorStub.class)
})
#PostMapping(value = "/", consumes = {"application/json"}, produces = {"application/json"})
public ResponseEntity<BankAccount> addBankAccount(#RequestBody BankAccount newaccount) {
return ResponseEntity.of(
Optional.of(bankAccountService.save(newaccount)));
}
#ApiOperation(
value="Modify a bank account",
notes = "Used to replace an old bank account with a new one with a certain id in the database")
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Success"),
#ApiResponse(code = 404, message = "Not found", response = ErrorStub.class),
#ApiResponse(code = 500, message = "Server failure", response = ErrorStub.class)
})
#PutMapping(value = "/{id}", consumes = {"application/json"}, produces = {"application/json"})
public ResponseEntity<BankAccount> mofifyBankAccount(#RequestBody BankAccount newAccount, #PathVariable Long id) {
return ResponseEntity.of(
bankAccountService.getBankAccountById(id)
.map(account -> {
account.setAccountNumber(newAccount.getAccountNumber());
account.setIban(newAccount.getIban());
account.setType(newAccount.getType());
account.setCurrency(newAccount.getCurrency());
account.setBalance(newAccount.getBalance());
return bankAccountService.save(account);
}));
}
#ApiOperation(
value="Delete a bank account with indicated id",
notes = "Used to delete a bank account by id from the database")
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Success"),
#ApiResponse(code = 404, message = "Not found", response = ErrorStub.class),
#ApiResponse(code = 500, message = "Server failure", response = ErrorStub.class)
})
#DeleteMapping(value = "/{id}", produces = {"application/json"})
public ResponseEntity<BankAccount> deleteBankAccount(#PathVariable Long id) {
return ResponseEntity.of(
bankAccountService.deleteBankAccount(id));
}
}
Here are the other 3 controllers:
EmployeeController:
#Slf4j
#RestController
#RequestMapping("/employees")
#Api(value ="Operations related to employees", tags = {"Employees"})
#SwaggerDefinition(tags = {#Tag(name = "Employees", description = "Operations related to employees")})
public class EmployeeController {
private final EmployeeService employeeService;
#Autowired
public EmployeeController(EmployeeService employeeService) {
this.employeeService = employeeService;
}
#ApiOperation(value="Find an employee by id",
notes = "Provide and id to lookup specific employee from database")
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Success"),
#ApiResponse(code = 404, message = "Not found", response = ErrorStub.class),
#ApiResponse(code = 500, message = "Server failure", response = ErrorStub.class)
})
#GetMapping(value = "/{id}", produces = {"application/json"})
public ResponseEntity<Employee> getEmployeeById(#PathVariable Long id) {
return ResponseEntity.of(employeeService.getEmployeeById(id));
}
#ApiOperation(
value="Retrieve all employees",
notes = "Used to fetch all employees from the database")
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Success"),
#ApiResponse(code = 404, message = "Not found", response = ErrorStub.class),
#ApiResponse(code = 500, message = "Server failure", response = ErrorStub.class)
})
#GetMapping(value = "/", produces = {"application/json"})
public ResponseEntity<List<Employee>> getAll() {
return ResponseEntity.of(Optional.of(employeeService.getAll()));
}
#ApiOperation(value="Add a new employee", notes = "Used to insert new employee in the database")
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Success"),
#ApiResponse(code = 404, message = "Not found", response = ErrorStub.class),
#ApiResponse(code = 500, message = "Server failure", response = ErrorStub.class)
})
#PostMapping(value = "/", consumes = {"application/json"}, produces = {"application/json"})
public ResponseEntity<Employee> addEmployee(#RequestBody Employee newEmployee) {
return ResponseEntity.of(
Optional.of(employeeService.save(newEmployee)));
}
#ApiOperation(
value="Modify an employee",
notes = "Used to replace an old employee with a new one with a certain id in the database ")
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Success"),
#ApiResponse(code = 404, message = "Not found", response = ErrorStub.class),
#ApiResponse(code = 500, message = "Server failure", response = ErrorStub.class)
})
#PutMapping(value = "/{id}", consumes = {"application/json"}, produces = {"application/json"})
public ResponseEntity<Employee> modifyEmployee(#RequestBody Employee newEmployee, #PathVariable Long id) {
return ResponseEntity.of(
employeeService.getEmployeeById(id)
.map(employee -> {
employee.setName(newEmployee.getName());
employee.setMidName(newEmployee.getMidName());
employee.setSurname(newEmployee.getSurname());
employee.setPhone(newEmployee.getPhone());
employee.setAddress(newEmployee.getAddress());
employee.setPosition(newEmployee.getPosition());
employee.setDateHired(newEmployee.getDateHired());
employee.setStartOfExperience(newEmployee.getStartOfExperience());
return employeeService.save(newEmployee);
}));
}
#ApiOperation(
value="Delete an employee with indicated id",
notes = "Used to delete an employee by id from the database")
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Success"),
#ApiResponse(code = 404, message = "Not found", response = ErrorStub.class),
#ApiResponse(code = 500, message = "Server failure", response = ErrorStub.class)
})
#DeleteMapping(value = "/{id}", produces = {"application/json"})
public ResponseEntity<Employee> deleteEmployee(#PathVariable Long id) {
return ResponseEntity.of(
employeeService.deleteEmployee(id));
}
}
ClientController:
#Slf4j
#RestController
#RequestMapping("/clients")
#Api(value = "Operations related to clients", tags = {"Clients"})
#SwaggerDefinition(tags = {#Tag(name = "Clients", description = "Operations related to clients") })
public class ClientController {
private final ClientService clientService;
#Autowired
public ClientController(ClientService clientService) {
this.clientService = clientService;
}
#ApiOperation(
value="Find a client by id",
notes = "Provide and id to lookup specific client from the database")
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Success"),
#ApiResponse(code = 404, message = "Not found", response = ErrorStub.class),
#ApiResponse(code = 500, message = "Server failure", response = ErrorStub.class)
})
#GetMapping(value = "/{id}", produces = {"application/json"})
public ResponseEntity<Client> getClientById(#PathVariable Long id) {
return ResponseEntity.of(
clientService.getClientById(id));
}
#ApiOperation(
value="Retrieve all clients",
notes = "Used to fetch all clients from the database")
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Success"),
#ApiResponse(code = 404, message = "Not found", response = ErrorStub.class),
#ApiResponse(code = 500, message = "Server failure", response = ErrorStub.class)
})
#GetMapping(value = "/", produces = {"application/json"})
public ResponseEntity<List<Client>> getAll() {
return ResponseEntity.of(
Optional.of(clientService.getAll()));
}
#ApiOperation(
value="Add a new client",
notes = "Used to insert new client in the database")
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Success"),
#ApiResponse(code = 404, message = "Not found", response = ErrorStub.class),
#ApiResponse(code = 500, message = "Server failure", response = ErrorStub.class)
})
#PostMapping(value = "/", consumes = {"application/json"}, produces = {"application/json"})
public ResponseEntity<Client> addCustomer(#RequestBody Client newClient) {
return ResponseEntity.of(
Optional.of(clientService.save(newClient)));
}
#ApiOperation(
value="Modify a client",
notes = "Used to replace an old client with a new one with a certain id in the database ")
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Success"),
#ApiResponse(code = 404, message = "Not found", response = ErrorStub.class),
#ApiResponse(code = 500, message = "Server failure", response = ErrorStub.class)
})
#PutMapping(value = "/{id}", consumes = {"application/json"}, produces = {"application/json"})
public ResponseEntity<Client> modifyClient(#RequestBody Client newClient, #PathVariable Long id) {
return ResponseEntity.of(
clientService.getClientById(id)
.map(customer -> {
customer.setName(newClient.getName());
customer.setMidName(newClient.getMidName());
customer.setSurname(newClient.getSurname());
customer.setAccountManager(newClient.getAccountManager());
customer.setAddress(newClient.getAddress());
customer.setEmail(newClient.getEmail());
customer.setIdCardNumber(newClient.getIdCardNumber());
customer.setIdCardIssueDate(newClient.getIdCardIssueDate());
customer.setDebitCardNumber(newClient.getDebitCardNumber());
customer.setCreditCardNumber(newClient.getDebitCardNumber());
return clientService.save(customer);
}));
}
#ApiOperation(value="Delete a client with indicated id.",
notes = "Used to delete a client by id from the database")
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Success"),
#ApiResponse(code = 404, message = "Not found", response = ErrorStub.class),
#ApiResponse(code = 500, message = "Server failure", response = ErrorStub.class)
})
#DeleteMapping(value = "/{id}", produces = {"application/json"})
public ResponseEntity<Client> deleteClient(#PathVariable Long id) {
return ResponseEntity.of(
clientService.deleteClient(id));
}
}
and the TransactionController:
#Slf4j
#RestController
#RequestMapping("/transactions")
#Api(value = "Operations related to financial transactions", tags = {"Transactions"})
#SwaggerDefinition(tags = {#Tag(name = "Transactions", description = "Operations related to financial transactions")})
public class TransactionController {
private TransactionService transactionService;
#Autowired
public TransactionController(TransactionService transactionService) {
this.transactionService = transactionService;
}
#ApiOperation(
value="Find a financial transaction by id",
notes = "Provide and id to lookup specific financial transaction from the database")
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Success"),
#ApiResponse(code = 404, message = "Not found", response = ErrorStub.class),
#ApiResponse(code = 500, message = "Server failure", response = ErrorStub.class)
})
#GetMapping(value = "/{id}", produces = {"application/json"})
public ResponseEntity<Transaction> getTransactionById(#PathVariable Long id) {
return ResponseEntity.of(transactionService.getTransactionById(id));
}
#ApiOperation(
value="Retrieve all financial transactions",
notes = "Used to fetch all financial transactions from the database")
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Success"),
#ApiResponse(code = 404, message = "Not found", response = ErrorStub.class),
#ApiResponse(code = 500, message = "Server failure", response = ErrorStub.class)
})
#GetMapping(value = "/", produces = {"application/json"})
public ResponseEntity<List<Transaction>> getAll() {
return ResponseEntity.of(
Optional.of(transactionService.getAll()));
}
#ApiOperation(
value="Add a new financial transaction",
notes = "Used to insert new financial transaction in the database")
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Success"),
#ApiResponse(code = 404, message = "Not found", response = ErrorStub.class),
#ApiResponse(code = 500, message = "Server failure", response = ErrorStub.class)
})
#PostMapping(value = "/", consumes = {"application/json"}, produces = {"application/json"})
public ResponseEntity<Transaction> addTransaction(#RequestBody Transaction newTransaction) {
return ResponseEntity.of(
Optional.of(transactionService.save(newTransaction)));
}
#ApiOperation(
value="Modify a financial transaction",
notes = "Used to replace an old financial transaction with a new one with a certain id in the database ")
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Success"),
#ApiResponse(code = 404, message = "Not found", response = ErrorStub.class),
#ApiResponse(code = 500, message = "Server failure", response = ErrorStub.class)
})
#PutMapping(value = "/{id}", consumes = {"application/json"}, produces = {"application/json"})
public ResponseEntity<Transaction> modifyTransaction(#RequestBody Transaction newTransaction, #PathVariable Long id) {
return ResponseEntity.of(
transactionService.getTransactionById(id)
.map(transaction -> {
transaction.setAmount(newTransaction.getAmount());
transaction.setSender(newTransaction.getSender());
transaction.setReceiver(newTransaction.getReceiver());
return transactionService.save(transaction);
}));
}
#ApiOperation(
value="Delete a financial transaction with indicated id",
notes = "Used to delete a financial transaction by id from the database")
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Success"),
#ApiResponse(code = 404, message = "Not found", response = ErrorStub.class),
#ApiResponse(code = 500, message = "Server failure", response = ErrorStub.class)
})
#DeleteMapping(value = "/{id}", produces = {"application/json"})
public ResponseEntity<Transaction> deleteTransaction(#PathVariable Long id) {
return ResponseEntity.of(transactionService.deleteTransaction(id));
}
}
I checked if everything is analogical really and I could not find a solution, searched in google as well but there found mostly questions for non-working Swagger UI, not for partially missing endpoints.
Here is my Swagger configurstion class:
#Import({SpringDataRestConfiguration.class, BeanValidatorPluginsConfiguration.class})
#Configuration
public class Swagger2Config {
private static final Set<String> DEFAULT_PRODUCES_AND_CONSUMES =
new HashSet<>(Arrays.asList("application/json"));
#Bean
public Docket swaggerConfiguration() {
return new Docket(DocumentationType.SWAGGER_2)
.host("http://localhost:8080")
.directModelSubstitute(LocalDate.class, Date.class)
.pathProvider(new DefaultPathProvider())
.select()
.apis(RequestHandlerSelectors.basePackage("com.example.bank.controller"))
.paths(PathSelectors.any())
.build()
.pathMapping("/")
.genericModelSubstitutes(ResponseEntity.class)
.apiInfo(apiDetails())
.produces(DEFAULT_PRODUCES_AND_CONSUMES)
.consumes(DEFAULT_PRODUCES_AND_CONSUMES);
}
private ApiInfo apiDetails() {
return new ApiInfoBuilder()
.title("Bank API")
.description("Sample API for Bank Application")
.termsOfServiceUrl("Free to use")
.version("1.0")
.contact(new Contact("John Dooe", "http://wwww.example.com", "rosen.hristov#example.com"))
.license("API License")
.licenseUrl("http://wwww.example.com")
.build();
}
}
My Gradle dependencies:
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.data:spring-data-rest-hal-explorer'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework:spring-core'
implementation 'javax.validation:validation-api'
implementation 'org.projectlombok:lombok'
implementation 'io.springfox:springfox-boot-starter:3.0.0'
implementation 'io.springfox:springfox-bean-validators:3.0.0'
implementation 'io.springfox:springfox-swagger-ui:3.0.0'
implementation 'org.springframework.plugin:spring-plugin-core:2.0.0.RELEASE'
implementation 'javax.activation:activation:1.1.1'
implementation 'javax.xml.bind:jaxb-api:2.3.1'
implementation 'org.glassfish.jaxb:jaxb-core:3.0.0-M5'
implementation 'javax.xml:jaxb-impl:2.1'
implementation 'org.springframework:spring-context'
implementation 'org.springframework.boot:spring-boot-devtools'
implementation "com.oracle.database.jdbc:ojdbc8-production:19.7.0.0",
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
annotationProcessor 'org.projectlombok:lombok'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
}
Here are screenshots from Swagger:
Bank Accounts Controller endpoints
Clients Controller endpoints
Employees Controller endpoints
Transactions Controller endpoints
Have you ever come upon such an issue and could someone help me, please?
Actually, I just solved the problem. I renamed path variables {id} in all endpoints with such a variable to {<entity>Id}, e.g. {clientId}, {employeeId}, etc. When the names are different for the respective entity Swagger handles everything successfully.
Interestingly, this problem existed just for GET (getById) and DELETE endpoints. The PUT endpoint was visualized successfully in all controllers although it also used an {id} path variable in all controllers.
I am using Spring Boot and Spring Rest Example. In this example, I am passing custom header, if that value is valid, endpoint gets called successfully, if custom header value is not correct then I get below response, which I want to wrap into show it to the enduser using #ControllerAdvice ExceptionHandler.
Note: I went through Spring mvc - How to map all wrong request mapping to a single method, but here in my case I am taking decision based on CustomHeader.
{
"timestamp": "2020-01-28T13:47:16.201+0000",
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/employee-data/employee-codes"
}
Controller
#Operation(summary = "Find Employee")
#ApiResponses(value = { #ApiResponse(code = 200, message = "SUCCESS"),
#ApiResponse(code = 500, message = "Internal Server Error") })
#Parameter(in = ParameterIn.HEADER, description = "X-Accept-Version", name = "X-Accept-Version",
content = #Content(schema = #Schema(type = "string", defaultValue = "v1",
allowableValues = {HeaderConst.V1}, implementation = Country.class)))
#GetMapping(value = "/employees/employee-codes", headers = "X-Accept-Version=v1")
public ResponseEntity<Employees> findEmployees(
#RequestParam(required = false) String employeeCd,
#RequestParam(required = false) String firstName,
#RequestParam(required = false) Integer lastName) {
Employees response = employeeService.getEmployees(employeeCd, firstName, lastName);
return new ResponseEntity<>(response, HttpStatus.OK);
}
I've implemented HttpMessageNotReadableException and HttpMediaTypeNotSupportedException and NoHandlerFoundException, but still not able to wrap this error.
Any suggestions?
I was able to find the solution for it.
# Whether a "NoHandlerFoundException" should be thrown if no Handler was found to process a request.
spring.mvc.throw-exception-if-no-handler-found=true
spring.resources.add-mappings=false
Error Handling Code:
#Override
protected ResponseEntity<Object> handleNoHandlerFoundException(NoHandlerFoundException ex, HttpHeaders headers,
HttpStatus status, WebRequest request) {
// custom logic here
return handleExceptionInternal(ex, error, getHeaders(), HttpStatus.BAD_REQUEST, request);
}
If you're using #ControllerAdvice,
do this:
#ControllerAdvice
public class RestResponseEntityExceptionHandler
extends ResponseEntityExceptionHandler {
#ExceptionHandler(value
= { IllegalArgumentException.class, IllegalStateException.class })
protected ResponseEntity<Object> handleConflict(
RuntimeException ex, WebRequest request) {
String bodyOfResponse = "This should be application specific";
return handleExceptionInternal(ex, bodyOfResponse,
new HttpHeaders(), HttpStatus.CONFLICT, request);
}
}
I am documenting an REST API using swagger but file upload isn't working through the swagger interface. File is coming as null.
#PostMapping(value = "upload")
#ApiOperation(value = "Upload a Document",
consumes = MediaType.MULTIPART_FORM_DATA_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
#ApiImplicitParams({
#ApiImplicitParam(name = "tenantId", required = true, paramType = "header"),
#ApiImplicitParam(name = "docImageOne", required = true, dataType = "file", paramType = "body"),
#ApiImplicitParam(name = "docImageTwo", dataType = "file", paramType = "body"),
})
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Success", response = UploadResponse.class),
#ApiResponse(code = 400, message = "Bad Request"),
#ApiResponse(code = 404, message = "Not Found"),
#ApiResponse(code = 500, message = "Failure")})
public ResponseEntity<?> identify(final #RequestHeader HttpHeaders headers,
final #RequestBody MultipartFile docImageOne,
final #RequestBody Optional<MultipartFile> docImageTwo)
{}
Not sure what I am missing, any pointers will be much appreciated.
I am facing a problem while trying to process a POST request via POSTMAN.
In my controller I have :
#ApiOperation(value = "xxxx", notes = "xxxx", response =
String.class, authorizations = {
#Authorization(value = "basicAuth")
}, tags={ "saveCourse", })
#ApiResponses(value = {
#ApiResponse(code = 200, message = "successful operation", response =
String.class),
#ApiResponse(code = 404, message = "Not found", response =
String.class),
#ApiResponse(code = 405, message = "Invalid input", response =
String.class),
#ApiResponse(code = 500, message = "Internal Server Error", response =
String.class),
#ApiResponse(code = 200, message = "unexpected error", response =
String.class) })
#RequestMapping(value = "/course/saveCourse",
produces = { "application/json"},
consumes = { "application/json"},
method = RequestMethod.POST)
ResponseEntity<String> saveCourse(#ApiParam(value = "xxxxx" ,required=true ) #RequestBody Course coure){
LOG.info(course.toString);
}
Class Course :
public class Course implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#JsonProperty("prof")
private Prof prof = null;
#JsonProperty("students")
private List<Strudent> students = new ArrayList<Strudent>();
// getters & setters
// ...
}
class Prof :
public class Prof implements Serializable {
#JsonProperty("profLastName")
private String profLastName = null;
#JsonProperty("profFirstName")
private String profFirstName = null;
#JsonProperty("age")
private int age = null;
// getters & setters
}
class Student :
public class Student implements Serializable {
#JsonProperty("studentId")
private String studentId = null;
#JsonProperty("studentName")
private String studentName = null;
#JsonProperty("studAge")
private int studAge = null;
// getters & setters
// ...
}
in POSTMAN I am sending a POST request with the header :
Content-Type : application/json
the body :
{
"prof": {
"profLastName":"test",
"profFirstName":"test",
"age":"30"
},
"students" :[
"{'studentId':'0','studentName':'','studAge':'00'}",
"{'studentId':'2','studentName':'','studAge':'21'}",
"{'studentId':'4','studentName':'','studAge':'40'}",
"{'studentId':'6','studentName':'','studAge':'60'}"
]
}
When I process the request I am getting the RequestBody null :
[http-nio-xxxx-exec-4] INFO com.test.myControllerIml - class Course {
prof: null
students: []
}
you request body is wrong
you should use
{
"prof": {
"profLastName":"test",
"profFirstName":"test",
"age":"30"
},
"students" :[
{"studentId":"0","studentName":"","studAge":"00"},
{"studentId":"2","studentName":"","studAge":"21"},
{"studentId":"4","studentName":"","studAge":"40"},
{"studentId":"6","studentName":"","studAge":"60"}
]
}