How to use #FormParam if form elements are dynamically created - rest

Since html form elements are dynamically created in this application, the number of elements are not known. How does one obtain element information using #FormParam annotation? For example, the below code obtains information for two form elements:
#POST
#Path("/newpage")
#Produces("text/html")
public String func(#FormParam("element1") String firstElement,
#FormParam("element2") String secondElement) throws IOException
{
// your code goes here
}
This is not possible as we don't know the number of elements.

I can't think of a way to do this using #FormParam but you can use #Context to access the HttpServletRequest (which references a map of all form parameters):
// you can make this a member of the Resource class and access within the Resource methods
#Context
private HttpServletRequest request;
#POST
#Path("/newpage")
#Produces("text/html")
public String func() throws IOException
{
// retrieve the map of all form parameters (regardless of how many there are)
final Map<String, String[]> params = request.getParameterMap();
// now you can iterate over the key set and process each field as necessary
for(String fieldName : params.keySet())
{
String[] fieldValues = params.get(fieldName);
// your code goes here
}
}

The correct answer is actually to use a MultivaluedMap parameter to capture the body (tested using Jersey):
#POST
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
#Produces(MediaType.TEXT_HTML)
public String post(MultivaluedMap<String, String> formParams)
{
... iterate over formParams at will

Related

Reading the contents of a body of a POST request in java (using REST)

Suppose I make a POST request using POSTMAN and have a body in json format. I want to read the contents of body and pass it in a method. How to do it ?
I can see that there is #QueryParam, #PathParam, #HeaderParam etc annotation are used to read the parameters. I don't get how to read body.
say body is
{
"param1":"value1",
"param2":"value2",
"param3":"value3",
}
ServerSide java code:
#POST
#Path("/myresource")
public Response addParams( String param1, String param2, String param3)
{
do somthing.
}
So I wanted this param1,param2,parmam3 values to be read from requestbody. Is it possible ?
Define a class like:
public class Foo {
String param1;
String param2;
String param3;
// Default constructor, getters and setters
}
Then use it as follows:
#POST
#Path("/myresource")
#Consumes(MediaType.APPLICATION_JSON)
public Response addParams(Foo params) {
String param1 = params.getParam1();
String param2 = params.getParam2();
String param3 = params.getParam3();
...
}
Alternatively, use a Map<String, String>:
#POST
#Path("/myresource")
#Consumes(MediaType.APPLICATION_JSON)
public Response addParams(Map<String, String> params) {
String param1 = params.get("param1");
String param2 = params.get("param2");
String param3 = params.get("param3");
...
}
Just ensure that you have a JSON parser such as Jackson or MOXy configured in your application.
Don't know which Java framework you use, but you could declare a #RequestBody parameter in your method and "map" it to a POJO that will correspond to the incoming JSON (just like #Smutje said in the comment).
For example, in Spring, we do it like this,
#PostMapping(value = "/example",
consumes = MediaType.APPLICATION_JSON_UTF8_VALUE,
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ResponseEntity postExample(#RequestBody ExamplePOJO examplePOJO) {
// Do something
}

Content Type Not Set Junit REST POST test

I have a Spring Boot REST application. The unit tests for all of the GET requests are working perfectly; however, the POST requests are all returning
java.lang.AssertionError: Content type not set
Here is the controller:
#RestController
public class ClassificationController {
private IClassificationService classificationService;
#Autowired
public ClassificationController(IClassificationService classificationService) {
this.classificationService = classificationService;
}
#RequestMapping(value="/category", method = RequestMethod.POST, produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
#ResponseStatus(HttpStatus.CREATED)
#ResponseBody
public CategoryDTO createCategory(#RequestBody final CategoryDTO category) throws MctException {
return classificationService.createCategory(category);
}
The unit test I have is:
#RunWith(MockitoJUnitRunner.class)
public class ClassificationControllerTest {
#Mock
private IClassificationService classificationService;
#Before
public void setUp() {
mockMvc = MockMvcBuilders.standaloneSetup(new ClassificationController(classificationService)).build();
}
#Test
public void createCategoryTest() throws Exception {
String jsonTask = String.format("{\"id\": \"2\",\"categoryName\": \"Category Name 2\"}");
MvcResult result = mockMvc.perform(post("/category")
.contentType(MediaType.APPLICATION_JSON_UTF8)
.content(jsonTask))
.andDo(MockMvcResultHandlers.print())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(content().string(containsString("\"id\":2")))
.andExpect(content().string(containsString("\"categoryName\":\"Category Name 2\"")))
.andExpect(status().isCreated())
.andReturn();
}
I have also tried this with a CategoryDTO object instead of the String jsonTask with the same result.
I discovered it was just failing on that assertion because it was the first one, but it just wasn't returning anything from the endpoint. I am returning the content type because it is returning the object that is being inserted so a content type is valid. I ended up changing my test create the content JSON using an ObjectMapper and then I had to add an equals method on my domain object....once I added the equals method, the test passed. I didn't realize the mock framework used that method.
#Test
public void createClassTest() throws Exception {
String jsonInString = objectMapper.writeValueAsString(singleClass);
when(classificationService.createClass(5, singleClass)).thenReturn(singleClass);
MvcResult result = mockMvc.perform(post("/class/5")
.contentType(MediaType.APPLICATION_JSON_UTF8)
.content(jsonInString))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(content().string(containsString("\"id\":1")))
.andExpect(content().string(containsString("\"className\":\"Test Class Name 1\"")))
.andExpect(status().isCreated())
.andReturn();
verify(classificationService).createClass(5, singleClass);
}
Judging by the assertion error, it seems the endpoint is not returning a MediaType.APPLICATION_JSON_UTF8. Try removing the contentType check or debugging and seeing what the endpoint is actually returning. Once again, judging by the error you are seeing, seems it's not returning any content type at all. So you should probably be checking that no content type is set.
I know typically the POST request I usually test do not return a contentType at all.
After all, it could be that endpoint is actually doing something incorrectly if you do expect the content type to be set.

How to get the url of called method resteasy

I making one Rest Service with Restaeasy (java) that have to return the same URL that was called but with one new string
Example Call service:
Post => mybase/myservice/somewrite with some JSON
| Reponse => mybase/myservice/somewrite/123456
So i want to make the mybase/myservice/somewrite url with one generic logic, because if i put String returnURL="mybase/myservice/somewrite"; and i change for example the name of mybase the reponse will not be good
I want somthing like this
someLogicService(JSON);
id=getId();
URL=getContextCallURL();
return URL+\/+id;
But i dont know if this is possible to do it, and less how to do it
You could also inject an instance of type UriInfo using the annotation Context within your resource, as described below:
#Context
private UriInfo uriInfo;
#POST
#Path("/")
#Consumes(MediaType.APPLICATION_JSON)
public Response makeContact(Contact contact) {
String requestUri = uriInfo.getRequestUri();
(...)
}
Hope it helps you,
Thierry
I found the answer to my problem, i put inject with #context the httpRequest to my function and call absolutPath :
#POST
#Path("/")
#Consumes(MediaType.APPLICATION_JSON)
public Response makeContact(Contact contact, #Context HttpRequest request) {
return Response.ok().header("location", request.getUri().getAbsolutePath().getPath() + contactService.makeContact(contactJSON)).build();
}

Spring multiple #ModelAttribute methods in the same #Controller

I have a page with two different forms (with two different submits) on Spring MVC 3, and I have a problem with #ModelAttribute methods. When I have two on the same controller, they are not always executed making the model to be NULL.
The code:
#Controller
#RequestMapping(value = "/session/admin/permission/{userId}")
public class PermissionController {
#Autowired
private UserManager userManager;
#ModelAttribute("passwordValidation")
private PasswordValidation getPasswordModel(){
return new PasswordValidation();
}
#ModelAttribute("user")
private User getUserModel(#PathVariable("userId") String userId){
//This is not executed
return userManager.getUser(userId);
}
#ModelAttribute("permissionsAvailable")
private PermissionsAvailable getPermissionsModel(#ModelAttribute("user") User user) {
return new PermissionsAvailable();
}
#RequestMapping(method = RequestMethod.GET)
public String adminPermission(){
return "/security/permission";
}
#RequestMapping(method = RequestMethod.POST, params="changeRoles")
public String modifyPermission(#ModelAttribute("permissionsAvailable") PermissionsAvailable permissions,
HttpServletRequest request, #ModelAttribute("user") User user,
final RedirectAttributes redirectAttributes){
//Modify something
}
#RequestMapping(method = RequestMethod.POST, params="changePassword")
public String modifyPassword(
#ModelAttribute("passwordValidation") PasswordValidation passwordValidation,
#ModelAttribute("user") User user,
HttpServletRequest request, BindingResult bindingResult,
final RedirectAttributes redirectAttributes){
return "newpage";
}
}
Don't know why, sometimes everything goes ok and every method is executed, but sometimes they are not executed.
UPDATE: I have two different controllers with the same problem so it must be an error on Spring or something I'm doing wrong.
Thanks.
The documentation doesn't mention anywhere that it's possible to use #ModelAttribute on an argument to a #ModelAttribute annotated method, like you're doing in your "getPermissionsModel()" method. It's possible that's not supported, since it's not documented as being supported. You might want to try either removing the "#ModelAttribute("user") User user" argument from your "getPermissionsModel()" method, and/or instead try just using one #ModelAttribute method to set all your model attributes:
#ModelAttribute
public void setAttributes(#PathVariable("userId") String userId, Model model) {
model.addAttribute(new PasswordValidation());
model.addAttribute(userManager.getUser(userId));
model.addAttribute(new PermissionsAvailable());
}

How do I access the HTTP request?

Say normally I have a REST method in Java
#POST
#Path("/test")
#Produces(MediaType.APPLICATION_JSON)
public String showTime(#FormParam("username") String userName) {
:
:
:
}
which is fine. However, I'm wondering is there a way I can access the full HTTP request with Jersey such as
#POST
#Path("/test")
#Produces(MediaType.APPLICATION_JSON)
public String showTime(#FormParam("username") String userName,#XXXXXX String httpRequest) {
:
:
:
}
where some annotation would give me the full HTTP request to store in a variable. I have tried using #POST but it doesn't seem to work. Any suggestions?
You can use the #Context annotation:
#POST
#Path("/test")
#Produces(MediaType.APPLICATION_JSON)
public String showTime(
#FormParam("username") String userName,
#Context HttpServletRequest httpRequest
) {
// The method body
}
If you want to get the request body, you could use the tip lined out in this post: How to get full REST request body using Jersey?
If you need to know more about the request itself, you could try the #Context annotation as mentioned by sdorra.
I wrote a helper function to address this. Simply extracts request headers and places them in a map.
private Map<String, String> extractHeaders(HttpServletRequest httpServletRequest) {
Map<String, String> map = new HashMap<>();
Enumeration<String> headerNames = httpServletRequest.getHeaderNames();
while (headerNames.hasMoreElements()) {
String header = headerNames.nextElement();
map.put(header, httpServletRequest.getHeader(header));
}
return map;
}