Spring Bind #PathVariable to JavaBean - java

I try to bind an object in Spring controller so it can be used as #PathVariable. I want to do so, since there are some #PathVariable that I want to pass. I have tried the solution from Bind Path variables to a custom model object in spring and also Is it possible to bind path variable and request param into a single object?. But both are not working.
I have created something like this in my controller.
#RestController
#RequestMapping("/buildings")
#RequiredArgsConstructor
public class BuildingController {
private final BuildingService buildingService;
#GetMapping("/{buildingId}/floors/{floorId}/rooms/{roomId}/sections")
public Flux<SectionDTO> getRoomSections(BuildingRequestBean request) {
return this.buildingService.getRoomSections(request);
}
}
and BuildingRequestBean.java like this
#Getter
#Setter
public class BuildingRequestBean {
private String buildingId;
private String floorId;
private String roomId;
}
When I check BuildingRequestBean, the attributes is null when I call it with GET localhost:8080/buildings/a/floors/b/rooms/c/sections.
However, it will not null if I call it as #RequestParam, something like this GET localhost:8080/buildings/{buildingId}/floors/{floorId}/rooms/{roomId}/sections?buildingId=a&floorId=b&roomId=c
How to fix it so it will behave like #PathVariable rather than behave like #RequestParam?

U can get it by using #ModelAttribute
Try with this:
#GetMapping("/{buildingId}/floors/{floorId}/rooms/{roomId}/sections")
public Flux<SectionDTO> getRoomSections(#ModelAttribute BuildingRequestBean request) {
return this.buildingService.getRoomSections(request);
}

PathVariable must be added to the function parameter
Try this :
#GetMapping("/{buildingId}/floors/{floorId}/rooms/{roomId}/sections")
public Flux<SectionDTO> getRoomSections(#PathVariable String buildingId,#PathVariable String floorId ,#PathVariable String roomId) {

Related

Make one property in request body not required

I have the following interface:
public interface TestRequestView {
String getCountryCode();
String getRegionCode();
}
It's used in several end points like so:
#PostMapping("/my/path/{id}")
public String test(#RequestBody TestRequestView request, #PathVariable String id) {
...
}
I would like to add a property to the TestRequestView that is only used in one new endpoint without breaking the rest, how can I mark that one property as ignorable? Something like:
public interface TestRequestView {
String getCountryCode();
String getRegionCode();
String getEmail(); // make this not required
}
Usually it is better to use 1 such a model per endpoint so they are independent. If you share models between endpoints this should be useful
This may help
You can use the #JsonIgnoreProperties annotation
Example:
#JsonIgnoreProperties(value = {"email"})
public interface TestRequestView {
String getCountryCode();
String getRegionCode();
#JsonProperty(required = false)
String getEmail();
}
Add annotation #JsonInclude(Include.NON_NULL) at class level for your TestRequestView. When passing your param you can pass it without that value and in your controller it will be received with that param as null. You just need to make sure that your controller can handle such case

Customize Path to REST params in Pageable

I am using spring to build a REST api with PageAble, to get numberofPages,itens...
first, i did a mapping like this
public ResponseEntity<Data> findByName(#PathVariable(value="name",required=true) String name, #RequestParam(value="page", defaultValue="0") Integer page, #RequestParam(value="qtd", defaultValue="10") Integer linesPerPage, #RequestParam(value="sort", defaultValue="nome") String sort, #RequestParam(value="direction", defaultValue="ASC") String direction)
So in my url i get for example "url?name=erick&direction=asc" but i need to change to "url?name=erick!asc"
How can i change it?
You can do this. Look at page 3 of https://www.ietf.org/rfc/rfc1738.txt
In you case,you should use #RequestParam("name") instead of #PathVariable.Then the request url will be like "url?name=erick&direction=asc"
Spring has three kinds of Annotation.
#PathVariable
This annotation means the variable is on the url.For example:
#RequestMapping("/{id}")
public void pathVariable(#PathVariable("id") Long id){}
The variable was put between the brace at the url.
#RequestParam
This annotation means the variable is part of the quest param,the request url looks like
stackoverflow.com?name=hhhh
For example:
#RequestMapping("/")
public void requestParam(#RequestParam("id")Long id){}
#RequestBody
This annotation means you will receive some data from request body.And some kind of converter,like jackson,will convert it into a properly object.For example:
#PostMapping("/")
public void requestBody(#RequestBody Example example){}

How to use #PathVariable to Pojo?

I've created a POJO like this.
public class Param(){
#NotNull
private Sring paraA;
#NotNull
private Sring paraB;
//Setter and getter
}
And I want to use JSR303 to check it.
#RequestMapping(value = "/test/{paraA}/{paraB}")
#ResponseBody
public BaseJsonRsp test(#PathVariable #Valid Param param) {
//doSomething
}
But this code it doesn't work and I've got following error
HTTP Status 500 - Missing URI template variable 'value' for method parameter of type PatchValue!
Why? How to fix it? Thanks.
Have a look at the Spring Refererence Docs on #PathVariable:
A #PathVariable argument can be of any simple type such as int, long, Date, etc.
If you want to use your Param type as the controller method argument, you won't be able to do so using #PathVariable.
Alternatively, you can map your parameters to individual String variables (using #PathVariable), and then manually construct your Param after that. Note that #PathVariable assumes that the placeholder in your URL is the same as the variable name by default. If your variable name doesn't match, you'd do something like
#RequestMapping(value = "/test/{paraA}/{paraB}")
#ResponseBody
public BaseJsonRsp test(#PathVariable("paraA") String myParam,
#PathVariable("paraB") String otherParam) {
//doSomething
}
You need to explicity set the variable values from the URL into the Param object.
#RequestMapping(value = "/test/{paraA}/{paraB}")
#ResponseBody
public BaseJsonRsp test(#PathVariable("paraA") String paramA, #PathVariable("paraB") String paramB) {
Param param = new Param(paramA, paramB);
}
#PathVariable assumes that the placeholder in your URL is the same as the variable name by default. You need to do this
#RequestMapping(value = "/test/{paraA}/{paraB}")
#ResponseBody
public BaseJsonRsp test(#PathVariable("paraA") String paramA,
#PathVariable("paraB") String otherparam) {
Param param = new Param(paramA, paramB);
}

Spring Rest Controller, Path Variables on an overriden method's arguement

I have a controller annotated with #RestController and it implements an interface:
public interface ContratEndpoint {
String ROOT = "/api/contrats";
String GET_CONTRAT = "";
String GET_CONTRAT_PER_PK = "/{idContrat}";
#RequestMapping(value = GET_CONTRAT)
Contrat getContrat(#RequestParam(value = "contratId")Long contratId);
#RequestMapping(value = GET_CONTRAT_PER_ID)
ExtContrat getContratById(#PathVariable("idContrat") Long idContrat);
}
The controller:
#RestController
#RequestMapping(value = ContratEndpoint.ROOT)
public class ContratController implements ContratEndpoint {
//Injecting Services....
#Resource
private Mapper mapper;
#Override
public Contrat getContrat(Long contratId) {
return mapper.map(contratService.get(contratId),Contrat.class);
}
#Override
public ExtContrat getContratById(#PathVariable("idContrat") Long idContrat){
Preconditions.checkArgument(idContrat !=null);
return mapper.map(contratService.get(idContrat),ExtContrat.class);
}
.The above Code works just fine.
. But For the first inherited method , I didn't have to annotate arguments with #RequestParam and it worked just fine.
As for the second method I tried at first :
#Override
public ExtContrat getContratById(Long idContrat){
Preconditions.checkArgument(idContrat !=null);
return mapper.map(contratService.get(idContrat),ExtContrat.class);
}
. I expected the same behaviour Like the first Method, But i was wrong and the code ended up firing an IllegalArgumentException because of the check in ligne Preconditions.checkArgument(idContrat!=null).
My question is what is so specific about #PathVariable that i've missed ?
Or is it just something is wrong with my approach?
Thanks.
There is difference between Request param and path variable,seee below post that you can confirm with your uri the cause for the exception :
#PathVariable is to obtain some placeholder from the uri (Spring call it an URI Template) — see Spring Reference Chapter 16.3.2.2 URI Template Patterns
#RequestParam is to obtain an parameter — see Spring Reference Chapter 16.3.3.3 Binding request parameters to method parameters with #RequestParam
Assume this Url http://localhost:8080/SomeApp/user/1234/invoices?date=12-05-2013 (to get the invoices for user 1234 for today)
#RequestMapping(value="/user/{userId}/invoices", method = RequestMethod.GET)
public List<Invoice> listUsersInvoices(
#PathVariable("userId") int user,
#RequestParam(value = "date", required = false) Date dateOrNull) {
...
}

Do not serialize subtype properties with Jackson in Spring MVC 3

I am using Spring MVC with a controller like this:
#RequestMapping(value = "/list", method = RequestMethod.GET, produces = "application/json")
public #ResponseBody List<Service> list() {
return services.list();
}
The model is like this:
public class Service {
private User user;
...
}
public class User {
private String name;
...
}
public class ExtendedUser extends User {
private Location location;
...
}
For sure, an object of type ExtendedUser is created in the application and set in Service. When the controller /list answer the request, an object of type ExtendedUser is serialized despite the reference in Service class is User. I would like to know if there is some way with annotations to only serialize supertype (the referenced type) and avoid the subtype propierties.
Taking the example into account, I want a JSON without the location property to be returned.
Thanks in advance
Try #JsonInclude(Include.NON_NULL) on ExtendedUser
Your statement of "I want a JSON without the location property to be returned" can easily be accomplished using the #JsonIngore annotation:
public class ExtendedUser extends User {
#JsonIgnore
private Location location;
...
}
Is that what you're trying to do, though, just eliminate the location from the response, or does the actual type returned (type id) matter? If I'm off base, please post your expected JSON result and your actual JSON result.
I think this will do the trick:
#JsonSerialize(using=User.class)
See this related answer: https://stackoverflow.com/a/13926740/1292605
I recommend to use as property of #JsonSerialize. BTW, #JsonSerialize can be declared on the fields so that it will not impact the common behavior of serialization of User or ExtendedUser.
public class Service {
#JsonSerialize(as = User.class)
private User user;
...
}

Categories

Resources