Swagger (Springfox) only finding Models used in Controller #RequestBody (Spring Boot) - java

Basically, I'm interested whether it's intended that the only models Swagger shows in swagger-ui are models used in RestController methods. It detects both my DTOs that I filled with #RequestBody, but it does not detect the User model, even with the ApiModel annotation. How to I go around this without making a dummy controller method?
For example:
#PostMapping("/signin")
#ApiOperation
public String login(
#ApiParam(value = "The login credentials DTO (username and password)", required = true)
#RequestBody
#Valid LoginCredentialsDTO loginCredentialsDTO) {
return userService.login(loginCredentialsDTO);
}
It detects the Model "LoginCredentialsDTO" because it was used here in the controller method.
Since I only use DTOs in my controller, it's not detecting my main model (User). I don't want to have to make a dummy method just for Swagger to be able to detect all my models.

Swagger describes the external interface of your api. When your User model is not used externally is will not be visible. See also swagger.io/docs/specification/2-0/basic-structure

Related

Same controller returning different amounts of information depending on role in Spring Boot Rest Controller

In my REST server, I have a controller with the mapping "/users":
#RequestMapping(value = "/users", method = RequestMethod.GET)
public List<UserModel> getAllUsers() {...}
I would like to use Spring Boot Security with Roles to determine how much information to return. For example:
public class UserModel {
private MetaDataModel user_metadata;
private MetaDataModel private_admin_metadata;
}
So that when getAllUsers is called by a user with the admin role, the UserModel supplies both fields, otherwise it only supplies the user_metadata field. I'm completely open to the idea that there is a better approach to this so any suggestions are welcome!
Set appropriate property of response DTO. And use include not null json annotation. Refer For Spring Boot 1.2.3, how to set ignore null value in JSON serialization?

Angular JS & Spring REST -How to Convert JSON Model object to HttpServletRequest for a legacy app

I need to work on an enterprise legacy Java application that is developed in servlets & jsp's.Planning to convert this legacy app to a Single Page application using angular js & Spring MVC REST.
In the new development, AngularJS will be submitting the model object's (as JSON ) to Spring REST methods.
In the existing application there is a lot of code in servlets and classes (at least 2000 lines in 30 classes) written to get request parameter's using HttpServletRequest i.e., request.getParameter("name");
Is it possible to be able to inject/convert the model (JSON) object submitted by angularJs to Spring MVC REST methods into HttpServletRequest object, so that I need not change all the legacy code & classes?
Not considering to use the #RequestParam annotation in the method signature as the number of parameters are high.
Whatever JSON Object you are defining like below and which you trying to pass backend
var dataToPass={
name:"XYZ",
id:12,
selstat:[12,14]
};
For that, you need to create JAVA POJO with similar name like below
class UIData{
private String name; // Getter and Setter
private Integer id; // Getter and Setter
private List<Integer> selstat; // Getter and Setter
}
And in Spring while defining mapping in controller, you need to use annotation #ResuestBody in argument like below
#RequestMapping(value ='/mappingURL', method = RequestMethod.POST)
public #ResponseBody RsponseObject processData(#RequestBody UIData uiData, HttpServletRequest request)
throws MyException {
// Process you data
}
This will automatically convert JSON object into POJO instance.
Please go through Spring Documentation for more details.
And make sure content-type in header while passing is application/json along with Jackson library added in your dependency.

How to make a Model attribute global?

I'm using Spring MVC Framework and I'd like all the .jsp pages of the View to have access to the User's attributes(name, sex, age...). So far, I use the addAttribute method of the Model(UI) in every Controller to pass the current User's attributes to the View. Is there a way to do this only once and avoid having the same code in every Controller?
You can use Spring's #ControllerAdvice annotation on a new Controller class like this:
#ControllerAdvice
public class GlobalControllerAdvice {
#ModelAttribute("user")
public List<Exercice> populateUser() {
User user = /* Get your user from service or security context or elsewhere */;
return user;
}
}
The populateUser method will be executed on every request and since it has a #ModelAttribute annotation, the result of the method (the User object) will be put into the model for every request through the user name, it declared on the #ModelAttribute annotation.
Theefore the user will be available in your jsp using ${user} since that was the name given to the #ModelAttribute (example: #ModelAttribute("fooBar") -> ${fooBar} )
You can pass some arguments to the #ControllerAdvice annotation to specify which controllers are advised by this Global controller. For example:
#ControllerAdvice(assignableTypes={FooController.class,BarController.class})
or
#ControllerAdvice(basePackages={"foo.bar.web.admin","foo.bar.web.management"}))
If it is about User's attributes, you can bind the model bean to session as an attribute which can be accessed on every view. This needs to be done only once.
Another option could be is to implement a HandlerInterceptor, and expose the model to every request.

What class or component of Spring MVC determines the object passed into a Controller's RequestMapping method parameter?

Raw beginner with Spring MVC -- that said,
What component of Spring MVC passes in objects to a method annotated with #RequestMapping within a controller object?
For example,
#RequestMapping
public String test(Model model) {
model.addAttribute("testMessage", "My Test");
return "test";
}
Where does Model come from?
Can my method take in any parameters I want?
Is there some bit of intuitive Spring framework dependency injection that I'm simply not understanding here?
This is all part of Spring dependency injection.
Spring injects the Model model
object to your controller method. Model model is simply a Map <String, Object>
that stores attributes. When you added the attribute to the model object using model.addAttribute("testMessage", "My Test") its adding one entry to the Map. This map is accessible from the view that you're interested in. So you can use this map in your view to access the attribute that you added from the controller (i.e. testMessage)
There are several other things that you can pass in these controller methods that Spring resolves automatically and injects appropriate objects/value. You can use things like:
ModelMap modelMap
#RequestParam
#PathVariable
#ModelAttribute
BindingResult bindingResult
and on and on. When you pass these things on your controller method, Spring knows how to resolve them and inject them to your method.
This might give you an better understanding of spring mvc: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html

Spring MVC #Valid Validation with custom HandlerMethodArgumentResolver

I want to register a custom HandlerMethodArgumentResolver that could handle the following #Controller handler method definition
#RequestMapping(method = RequestMethod.POST)
public String createDomain(#Valid Domain domain, BindingResult errors, #RequestParam("countryId") Long countryId) {
I can register my resolver, which just creates a Domain object through request parameters, by overriding addArgumentResolver() from WebMvcConfigurerAdapter. When Spring tries to resolve the Domain parameter, it goes through its list of HandlerMethodArgumentResolver (there are a lot) and picks the first one that supports() it.
In the above example, although my resolver will get called and my Domain argument will get initialized, the #Valid annotation won't have been processed and the resolver for BindingResult, an ErrorsMethodArgumentResolver will fail because it requires a #ModelAttribute, #RequestBody or the #RequestPart argument in the handler method, which I don't have.
If I try to fix it by adding #ModelAttribute
#RequestMapping(method = RequestMethod.POST)
public String createDomain(#Valid #ModelAttribute Domain domain, BindingResult errors, #RequestParam("countryId") Long countryId) {
a HandlerMethodArgumentResolver implementation, ModelAttributeMethodProcessor, will get checked first with supports() and resolve the argument (with #ModelAttribute and #Valid) before my custom resolver. The BindingResult won't fail, but I won't have my custom creation behavior on the Domain instance.
I could just copy-paste the code for validation and adding to model that's in ModelAttributeMethodProcessor, but I was hoping there was an easier way to resolve my parameters and perform validation without adding an object to the model. Is there such a way?
Nice description of the issue that you are facing.
I checked out the code that you have outlined and have come to the same conclusion that you have - there is no built-in way to have both a custom HandlerMethodArgumentResolver as well as #Valid related validation applied at the same time, the only choice is to do what the ModelAttributeMethodProcessor does which is to check if the parameter has a #Valid annotation and call the validation logic related code.
You can probably derive your HandlerMethodResolverArgumentResolver from ModelAttributeMethodProcessor and call super.validateIfApplicable(..) atleast this way the existing code is leveraged.
It's may be too late, but your HandlerMethodArgumentResolver gets WebDataBinderFactory object as last argument, then, to hook up the validation, simply add this to your resolver implementation:
Object resolvedObject = // your logic
if(parameter.hasParameterAnnotation(Valid.class){
binderFactory.createBinder(webRequest,resolvedObject,"resolvedObjectLogicalName").validate ();
}

Categories