I use springdoc-openapi to document my REST API. An error is returned by an error object, that has an errorCode and message. I use #Schema annotation to document an example. However I need different examples per different errors. Is there any way, how to do that?
Example from my code:
#PostMapping(consumes = APPLICATION_JSON_VALUE, produces = APPLICATION_JSON_VALUE)
#Operation(summary = "Get new license or retrieve previously issued one for this userId.", tags = "License Endpoint", description = "Licensing operations.",
responses = {
#ApiResponse(
responseCode = "200",
description = "New license or previously issued license for this user, if request was called multiple times.",
content = {#Content(schema = #Schema(implementation = LicenseResponse.class))}
),
#ApiResponse(responseCode = "400",
description = "License can not be retrieved because of either expired bundle or requested bundleId does not exist.",
//I need different example for this error
content = {#Content(schema = #Schema(implementation = LicenseErrorResponse.class))
}
),
#ApiResponse(responseCode = "500",
description = "Internal Error",
//And different example for this error
content = {#Content(schema = #Schema(implementation = LicenseErrorResponse.class))
}
)
}
)
#LoggedIO(input = INFO, result = INFO)
public ResponseEntity<Object> newLicense(#Valid #RequestBody LicenseRequest licenseRequest) {
//content not interesting
}
import javax.validation.constraints.NotBlank;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
#Data
public class LicenseErrorResponse {
// I need different examples for different error in controller.
#Schema(example = "UNKNOWN_BUNDLE_ID", required = true)
private final LicenseErrorCode licenseErrorCode;
#Schema(example = "Bundle doesn't exist, bundleId=com.unknown.id")
private final String message;
#JsonCreator
public LicenseErrorResponse(
#NotBlank #JsonProperty(value = "errorCode") final LicenseErrorCode licenseErrorCode,
#NotBlank #JsonProperty(value = "message") final String message) {
this.licenseErrorCode = licenseErrorCode;
this.message = message;
}
public enum LicenseErrorCode {
EXPIRED_BUNDLE, UNKNOWN_BUNDLE_ID, OTHER
}
}
One way to do that is you can define a string as an example
public static final String exampleInternalError = "{\r\n"
+ " \"licenseErrorCode\": 500,\r\n"
+ " \"message\": \"Internal Error\"\r\n" + "}";
same is used to show the example as
#ApiResponse(responseCode = "500",
description = "Internal Error",
//And different example for this error
content = #Content(schema = #Schema(implementation = LicenseErrorResponse.class),
examples = #ExampleObject(description = "Internal Error", value = exampleInternalError)))
Related
I'm currently working on a website, which has a backend made in Java Spring Boot. But everytime i make a delete or a put request, the following Error appears in the console:
Access to fetch at 'http://10.0.10.67:8080/users/2' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
I've tried multiple things, and nothing worked. I know it can't be a problem of the backend, because delete requests work, when sending them with postman.
This is my function for deleting users:
export async function deleteUser(id, token) {
console.log("helo")
const response = await fetch(`${URL}/users/${id}`, {
method: "DELETE",
mode: 'cors',
headers: {
"content-type": "application/json",
"authorization": `Bearer ${token}`,
"Access-Control-Allow-Origin": "http://localhost:3000"
}
})
if (!response.ok) {
return Promise.reject(response)
}
}
And this is my controller class in backend (like i said, the delete function works in backend, i tested it manually):
public class ApplicationUserController {
private final UserService userService;
private final TimeService timeService;
private final RfidChipService rfidChipService;
#Autowired
public ApplicationUserController(UserService userService, TimeService timeService, RfidChipService rfidChipService) {
this.userService = userService;
this.timeService = timeService;
this.rfidChipService = rfidChipService;
}
#Operation(summary = "Find ApplicationUser with a given firstname, lastname and/or email. If no parameters given, all users are returned.")
#ApiResponses(value = {
#ApiResponse(responseCode = "200", description = "ApplicationUser(s) found",
content = {#Content(mediaType = "application/json",
schema = #Schema(implementation = ApplicationUser.class))})})
#GetMapping()
public ResponseEntity<?> findUserByNameSurnameEmail(#Parameter(description = "Users firstname to search") #RequestParam(required = false) String firstname,
#Parameter(description = "Users lastname to search") #RequestParam(required = false) String lastname,
#Parameter(description = "Users email to search") #RequestParam(required = false) String email) {
try {
if (StringUtils.isNotBlank(firstname)) {
return ResponseEntity.ok(userService.getUserByFirstname(firstname));
} else if (StringUtils.isNotBlank(lastname)) {
return ResponseEntity.ok(userService.getUserByLastname(lastname));
} else if (StringUtils.isNotBlank(email)) {
return ResponseEntity.ok(userService.getUserByEmail(email));
}
return ResponseEntity.ok(userService.getAllUsers());
} catch (EntityNotFoundException e) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "No ApplicationUser(s) found");
}
}
#PostMapping(value = "/sign-up", consumes = "application/json")
#ResponseStatus(HttpStatus.CREATED)
public void signUp(#Parameter(description = "The new user to create") #Valid #RequestBody ApplicationUserDTO requestDTO) {
try {
List<RfidChipDTO> rfidChipDTOList = rfidChipService.getRfidChipWithNoUser();
requestDTO.setRfidChip(RfidChipMapper.fromDTO(rfidChipDTOList.get(0)));
userService.signUp(ApplicationUserMapper.fromDTO(requestDTO));
} catch (DataIntegrityViolationException e) {
throw new ResponseStatusException(HttpStatus.CONFLICT);
}
}
#Operation(summary = "Find a user by his id")
#ApiResponses(value = {
#ApiResponse(responseCode = "200", description = "ApplicationUser found",
content = {#Content(mediaType = "application/json",
schema = #Schema(implementation = ApplicationUser.class))}),
#ApiResponse(responseCode = "404", description = "ApplicationUser not found",
content = #Content)})
#GetMapping(path = "{id}")
public ResponseEntity<?> findById(#Parameter(description = "Id of user to get") #PathVariable Integer id) {
try {
return ResponseEntity.ok(userService.getById(id));
} catch (EntityNotFoundException e) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "ApplicationUser could not be found");
}
}
#Operation(summary = "Find admins employees by his id")
#ApiResponses(value = {
#ApiResponse(responseCode = "200", description = "Employees found",
content = {#Content(mediaType = "application/json",
schema = #Schema(implementation = ApplicationUser.class))}),
#ApiResponse(responseCode = "404", description = "No Employees found",
content = #Content)})
#GetMapping(path = "{id}/employees")
public ResponseEntity<?> findEmployeesByAdminId(#Parameter(description = "Id of admin") #PathVariable Integer id) {
try {
return ResponseEntity.ok(userService.getUserByAdminId(id));
} catch (EntityNotFoundException e) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Admin could not be found");
}
}
#Operation(summary = "Find users times by his id")
#ApiResponses(value = {
#ApiResponse(responseCode = "200", description = "Time(s) found",
content = {#Content(mediaType = "application/json",
schema = #Schema(implementation = ApplicationUser.class))}),
#ApiResponse(responseCode = "404", description = "No times found",
content = #Content)})
#GetMapping(path = "{id}/times")
public ResponseEntity<?> findTimesByUserId(#Parameter(description = "Id of user") #PathVariable Integer id) {
try {
return ResponseEntity.ok(timeService.findTimeByUserId(id));
} catch (EntityNotFoundException e) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "User could not be found");
}
}
#Operation(summary = "Update a user")
#ApiResponses(value = {
#ApiResponse(responseCode = "200", description = "ApplicationUser was updated successfully",
content = {#Content(mediaType = "application/json",
schema = #Schema(implementation = ApplicationUser.class))}),
#ApiResponse(responseCode = "409", description = "ApplicationUser could not be updated",
content = #Content),
#ApiResponse(responseCode = "400", description = "Validation failed",
content = {#Content(mediaType = "application/json",
schema = #Schema(implementation = ApplicationUser.class))})})
#PatchMapping(value = "{id}", consumes = "application/json")
public ResponseEntity<?> update(#Valid #RequestBody ApplicationUserDTO applicationUserDTO, #PathVariable Integer id) {
try {
ApplicationUserDTO updatedUser = userService.update(applicationUserDTO, id);
return ResponseEntity.ok(updatedUser);
} catch (DataIntegrityViolationException e) {
throw new ResponseStatusException(HttpStatus.CONFLICT, "ApplicationUser could not be updated");
}
}
#Operation(summary = "Create a new ApplicationUser")
#ApiResponses(value = {
#ApiResponse(responseCode = "201", description = "ApplicationUser was created successfully",
content = {#Content(mediaType = "application/json",
schema = #Schema(implementation = ApplicationUser.class))}),
#ApiResponse(responseCode = "409", description = "ApplicationUser could not be created",
content = #Content),
#ApiResponse(responseCode = "400", description = "Validation failed",
content = {#Content(mediaType = "application/json",
schema = #Schema(implementation = ApplicationUser.class))})})
#ResponseStatus(HttpStatus.CREATED)
#PostMapping(consumes = "application/json")
public ResponseEntity<?> create(#Valid #RequestBody ApplicationUserDTO applicationUserDTO) {
try {
ApplicationUserDTO createdApplicationUserDTO = userService.create(applicationUserDTO);
return ResponseEntity.status(201).body(createdApplicationUserDTO);
} catch (DataIntegrityViolationException | ConstraintViolationException e) {
throw new ResponseStatusException(HttpStatus.CONFLICT, "ApplicationUser could not be created");
}
}
#Operation(summary = "Delete a user")
#ApiResponses(value = {
#ApiResponse(responseCode = "200", description = "ApplicationUser was deleted successfully",
content = {#Content(mediaType = "application/json",
schema = #Schema(implementation = ApplicationUser.class))}),
#ApiResponse(responseCode = "404", description = "ApplicationUser could not be deleted",
content = #Content)})
#DeleteMapping("{id}")
public ResponseEntity<?> delete(#PathVariable Integer id) {
try {
userService.deleteById(id);
return ResponseEntity.ok().build();
} catch (EmptyResultDataAccessException e) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "ApplicationUser could not be deleted");
}
}
}
I call the function in an "onClick(() => {}), and this seems to work.
I would appreciate it if someone could solve the problem for me.
Ps: I already tried the #CrossOrigin annotation, it didn't work
Sending a request from a browser is completely different that sending it with postman. You are not hitting directly your backend like postman, browsers does it for you
To understand it better you can read this one. crossorigin resource sharing
Your error comes from your backend configuration. You can use CorsConfigurer. Also you can combine it with spring security.
note: you can use allowedOrigins or allowerOriginsPattern according to your spring boot version.
spring boot enabling crossorigin
Let me know if I can help further.
I could fix the error, by creating a "configuration"-package and following class in it:
#Configuration
public class CorsConfiguration
{
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedMethods("GET", "POST", "PUT", "DELETE");
}
};
}
}
This Class is global and it allows everyone access to put post delete and get requests on all controllers
I have a POST endpoint which receives a #ModelAttribute parameter. Everything is working ok, but the swagger documentation fails to have the descriptions, examples, etc.
I am using java 11, springboot 2.5.4 and springfox-boot-starter 3.0.0
Here is my code:
#Api
#RestController
#RequestMapping("/foo")
#Validated
public class MyRest {
#PostMapping(value = "/{id}/bar", consumes = { MediaType.MULTIPART_FORM_DATA_VALUE })
#ApiOperation(value = "Do nothing", notes = "This endpoint does nothing")
public ResponseEntity<String> search(
#ModelAttribute MyModelRequest request,
#ApiParam(value = "Folder ID", required = true)
#PathVariable String id) {
// some business code
return new ResponseEntity<>("lorem ipsum", HttpStatus.OK);
}
}
MyModelRequest
#ApiModel
#Data
public class MyModelRequest {
#ApiParam(name = "fileName", value = "The name of the image to be stored in database")
#ApiModelProperty(value = "name model description", example = "summer picture", required = true)
private String name;
#DecimalMin("0.00")
#DecimalMax("100.00")
#ApiParam(name = "accuracy", value = "The required accuracy")
#ApiModelProperty(value = "Minimum required accuracy", example = "95.15", required = false)
private BigDecimal accuracy;
#ApiParam(name = "marginTop", value = "Top margin of the image")
#ApiModelProperty(value = "Separation between top item and the image", example = "300", required = false)
private Integer marginTop;
#ApiParam(name = "image")
#ApiModelProperty(value = "The image to be stored", example = "vacations.png", required = true)
private MultipartFile image;
}
And this is the generated swagger doc
UPDATE: I noticed that if I change the consumes = { MediaType.MULTIPART_FORM_DATA_VALUE } for consumes = { MediaType.APPLICATION_JSON_VALUE } or remove the whole "consumes" parameter from the endpoint, the documentation shows up correctly, however, doing this will make the fileupload fail.
I have an entity Users, which contains id and emailAddress. I want to write a controller which has 3 get methods simultaneously:
getAll() - http://localhost:8080/api/users?pageNumber=0&pageSize=10
get(UUID id) - http://localhost:8080/api/users/209347293875928375928
get(String email) - http://localhost:8080/api/users/fireball%40email.com or http://localhost:8080/api/users?emailAddress="fireball%40email.com"
NOTE: The difference in the two pieces of code is the arguments of the last function in both(The first is #PathVariable and the second is a #RequestParam.
I have tried two ways to accomplish this(both run into a separate issue), the first being:
#GetMapping
#ApiOperation(value = "List all Users")
#ApiResponses({
#ApiResponse(code = 200, message = "OK", response = User.class, responseContainer = "List"),
#ApiResponse(code = 401, message = "Unauthorized", response = Error.class),
#ApiResponse(code = 404, message = "Not Found", response = Error.class),
#ApiResponse(code = 500, message = "Internal Server Error", response = Error.class)
})
#Transactional(readOnly = true)
public ResponseEntity<Page<User>> getAll(
#RequestParam(required = false, defaultValue = "0") int pageNumber,
#RequestParam(required = false, defaultValue = "10") int pageSize) {
return ResponseEntity.ok(UserService.getUsers(pageNumber, pageSize));
}
#GetMapping(path = "/{id}")
#ApiOperation(value = "Get User by ID")
#Transactional(readOnly = true)
#ApiResponses({
#ApiResponse(code = 200, message = "OK", response = User.class),
#ApiResponse(code = 401, message = "Unauthorized", response = Error.class),
#ApiResponse(code = 404, message = "Not Found", response = Error.class),
#ApiResponse(code = 500, message = "Internal Server Error", response = Error.class)
})
public ResponseEntity<?> get(#PathVariable("id") final UUID id) {
return UserService.get(id)
.map(ResponseEntity::ok)
.map(ResponseEntity.class::cast)
.orElse(
ResponseEntity.status(NOT_FOUND).body(new Error(format(USER_NOT_FOUND_MESSAGE, id))));
}
#GetMapping
#ApiOperation(value = "Get User by Email Address")
#Transactional(readOnly = true)
#ApiResponses({
#ApiResponse(code = 200, message = "OK", response = User.class),
#ApiResponse(code = 401, message = "Unauthorized", response = Error.class),
#ApiResponse(code = 404, message = "Not Found", response = Error.class),
#ApiResponse(code = 500, message = "Internal Server Error", response = Error.class)
})
public ResponseEntity<?> get(#RequestParam("email") final String email) {
return UserService.get(email)
.map(ResponseEntity::ok)
.map(ResponseEntity.class::cast)
.orElse(
ResponseEntity.status(NOT_FOUND).body(new Error(format(USER_NOT_FOUND_MESSAGE, email))));
}
The above fails at compilation with Ambiguous mapping. Cannot map 'userController' method as error. Essentially getAll() and get(#RequestParam("email") final String email) have the same URL path - /users.
The second being:
#GetMapping
#ApiOperation(value = "List all Users")
#ApiResponses({
#ApiResponse(code = 200, message = "OK", response = User.class, responseContainer = "List"),
#ApiResponse(code = 401, message = "Unauthorized", response = Error.class),
#ApiResponse(code = 404, message = "Not Found", response = Error.class),
#ApiResponse(code = 500, message = "Internal Server Error", response = Error.class)
})
#Transactional(readOnly = true)
public ResponseEntity<Page<User>> getAll(
#RequestParam(required = false, defaultValue = "0") int pageNumber,
#RequestParam(required = false, defaultValue = "10") int pageSize) {
return ResponseEntity.ok(UserService.getUsers(pageNumber, pageSize));
}
#GetMapping(path = "/{id}")
#ApiOperation(value = "Get User by ID")
#Transactional(readOnly = true)
#ApiResponses({
#ApiResponse(code = 200, message = "OK", response = User.class),
#ApiResponse(code = 401, message = "Unauthorized", response = Error.class),
#ApiResponse(code = 404, message = "Not Found", response = Error.class),
#ApiResponse(code = 500, message = "Internal Server Error", response = Error.class)
})
public ResponseEntity<?> get(#PathVariable("id") final UUID id) {
return UserService.get(id)
.map(ResponseEntity::ok)
.map(ResponseEntity.class::cast)
.orElse(
ResponseEntity.status(NOT_FOUND).body(new Error(format(USER_NOT_FOUND_MESSAGE, id))));
}
#GetMapping(path = "/{email}")
#ApiOperation(value = "Get User by Email Address")
#Transactional(readOnly = true)
#ApiResponses({
#ApiResponse(code = 200, message = "OK", response = User.class),
#ApiResponse(code = 401, message = "Unauthorized", response = Error.class),
#ApiResponse(code = 404, message = "Not Found", response = Error.class),
#ApiResponse(code = 500, message = "Internal Server Error", response = Error.class)
})
public ResponseEntity<?> get(#PathVariable("email") final String email) {
return UserService.get(email)
.map(ResponseEntity::ok)
.map(ResponseEntity.class::cast)
.orElse(
ResponseEntity.status(NOT_FOUND).body(new Error(format(USER_NOT_FOUND_MESSAGE, email))));
}
Here I run into the issue of the controller not being able to resolve between get(#PathVariable("email") final String email and get(#PathVariable("id") final UUID id) with the following error:
Ambiguous handler methods mapped for '/api/gems/users/fireball%40email.com': {public org.springframework.http.ResponseEntity com.personal.project.controllers.UserController.get(java.util.UUID), public org.springframework.http.ResponseEntity com.personal.project.controllers.UserController.get(java.lang.String)}
You can solve it by merging these two Ambiguous path into one.
For the first case:
#GetMapping
#ApiOperation(value = "List all Users")
#ApiResponses({
#ApiResponse(code = 200, message = "OK", response = User.class, responseContainer = "List"),
#ApiResponse(code = 401, message = "Unauthorized", response = Error.class),
#ApiResponse(code = 404, message = "Not Found", response = Error.class),
#ApiResponse(code = 500, message = "Internal Server Error", response = Error.class)
})
#Transactional(readOnly = true)
public ResponseEntity<?> getUsers(
#RequestParam(required = false, defaultValue = "0") int pageNumber,
#RequestParam(required = false, defaultValue = "10") int pageSize,
// add email as param.
#RequestParam(required = false) String email,
) {
if(email ==null || StringUtils.isEmpty(email)){
return ResponseEntity.ok(UserService.getUsers(pageNumber, pageSize));
}else return UserService.get(email)
.map(ResponseEntity::ok)
.map(ResponseEntity.class::cast)
.orElse(
ResponseEntity.status(NOT_FOUND).body(new Error(format(USER_NOT_FOUND_MESSAGE, email))));
}
For the second one:
// change the type UUID id to string.
#GetMapping(path = "/{id}")
...
public ResponseEntity<?> get(#PathVariable("id") final String id) {
// check if id as an uuid or email, and based on that take action
}
In line with my previous answer, you only need two controller methods. Then, in the method that handles GET /users requests, the presence or absence of the name query parameter will determine whether the server will fetch all users or filter the user by email.
See below the example below. For simplification, I have not added the OpenAPI annotations and also removed pagination, but you can easily add them as you need:
#RestController
#RequestMapping(path = "/users",
produces = MediaType.APPLICATION_JSON_VALUE)
public class UserController {
#GetMapping
public ResponseEntity<List<User>> findUsers(#RequestParam("email") final String email) {
// If email is null/empty/blank, then fetch all users
// Otherwise filter users by email
}
#GetMapping(path = "/{id}")
public ResponseEntity<User> findUserById(#PathVariable("id") final UUID id) {
// Find user with the given ID
}
}
In case you plan to support multiple filters (or simply want to avoid if-'else's or custom repository methods), it may be a good idea to use Query by Example (QBE), which is supported by Spring Data:
Query by Example (QBE) is a user-friendly querying technique with a simple interface. It allows dynamic query creation and does not require you to write queries that contain field names. In fact, Query by Example does not require you to write queries by using store-specific query languages at all.
The documentation also states the following:
The Query by Example API consists of three parts:
Probe: The actual example of a domain object with populated fields.
ExampleMatcher: The ExampleMatcher carries details on how to match particular fields. It can be reused across multiple Examples.
Example: An Example consists of the probe and the ExampleMatcher. It is used to create the query.
Query by Example is well suited for several use cases:
Querying your data store with a set of static or dynamic constraints.
Frequent refactoring of the domain objects without worrying about breaking existing queries.
Working independently from the underlying data store API.
Query by Example also has several limitations:
No support for nested or grouped property constraints, such as firstname = ?0 or (firstname = ?1 and lastname = ?2).
Only supports starts/contains/ends/regex matching for strings and exact matching for other property types.
See below how to use Query by Example in your case:
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
public class UserFilter {
private String email;
}
#RestController
#RequiredArgsConstructor
#RequestMapping(path = "/users",
produces = MediaType.APPLICATION_JSON_VALUE)
public class UserController {
private final UserService userService;
#GetMapping
public ResponseEntity<List<User>> findUsers(#RequestParam("email") final String email) {
UserFilter filter = UserFilter.builder().name(email).build();
List<User> users = userService.findUsers(filter);
return ResponseEntity.ok(users);
}
#GetMapping(path = "/{id}")
public ResponseEntity<User> findUserById(#PathVariable("id") final UUID id) {
User user = userService.findUserById(filter).orElseThrow(SomeSortOfException::new);
return ResponseEntity.ok(user);
}
}
#Service
#RequiredArgsConstructor
public class UserService {
private final UserRepository userRepository;
public List<User> findUsers(UserFilter filter) {
User user = new User();
user.setEmail(filter.getEmail());
Example<User> example = Example.of(user);
return userRepository.findAll(example);
}
public Optional<User> findUserById(UUID id) {
return userRepository.findById(id);
}
}
How can I insert a default value instead of the "{}" using swagger annotations?
You need to annotate your Rest method with #ApiResponses and #ApiResponse.
For example
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Successful retrieval of demand",responseContainer="List"),
#ApiResponse(code = 404, message = "Demand does not exist", response = Your Error response.class),
#ApiResponse(code = 500, message = "Internal server error", response = Your Error response.class)
}
)
Annotate your Json Response class with #ApiModel and its field with #ApiModelProperty like
#ApiModel(description = "Your comment")
public class Demand implements Serializable {
private static final long serialVersionUID = 1L;
#ApiModelProperty(notes = "Your comments", required = true, example = "example value")
private String demandId;
}
I generated automatically SpringMVC API using swagger. Now I want to update some end-points manually.
I have the folloiwng end-point:
#ApiOperation(value = "Estimation of ...", notes = "...", response = Similarity.class, responseContainer = "List")
#io.swagger.annotations.ApiResponses(value = {
#io.swagger.annotations.ApiResponse(code = 200, message = "Similarity metrics", response = Similarity.class),
#io.swagger.annotations.ApiResponse(code = 200, message = "Unexpected error", response = Similarity.class) })
#RequestMapping(value = "/estimateSimilarity",
produces = { "application/json" },
method = RequestMethod.GET)
public ResponseEntity<HashMap<String,Double>> estimateSimilarity(
#ApiParam(value = "...", required = true)
#RequestParam(value = "term1", required = true) String term,
#ApiParam(value = "...", required = true)
#RequestParam(value = "terms", required = true) List<String> concepts)
throws NotFoundException {
Similarity similarity = new Similarity();
HashMap<String,Double> result = similarity.getEstimates(term1, terms);
return new ResponseEntity<HashMap<String,Double>>(HttpStatus.OK);
}
Instead of response = Similarity.class, I want to return HashMap<String,Double> result. How should I update the above-given code to be able to return this object?
Try modifying the ApiOperations Response container.
#ApiOperation(value = "Estimation of ...", notes = "...", response = Double.class, responseContainer = "Map")