How to nest #PathVariable in spring-rest? - java

I have a simple #RestController service that takes query parameters, and spring automatically parses them to an bean:
#ResponseStatus(HttpStatus.OK)
#RequestMapping(value = "/rest", method = RequestMethod.GET)
public MyDTO getGiataHotel(#Valid MyParams p) {
Sysout(p.getId()); //prints "123"
}
public class MyParams {
private int id;
//private SubParams subs;
}
Query: .../rest?id=123
Now I'd like to structure the parameter object with nested classes. How can I achieve this?
public class SubParams {
private String name;
//some more
}
Ideally my query should be: Query: .../rest?id=123&name=test, and the "test" string should go into the SubParams bean.
Is that possible?

You have to register a Custom Covertor if you need to set to a inner class. The change would be following:
#ResponseStatus(HttpStatus.OK)
#RequestMapping(value = "/rest", method = RequestMethod.GET)
public MyDTO getGiataHotel(#ModelAttribute("subParam") MyParams params, #Valid MyParams p) {
//Do stuff
}
The subParam denotes that there is a converter registered for conversion.
public class MyParamsConverter implements Converter<String, MyParams> {
#Override
public MyParams convert(String name) {
MyParams myParams = new MyParams();
SubParams subParams = new SubParams();
subParams.setName(name);
myParams.setSubParams(subParams);
return myParams;
}
}

You can achieve this by using the #ModelAttribute annotation : http://docs.spring.io/spring/docs/3.1.x/spring-framework-reference/html/mvc.html#mvc-ann-modelattrib-method-args (this is not in the Path parameters, but in the requestParams either get/post)
#RequestMapping(value="/owners/{ownerId}/pets/{petId}/edit", method = RequestMethod.POST)
public String processSubmit(#ModelAttribute("pet") Pet pet, BindingResult result) {
if (result.hasErrors()) {
return "petForm";
}
// ...
}

maybe u should use RequestMethod.POST, like this
#RequestMapping(value = "/rest", method = RequestMethod.POST)
public ModelAndView getGiataHotel(#ModelAttribute("subparams") SubParams subparams){
SubParams sub=subparams;
//do something...
}

Related

Deserialize json ids to list of objects

I am sending ajax json request to my controller using jackson. This is my entity:
#Entity
public class Template implements Serializable
{
private String templateName;
#ManyToMany(cascade = CascadeType.MERGE, fetch = FetchType.EAGER)
private List<Action> actions;
//getters setters
}
My JSON looks like:
"{"templateName":"aaa",
"actions":["2", "3"]
}"
Controller:
#RequestMapping(value = "/testCreate", consumes = MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody List<ObjectError> testCreate(#Valid #RequestBody final TemplateForm templateForm,
final BindingResult bindingResult)
{
if (bindingResult.hasErrors())
{
return bindingResult.getAllErrors();
}
else
{
//some actions
return EMPTY_LIST;
}
}
How to map action ids from JSON on list of Action object? Thank you.
You can use #InitBinder in case you are using Spring.
Like this:
#InitBinder
protected void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(ArrayList.class, "actions",
new ActionEditor(actionService));
}
and ActionEditor will look like:
public class ActionEditor extends PropertyEditorSupport {
private final ActionService actionService;
public ActionEditor(ActionService actionService) {
this.ActionService = actionService;
}
#Override
public void setAsText(String text) throws IllegalArgumentException {
List<Action> facilities = new ArrayList<Action>();
String[] ids = text.split(",");
Set<Long> actionIds = new HashSet<Long>();
for (String id : ids) {
actionIds.add(Long.parseLong(id));
}
facilities.addAll(actionService.list(actionIds));
setValue(facilities);
}}

Append prefix to Annotated value and use in Overrided method as another Annotated value in Java Spring Framework

I am working on Spring MVC framework, I am using annotations for mapping controllers I am using some common mapping words and common methods in each controller class.
example:
#RequestMapping(value = "/employee_job/list")
#RequestMapping(value = "/employee_job/list_json")
#RequestMapping(value = "/employee_job/add")
#RequestMapping(value = "/employee_job/update")
#RequestMapping(value = "/employee_job/delete")
This is employee_job controller.
So I am creating an interface with the partial mapping and the implementer will append the prefix in that value.
here is the code of interface:
#Controller
public interface CommonController {
#RequestMapping(value = "/list")
public String showList(Model model);
#RequestMapping(value = "/list_json")
public String showListJson(Model model);
#RequestMapping(value = "/add")
public String add(Model model);
#RequestMapping(value = "/update")
public String update(Model model);
#RequestMapping(value = "/delete")
public String delete(Model model);
}
I want to implement it like this:
public class EmployeeJobController implements CommonController{
private static final String prefix = "/employee_job";
#Override
#RequestMapping(value = prefix+value)
public String showList(Model model){
//some code here
}
#Override
#RequestMapping(value = prefix+value)
public String showListJson(Model model){
//some code here
}
#Override
#RequestMapping(value = prefix+value)
public String add(Model model){
//some code here
}
#Override
#RequestMapping(value = prefix+value)
public String update(Model model){
//some code here
}
#Override
#RequestMapping(value = prefix+value)
public String delete(Model model){
//some code here
}
}
But I am getting error "value cannot be resolved to a variable".
What can be the right way to do this?
Thanks.
Where do you define value?
In Annotations you can only use static final Strings. Something like prefix+"/add" should work
A nicer solution would be
#RequestMapping("/employee_job")
public class EmployeeJobController {
#RequestMapping("/add")
public String add(...) {...}
...
}
Declare variables in CommonController interface. Use those variables in the EmployeeJobController class.
#Controller
public interface CommonController {
public static final String showListStr="/list";
#RequestMapping(value = "/list")
public String showList(Model model);
#RequestMapping(value = "/list_json")
public String showListJson(Model model);
#RequestMapping(value = "/add")
public String add(Model model);
#RequestMapping(value = "/update")
public String update(Model model);
#RequestMapping(value = "/delete")
public String delete(Model model);
}
and in child class use this variable
public class EmployeeJobController implements CommonController{
private static final String prefix = "/employee_job";
#Override
#RequestMapping(value = prefix+showListStr)
public String showList(Model model){
//some code here
}
#Override
#RequestMapping(value = prefix+value)
public String showListJson(Model model){
//some code here
}
#Override
#RequestMapping(value = prefix+value)
public String add(Model model){
//some code here
}
#Override
#RequestMapping(value = prefix+value)
public String update(Model model){
//some code here
}
#Override
#RequestMapping(value = prefix+value)
public String delete(Model model){
//some code here
}
}

Converting request parameters to the Class object

I have two POJO classes.
Class 1 is Engine.java:
private String engineId;
public String getEngineId(){
return this.engineId;
}
public void setEngineId(String engineId){
this.engineId = engineId;
}
The Second POJO class is Vehicle.java:
private String type;
private String manufacturer;
private Engine engine;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getManufacturer() {
return manufacturer;
}
public void setManufacturer(String manufacturer) {
this.manufacturer = manufacturer;
}
public Engine getEngine() {
return engine;
}
public void setEngine(Engine engine) {
this.engine = engine;
}
I have a REST Controller for providing information of Vechicles (RequestMethod.GET):
#RequestMapping(method = RequestMethod.GET)
public Vehicle getVechileDetails(Vehicle inputVehicle){
Vehicle vehicle = new Vehicle();
// some processing
return vehicle;
}
When I hit this service and provide the Request parameter as type or manufacturer, then the Spring creates the Vehicle object and populates the value of type and manufacturer. But if I provide the value of engineId, then the Spring is not able to create the Engine object such that vehicle.getEngine().getEngineId() != null
Is there any way in which if I invoke my Rest Service like:
http://localhost:8080/Controller/getVehicleDetails?engineId=12345
then the Vehicle is created with Engine having the value of engineId ?
You can get the vehicleId like this (ResponseEntity structure is included):
#RequestMapping(value = "/Controller/getVehicleDetails", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public
#ResponseBody
ResponseEntity<AjaxResponse> controller(#RequestParam(value = "engineId") Long engineId) {
//Do whatever you want with the engineId
return new ResponseEntity<AjaxResponse>(new AjaxResponse("Success"), HttpStatus.OK);
}
But, for POJOs, I have to warn two things:
Make sure your classes implement Serializable
For the fields which are not certain while converting from Java to Javascript or vice versa, like Date variables, You have to set your JsonSerializer class properly
Update: You wanted to get the object from request, so:
#RequestMapping(value = "/Controller/getVehicleDetails", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE, , consumes = MediaType.APPLICATION_JSON_VALUE)
public
#ResponseBody
ResponseEntity<AjaxResponse> controller(#RequestBody Vehicle vehicle) {
//vehicle.getEngine().getEngineId()
return new ResponseEntity<AjaxResponse>(new AjaxResponse("Success"), HttpStatus.OK);
}
POJOS:
public class Engine implements Serializable {
//...
}
public class Vehicle implements Serializable {
private Engine engine;
}
JS side:
var vehicle = {
engine: {id: 123}//,
//...
}
//via angularjs:
$http.post("http://localhost:8080/Controller/getVehicleDetails", vehicle).success(function(response) {
console.log("success");
});
Here you can refer , where the request body has JSON which converted to Object
See : For references
#RequestMapping(value = EmpRestURIConstants.CREATE_EMP, method = RequestMethod.POST)
public #ResponseBody Employee createEmployee(#RequestBody Employee emp) {
logger.info("Start createEmployee.");
emp.setCreatedDate(new Date());
empData.put(emp.getId(), emp);
return emp;
}

implementing an interface contains #PreAuthorize to a controller causes something wrong, why?

I have this Controller and an Interface, when i try to implement the interface for applying Preauthorize annotation , it cause a damage to the controller , so the methods aren't working at that case . I know that i can apply the annotation directly inside the controller but i'll be happy if i can apply it using the interface as read in Spring's example
public interface PermissionsSecurity {
#PreAuthorize("hasRole('ROLE_ADMIN')")
String deletePost(#RequestParam(value = "id", required = true) Long id);
#PreAuthorize("hasRole('ROLE_ADMIN')")
String permissions(ModelMap model, #RequestParam(value = "q", required = false) String q);
}
Controller :
#Controller
public class PermissionsController implements PermissionsSecurity{
#Autowired
#Qualifier("permissionValidator")
private Validator validator;
#Autowired
private Permissions permissionsService;
#InitBinder
private void initBinber(WebDataBinder binder){
binder.setValidator(validator);
}
#RequestMapping(value="/permissions:delete", method=RequestMethod.POST)
public String deletePost(#RequestParam(value = "id", required = true) Long id) {
permissionsService.delete(id);
return "redirect:/permissions";
}
#RequestMapping(value = "/permissions", method=RequestMethod.GET)
public String permissions(ModelMap model, #RequestParam(value = "q", required = false) String q){
model.addAttribute("q", (q != null)? q : "");
model.addAttribute("viewTemplate", "permissions");
model.addAttribute("roles", permissionsService.getAll());
return "welcome";
}
}

Is it alright to create an object of modelandview in each method of the class?

I have following controller which is serving different requests. I am wondering if the way that I create ModelAndView is correct? I am creating one object in each method. Is there any better approach?
#RequestMapping(method = RequestMethod.GET)
public ModelAndView showNames() {
...
ModelAndView model = new ModelAndView("names");
model.addObject ....
return model;
}
#RequestMapping(value = "/name/{name}", method = RequestMethod.GET)
public ModelAndView showNameDetails(#PathVariable String name) {
...
ModelAndView model = new ModelAndView("name");
model.addObject ...
return model;
}
#RequestMapping(value = "/name/{name}/{item}", method = RequestMethod.GET)
public ModelAndView showItemsOfName(#PathVariable String name,
#PathVariable String item) {
...
ModelAndView model = new ModelAndView("item");
model.addObject ....
return model;
}
You can ask Spring to inject the Model for you, and then return the view name from the method, e.g.
#RequestMapping(method = RequestMethod.GET)
public String showNames(Model model) {
...
model.addObject ....
return "names";
}
#RequestMapping(value = "/name/{name}", method = RequestMethod.GET)
public String showNameDetails(#PathVariable String name, Model model) {
...
model.addObject ...
return "name";
}
#RequestMapping(value = "/name/{name}/{item}", method = RequestMethod.GET)
public String showItemsOfName(#PathVariable String name,
#PathVariable String item, Model model) {
...
model.addObject ....
return "item";
}
It's a bit cleaner, and less code.

Categories