1

I have a problem with my Swagger-UI: It does show Enums as intended.

Instead of a simple representation like CATEGORY1 it shows the full class like CATEGORY1(name=Cat 1) and also uses it in the requests like http://localhost:8080/file/byCategory?category=Category.CATEGORY1%28name%3DCat%201%29

I figured that I can send Requests (e.g. with Postman) with the correct Enum-descriptions and the server would respond, so the api itself works.

The dependencies important for this issue:

 <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
 </dependency>

<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-ui</artifactId>
    <version>1.5.0</version>
</dependency>
<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-data-rest</artifactId>
    <version>1.5.0</version>
</dependency>
<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-webmvc-core</artifactId>
    <version>1.5.0</version>
</dependency>

I also use Spring Boot (2.4.0) and some other dependencies which shouldn't be part of the issue.

My Controller:

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.util.List;

@Slf4j
@RestController
@RequestMapping("/file")
@CrossOrigin(origins = "http://localhost:4200")
@Tag(name = "Files")
public class GridFSController {

private final GridFsService service;

@Autowired
public GridFSController(GridFsService service) {
    this.service = service;
}

@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@Operation(summary =  "Upload a document")
@ResponseBody
public ResponseEntity<String> upload(@RequestParam("file") MultipartFile file, @RequestParam("category") Category category) {
    try {
        if (ObjectUtils.isEmpty(file)) {
            return ResponseEntity.ok().body("The uploaded file cannot be empty");
        } else {
            return ResponseEntity.ok().body(service.saveFile(file, category.getName()));
        }
    } catch (Exception e) {
        log.error("[Upload Failed]", e);
        return ResponseEntity.badRequest().body(e.getMessage());
    }
}

@GetMapping(value = "/download", produces = MediaType.MULTIPART_FORM_DATA_VALUE)
@Operation(summary =  "Download a document by its name")
public ResponseEntity<String> download(HttpServletResponse response, @RequestParam("fileName") String fileName) {
    try {
        service.downLoad(response, fileName);
        return ResponseEntity.ok().body("SUCCESS");
    } catch (Exception e) {
        log.error("[Download Failed]", e.getMessage());
        return ResponseEntity.badRequest().body(e.getMessage());
    }
}

@GetMapping("/byCategory")
@Operation(summary =  "Get information about all documents in a category")
public ResponseEntity<List<FileMetaDomain>> getByCategory(@RequestParam("category") Category category) {
    List<FileMetaDomain> allFilesForCategory = service.getAllFilesForCategory(category.getName());
    return ResponseEntity.ok(allFilesForCategory);
}

}

My Enum:

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;

@ToString
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Getter
public enum Category {

    CATEGORY1("Cat 1"),
    CATEGORY2("Cat 2"),
    CATEGORY3("Cat 3");

    private final String name;

}

My Swagger-UI however looks like this: enter image description here

As mentioned, it works with Postman (even though at this point the response is just an empty array): enter image description here

Helen
  • 87,344
  • 17
  • 243
  • 314

1 Answers1

2

The point is the toString() method overriding. Try to remove the @ToString annotation.

Your Category should be:

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;

@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Getter
public enum Category {

    CATEGORY1("Cat 1"),
    CATEGORY2("Cat 2"),
    CATEGORY3("Cat 3");

    private final String name;
}

And then the swagger-ui will show the enum values dropdown list:

enter image description here

Update: If you need to keep the toString() method, you have to enrich the category parameter description on your controller. Your GET /byCategory endpoint code should look like:

@GetMapping("/byCategory")
@Operation(summary =  "Get information about all documents in a category")
public ResponseEntity<List<FileMetaDomain>> getByCategory(@Parameter(name = "category", in = ParameterIn.QUERY, schema = @Schema(type = "string", allowableValues = {"CATEGORY1", "CATEGORY2", "CATEGORY3"})) Category category) {
    List<FileMetaDomain> allFilesForCategory = service.getAllFilesForCategory(category.getName());
    return ResponseEntity.ok(allFilesForCategory);
}
thepaoloboi
  • 708
  • 4
  • 13
  • Thanks, that helped. However I would prefer to keep the Annotation (e.g. for better analysis). Maybe there is a way to persuade Swagger to use another method? I thought about a converter but didn't found anything in the code (or on the web). – blackwodka86 Jan 12 '21 at 08:06
  • Ok, I caught the point. If you need to keep the `toString()` method, you have to enrich the `category` parameter description on your controller. Please see the update answer :-) – thepaoloboi Jan 13 '21 at 10:37