Good afternoon.
I am trying to generate Swagger documentation but fails to generate clean result if the response is not a simple class.
if we consider a user with family members, the following REST function as a partial documentation
public ResponseEntity<FamilyMembersResponse> getUserFamily(#PathVariable("user_uuid") String UUID) {
...
FamilyMembersResponse response= new FamilyMembersResponse();
...
return new ResponseEntity<>(response, HttpStatus.OK);
}
By partial, I mean that swagger will say that result is of type FamilyMembersResponse (that is correct) but the FamilyMembersResponse class itself is not documented (return without any attributes).
The issue may be that the class FamilyMembersResponse is created within the controler but even with such definitions the class description is always empty:
class FamilyMembersResponse {
#Schema(name = "user" )
User user;
#Schema(name = "family_members" )
List<FamilyMember> family_members;
}
Any idea why? Issue seems "only" on the generation of FamilyMembersResponse "class", not the route
Just found the answer... as in simply posting in SO after looking for hours helped solving the issue (why, that is the question :D).
JsonProperty was expected, .. which kind of makes sense.
#JsonProperty("user")
Related
I am following Spring in Action, 5th edition, and in chapter 3 I am facing this issue:
#PostMapping
public String processDesign(#Valid Taco design, Errors errors, #ModelAttribute Order order) {
if (errors.hasErrors()) {
return "design";
}
Taco saved = designRepo.save(design);
order.addDesign(saved);
return "redirect:/orders/current";
}
On Submit your Taco action, a request goes to the above method, but the ingredients field in Taco object is null.
My Taco class is the same as provided here.
So, what am I missing?
You need to generate the list of ingredients in case of error (again).
#PostMapping
public String designForm(#ModelAttribute("design") #Valid Taco taco, Errors errors, Model model) {
if (errors.hasErrors()) {
List<Ingredient> ingredients = ingredientRepository.findAll();
Type[] types = Ingredient.Type.values();
for (Type x : types) {
model.addAttribute(x.toString().toLowerCase(),
ingredients.stream().filter(p -> p.getType().equals(x)).collect(Collectors.toList()));
}
return "design";
}
log.info("Processing desing: " + taco);
return "redirect:/order/current";
}
Removing
model.addAttribute("order",new Order());
in OrderController would fix the issue.
TacoController is passing the model with order instance populated, however the get method in order controller, specifically the above line add a new order to model, overwriting the old order details.
I too am going over Spring in Action 5, chapter 3. I had an issues with my "ingredients" field being null as well. I have managed to fix this.
Somewhere in Ch3, the code for "ingredients" changed types. In your Taco class, "ingredients" should be List (as seen from ch2); however this changed to List in Ch3 without any mention. I found out about that change looking at the chapter's source code. Anyhow, because the list's type switched from String to Ingredient, Spring will no longer bind the list of ingredients from the form.
My fix is this:
1 - revert the Taco class' "ingredient" field to be a List data type.
2 - in the JdbcTacoRepository class, make the following changes:
2a - add a new private final field of type IngredientRepository
2b - update the constructor to autowire the above field
2c - within the save(Taco taco) method, use the following changes:
for(String ingredientId : taco.getIngredients()){ Ingredient ingredient = ingredientRepo.findOne(ingredientId); saveIngredientToBurger(ingredient, burgerId); }
Overall the ingredients field was null b/c Spring couldn't bind a String object to an Ingredient object. I'm still trying to understand how Spring recognizes the ingredient in the first place, but hopefully this works for you.
I need to implement PATCH functionality at my Spring #RestController.
I saw a lot of questions and the most common approach is to use a plain Java Map to do this. Map that allows null helps to solve the issue with null or absent values because it looks like impossible to implement on POJO.
Is there at Spring any out of the box functionality that helps to reflect values from Map to the existing model object or I have to implement it by myself.. for example using Jackson and so on ?
I can share My implementation of PATCH, hope this helps some one in some way. I have a client which has six fields like ( name, type, address fields , ID, Number, postcode), I can edit the client and change anything.
this is also an elaboration on the question with a partial answer ( or a complete one if there is no other way than the two below) Or perhaps PATCH is supposed to be done differently
clientService is just a service which holds the ClientRepository
#RequestMapping(value = "/{id}", method = RequestMethod.PATCH ,produces = {"application/vnd.api+json"} )
ResponseEntity<Resource<Client>> editClient(#PathVariable("id") Integer id,#RequestBody Client editedClientFromBrowser) {
// the id is the ID of the client that I was editing..
//i can use this to retrieve the one from back end
// editedClientFromBrowser is the changed Client Model Object
//from the browser The only field changed is the one
// that was changed in the browser but the rest of
//the object is the same with the ID as well
logger.info("Edit Client reached");
//retreive the same Client from backend and update and save it
// Client client = clientService.getClient(id);
// if (client == null) {
// throw new EntityNotFoundException("Client not found - id: " + id);
// }else{
// change the field that is different from the
//editedClientFromBrowser and then saveAndFlush client
//}
//OR saveAndFlush the editedClientFromBrowser itself
clientService.saveAndFlush(editedClientFromBrowser);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
now another method I read on (http://www.baeldung.com/http-put-patch-difference-spring) and tried:
#RequestMapping(value = "/{id}", method = RequestMethod.PATCH ,
produces = {"application/vnd.api+json"} )
ResponseEntity<Resource<Client>> editClient(#PathVariable("id") Integer id,
#RequestBody Map<String, Object> updates)
this one does give me a hashMap. but it gives me each and every field. even the ones I did not change. So, is that really beneficial? No idea seriously, may be it is lighter than getting the whole client object back.
I would have liked if I get only the hashmap of one or two fields which I did change. that would have been more in line with PATCH i think. Can I improve my two implementations in some way?
I am pretty new in Spring MVC and I have the following doubt about how correctly achieve the following task.
I am working on a web application that implement a user registration process. This registration process is divided into some consecutive steps.
For example in the first step the user have to insert a identification code (it is a code that identify uniquely a user on some statal administration systems) and in the second step it have to compile a form for his personal data (name, surname, birth date, and so on).
So, actually I have the following controller class that handle these steps:
#Controller
public class RegistrazioneController {
#Autowired
private LoadPlacesService loadPlacesService;
#RequestMapping(value = "/iscrizioneStep1")
public String iscrizioneStep1(Model model) {
return "iscrizioneStep1";
}
#RequestMapping(value = "/iscrizioneStep2", method=RequestMethod.POST)
public String iscrizioneStep2(Model model, HttpServletRequest request, #RequestParam("cf") String codicFiscale) {
System.out.println("INTO iscrizioneStep2()");
//String codicFiscale = request.getParameter("cf");
System.out.println("CODICE FISCALE: " + codicFiscale);
model.addAttribute("codicFiscale", codicFiscale);
return "iscrizioneStep2";
}
#RequestMapping(value = "/iscrizioneStep3", method=RequestMethod.POST)
public String iscrizioneStep3(#ModelAttribute("SpringWeb")Step2FormCommand step2Form, ModelMap model, HttpServletRequest request) {
System.out.println("INTO iscrizioneStep3()");
System.out.println("NOME: " + step2FormCommand.getName());
return "iscrizioneStep3";
}
Into the iscrizioneStep2() it is retrieved the first code (#RequestParam("cf") String codicFiscale).
Into the iscrizioneStep3() it is retrieved a command object containing the data inserted into the form of the view in which this form was submitted, this one:
#ModelAttribute("SpringWeb")Step2FormCommand step2FormCommand
It works fine.
Now my problem is that I have another object named Step3View that have to be initialized with the aggregation of the #RequestParam("cf") String codicFiscale object retrieved into the iscrizioneStep2() method and the #ModelAttribute("SpringWeb")Step2FormCommand step2FormCommand retrieved into the iscrizioneStep3() method.
This Step3View class simply contain the String codicFiscale and all the fields of the Step2FormCommand class.
Now my doubts are: what is the best way to handle this situation? Where have I to declare this Step3View object? at controller level? (so I can use it in all my controller methods?). Have I to annotate this class with #Component (or something like this) to inject it in my controller?
What is the best solution for this situation?
I think in order to get an answer you need to understand the question and ask the right question. I think your question is "how do I pass a parameter from one page to another page in SpringMVC?". You specifically want to know how to pass the "cf" param, but readers here will tend to pass over questions that are too specific because it takes too much time to figure out what you want.
In answer to that, see Spring MVC - passing variables from one page to anther as a possible help.
Also, there are many good answers about this question for JSP in general, which can be worked into the SpringMVC architecture. See How to pass value from one jsp to another jsp page? as a possible help.
I am using the below URL to send a request,but i am getting a 404 error.
with a warning on server:No mapping found for HTTP request with URI
The URI is
http://localhost:8080/webstore/products/tablet/price;low=200;high=400?manufacturer="Google"
The method in controller used is
#RequestMapping(value="/products/{category}/{ByCriteria}",method=RequestMethod.GET)
public String getSpecificProductByFilter(#PathVariable("category")String ProductCategory,#MatrixVariable(pathVar= "ByCriteria") Map<String,List<Long>> filterParams,#RequestParam String manufacturer,Model model){
model.addAttribute("products",productService.getfilterproducts(ProductCategory,filterParams, manufacturer));
return "products";
}
The category signifies "tablet"in the URI
Criteria signifies"low" and "high"
manufacturer is"google"
For those who dont know, this is from book "Spring MVC begginers guide" by Amuthan G. This question is really old but I will give there my solution just in case somebody going to need that, just like me today.
First of all your #RequestMapping is wrong. It should looks like this:
#RequestMapping(value="/{category}/{ByCriteria}", method=RequestMethod.GET)
And reason for that is you already have #RequestMapping("/products") on this whole controller class (above your class declaration). And because you want to map
webstore/products/tablet and NOT webstore/products/products/tablet you have to leave that "products" mapping from this method.
Second thing is your URI. I know that in the books there is this one and its not really big deal, but if you dont want to have problems, leave quotation marks next to word Google. Its because you dont want to have value "Google" but just Google without these quation marks and if you let them there, you will have problems with comparing values. So your URI should looks like this.
http://localhost:8080/webstore/products/tablet/price;low=200;high=400?manufacturer=Google
For complete solution you have to do following steps:
In your repository and service interfaces and classes write method:
List<Product> getProductsByManufacturer(String manufacturer);
and implement it in same way like you wrote method GetProductsByCategory.
In your repository and service interfaces and classes write method:
Set<Product> getProductsByPrice(Map<String, List<String>> priceParams);
and implement it in same way like you wrote method getProductsByFilter.
Finnaly write method in Controller class:
#RequestMapping("/{category}/{ByPrice}")
public String filterProducts(#PathVariable("category") String productCategory,
#MatrixVariable(pathVar = "ByPrice") Map<String, List<String>> filterParams,
#RequestParam String manufacturer, Model model) {
List<Product> byCategory = productService.getProductsByCategory(productCategory);
List<Product> byManufacturer = productService.getProductsByManufacturer(manufacturer);
Set<Product> byPrice = productService.getProductsByPrice(filterParams);
byCategory.retainAll(byManufacturer);
byCategory.retainAll(byPrice);
model.addAttribute("products", byCategory);
return "products";
}
In my project this method look like this, but you can certainly do it in shorter way. After you complete these steps, your project should working. If not, feel free to ask me there. If you dont know how to write methods in steps 1 and 2 I will comment there code for you, but its almost same like that another methods as I said. I hope that this is going to help somebody.
I'm investigating Web Api in ASP.NET vNext using the daily builds. In a web api 2x project, I use HttpParameterBinding and ParameterBindingAttribute in some situations (see http://bit.ly/1sxAxdk); however, I can't seem to find either in vNext. Do/will these classes exist? If not, what are my alternatives?
Edit (1-22-15):
I want to be able to serialize a complex JS object to a JSON string, put the JSON string in a hidden form field (say name="data"), submit the form, and then bind my parameter to that JSON object on the server. This will never be done by a human, but rather by a machine. I also want this very same mechanism to work if the JSON is sent directly in the request body instead of form data. I also need this to work for several different types of objects.
I've been able to accomplish this scenario in Web Api 2.2 in a few different ways, including a custom ModelBinder; however, I remember reading an MSFT blog post that suggested to use a ModelBinder for query string binding, formatters for request body, and HttpParameterBinding for more general scenarios. Is it okay to read the request body in a ModelBinder ASP.NET 5, or is there a better mechanism for that? If so, then case closed and I will port my ModelBinder with a few minor changes.
I'm not sure that IInputFormatter will work for me in this case either.
Here are two rough approaches
Approach 1:
A quick and dirty approach would be to start with a Dto model
public class Dto
{
public Serializable Result { get; set; }
public Serializable FromForm
{
get { return Result; }
set { Result = value; }
}
[FromBody]
public Serializable FromBody
{
get { return Result; }
set { Result = value; }
}
}
public class Serializable
{
}
And an action method
public IActionResult DoSomething(Dto dto)
{
// Do something with Dto.Result
}
Then write a custom model binder for Serializable, that just works with Request.Form this way you never actually read the body yourself, and Form only reads it if it of type Form.
The down side of this is that ApiExplorer will not provide correct details (but I think since this is none-standard you are going to be in trouble here anyways).
Approach 2
You can alternatively just use the code from BodyModelBinder and create a custom binder for Serializable type above, that first tries to get it from the Form, and if it fails tries to get it from the Body. The Dto class in that case is not necessary.
Here is some pseudo code
if (inputType is yourtype)
{
if (request.Form["yourkey"] != null)
{
Use Json.Net to deserialize your object type
}
else
{
fall back to BodyModelBinder code
}
}
With this approach you can make it generic, and ApiExplorer will say the way to bind the type is unknown/custom (we haven't decided on the term yet :) )
Note:
Instead of registering the model binder you can use the [ModelBinder(typeof(customBinder))] attribute to apply it sparingly.
Here is a link to the BodyModelBinder code.
There is a new [FromHeader] attribute that allows you to bind directly to http header values if that is what you need.
https://github.com/aspnet/Mvc/issues/1671
https://github.com/aspnet/Mvc/search?utf8=%E2%9C%93&q=fromheader