Multiple parameters into one Spring controller argument - java

I have a class setup like the following...
public class Person {
protected String firstName;
protected String lastName;
protected Integer age;
...
}
A controller that looks like this...
#RequestMapping(value={"/person"}, method = RequestMethod.GET)
public void returnPerson(Person person, ModelMap model, HttpServletResponse response) {
....
}
And I am passing in a straight URL such as...
Link
Is it possible to pass all of these into the "Person" argument in my controller rather than making numerous #RequestParam arguments for each one? Especially if I am going to be passing in a good amount of params?

Yes you can do that in the exact way you are describing as long as you are following the property naming convention for Person.
What problem do you get when you try it this way?

You can do exactly what you're asking for using model binding:
#ModelAttribute("person")
public Person getPerson() {
return new Person();
}
#RequestMapping(value="/person", method=RequestMethod.GET)
public void handle(#ModelAttribute("person") Person person, BindingResult errors, ModelMap model, HttpServletRequest req) {
...
}
The model attribute will be initialised by the getPerson method and when the handle method fires, any parameters from the request will be automatically bound to corresponding properties in the new Person object. The BindingResult holds any errors as a result of the binding e.g. if you passed "XYZ" as the age field (an integer).
More information here http://static.springsource.org/spring/docs/current/spring-framework-reference/html/validation.html

This question is also nicely answered here:
Passing parameters from JSP to Controller in Spring MVC
read the answer carefully, hopefully you'll get your answer correctly.

Related

Pass value to controller in Spring MVC, what is the difference?

When I read some codes written with Spring MVC in an old project, I notice that the author using two similar method to pass value to controller as follows:
#RequestMapping(value="/print")
public String PrintInfo(#RequestParam("name") String name,#RequestParam("age") int age) {
.......
}
Or
#RequestMapping(value="/print")
public String PrintInfo(String name,int age) {
.......
}
Both them work well.
The difference is whether it use the #RequestParam.
So what's the main difference between them? Which one is better, and why?
This basically sounds to me like you're asking "what is a RequestParam and why should I use it?"
The RequestParam allows you to bind the method parameter argument to the web request parameter. Without any other attributes, your example tells Spring that a name and age parameter are required and Spring will know to associate those two parameters against the incoming request. You can optionally set required to false to, well, make the argument optional:
public String PrintInfo(#RequestParam("name", required = false) String name,
#RequestParam("age") int age) {
As an extremely useful feature, you can also provide a defaultValue in case you receive an empty value from the request. So you can do:
public String PrintInfo(#RequestParam("name", defaultValue="John Doe") String name,
#RequestParam("age") int age) {
...and you'll never deal with a null name.
Finally, using it also does some magic type conversions, like for example automatically using an Integer type. In your example, you could have used:
public String PrintInfo(#RequestParam("name") String name,
#RequestParam("age") Integer age) {
...and Spring would have boxed it automatically without you doing any extra work.
There's nothing inherently wrong with leaving off the RequestParam annotation, but you're essentially saying no to Spring enabling these features as you have in your second case.
Aside:
#RequestMapping(value="/print") can be more simply written as #RequestMapping("/print")
If the name of request parameter and the name of method arguments will be equal, then Spring will bind parameters automatically by names. For example, you have incoming GET request:
http://localhost:8080/print?name=somename&age=30
And controller method:
#RequestMapping(value="/print")
public String PrintInfo(String name,int age) {
...
}
In this case you don't need to specify #RequestParam annotation for parameter. Because names in request and names of methods args are equals.
But when names are not equals, then you need to specify the correspondence of names explicitly with #RequestParam. For example:
http://localhost:8080/print?user_name=somename&user_age=30
And controller method:
#RequestMapping(value="/print")
public String PrintInfo(#RequestParam("user_name") String userName, #RequestParam("user_age")int userAge) {
...
}
So #RequestParam needed to help the Spring make bindings properly, when request param names and method args names are different.
Acutally, many developers always use #RequestParam even when names are equal. For example empty #RequestParam:
#RequestMapping(value="/print")
public String PrintInfo(#RequestParam() String name, #RequestParam() int age) {
...
}
Because this annotation shows that argument comes from request and makes your code more clear and readable.

Passing POJO class, object to another POJO

I am sure this question might have been asked couple of times here but I am not understanding what query I should use.
What I want to do is, Passing POJO to another POJO where parameter could be dynamic
like example below
Class DataPOJO{
private String name;
public String getName(){
return this.name;
}
public void setName(String name){
return this.name;
}
}
I want to make another POJO where I can pass value like
RequestmakerPOJO request = new RequestmakerPOJO(authorisationObject, dataPOJO, DataPOJO);
Where dataPOJO would be object I created and DataPOJO.class it's structure, later I can pass any kind of pojo to this new Requestmaker class with it's structure definition and object just like. HashMap<ObjectType, ObjectType2>
But I want only 1 Object type to be passed and then it's object. I am new at java so I don't know what to call these scenarios. Please help me out with the query or solution.
:) thanks
You should declare RequestmakerPOJO as a generic class:
class RequestmakerPOJO<T> {
...
}
Now you can use T as a type wherever you want. For example, the constructor can be
RequestmakerPOJO(AuthPOJO auth, T data) {
...
}
To declare a variable
RequestmakerPOJO<DataPOJO> request = new RequestmakerPOJO<>(auth, data);
For more details, research generics in Java.

Spring MVC controller parameters binding: replace parameters with POJO

I have a simple controller method with more than 7 parameters and would like to refactor it using a model object instead, i.e. to extract a parameter object:
#RequestMapping(value="/{one}")
public String controllerMethod(#PathVariable(value="one") String one, #RequestParam String two, ... #RequestBody body) {
...
}
I tried to extract an object with setters and getters and pathVariable and requestParameters are mapped by name. However I have troubles making the same for #RequestBody, it doesn't work for me even if I put #RequestBody into setter...
public class Parameters {
private String one; // pathVariable
private String two; // requestParameter
private String body;// requestBody - always NULL!
// other fields definition
public setBody(#RequestBody String body) {this.body = body}
//other setters/getters
}
How to keep #RequestBody parameter in extracted POJO?
Another question is how to control name of parameters, i.e. if
parameter name differs from the field name in POJO, is there any
annotation? This one doesn't work:
public void setOne(#RequestParameter(value="o") String one) {this.one = one}
How to mark the fields as required or give a default value like in the #RequestParameter annotation?
For the (1) I would simply keep #RequestBody as a separate parameter though I don't like it much.
Ok, looks like the only way of doing (2) and (3) is through customizing data binding: the similar question
Feel free to post another easy solution if you know about it.

java jersey 2 how to process regular html form array with post?

I have a jersey endpoint
#Path(value = "/testfields")
#POST
#Consumes({"application/x-www-form-urlencoded"})
public Response acceptFields(#BeanParam MyWrapper initialWrapper,String entity) {
//.......
}
MyWrapper is:
class MyWrapper{
#FormParam("param1")
private String param1;
#FormParam("inners")
private List<MyInnerWrapper> inners;
//..getters setters
}
class MyInnerWrapper{
#FormParam("innerParam1")
private String innerParam1;
//.... getters setters
}
I have request POST entity string:
param1=aaa&inners[0]["innerParam"]=bbb&inners[1]["innerParam"]=nnn
The issue is I can obtain parent`s field param1 with #BeanParam annotation, but I can't obtain inner list of custom classes, why? How to process regular html form array? I need to get my class evaluated with its inner classes in my endpoint. I tried array, list of objects, nothing works. Thanks
AFAIK, that type of syntax is not supported in Jersey. If you want to use custom types for #FormParam, then you need to meet the requirements of at least one those listed in the Javadoc. One options is to just have a constructor with a String argument. For example
public class MyInnerWrapper {
private final String innerParam;
public MyInnerWrapper(String param) {
this.innerParam = param;
}
public String getInnerParam() {
return innerParam;
}
}
Then all you need to do is send this request
param1=blahparam&inners=first&inners=second&inners=third
Then you can have
#FormParam("inners")
private List<MyInnerWrapper> inners;
There's no need for an [] to specify indices. Duplicates are allowed. That's why we are allowed to have lists and arrays for the #FormParam types.
Now if you want to have more than one property and then try to map them like you currently are, I don't think that will work. At least not in Jersey. I would recommend maybe looking into using JSON if you need more complex types. Otherwise just stick to simple keys.

Is it possible to use a value for a #RequestMapping that is a String but not a String literal?

Is there a way to use an Enum value in a RequestMapping?
#RequestMapping(value = "/example",
method = RequestMethod.POST)
public final void foo(final HttpServletResponse response,
I want to use a URL value that is already stored in an Enum.
However, I get compile time errors when I try to put anything except a String literal in the RequestMapping.
How does it know the difference between a String literal and a String that is not a String literal ( not sure what that's called ) ?
This is what I tried but it failed at compile time:
#RequestMapping(value = FooEnum.Example.getStringValue(),
method = RequestMethod.POST)
public final void foo(final HttpServletResponse response,
I also tried using String.format but it doesn't like that either:
#RequestMapping(value = String.format("%s", FooEnum.Example.getStringValue()),
method = RequestMethod.POST)
public final void foo(final HttpServletResponse response,
Only literal values can be assigned to annotation attributes because they must be known at compile-time when annotations are processed. Yes, you could use an enum value, where "enum value" is FooEnum.Example, but not on an attribute that takes a String value, and you can't call a method on it.
Tying your URL to an enum value seems funny; I wouldn't want my URLs to change if I updated the enum. Are you actually generating the client links using these same enums? Maybe instead you could just query Spring's Handler bean for the URLs?
There's also the Spring Expression Language, but I only know that it works in #Value annotations, I'm not sure about #RequestMapping
If you're trying to catch multiple URLs in one method, you could use #PathVariable

Categories