"Unexpected end of JSON input" on a Void SpringMVC Ajax Controller - ajax

I have a SpringMVC/Thymeleaf applications where the following Ajax handling works perfectly fine if I return a boolean. However, as soon as the method is void, then I get the error
Unexpected end of JSON input in Firebug. This is a POST request.
#ResponseBody
#PostMapping("/addOrUpdate")
public void /*boolean works!*/ addOrUpdate(#RequestBody String json) throws Exception {
service.addOrUpdateUserRoles(json);
/*boolean works - return true;*/
}
JS
$.ajax({
type : "post",
dataType : 'json',
contentType : 'text/plain',
url : 'addOrUpdate',
data : id
})
.then(function() {
//...
})
.fail(function(jqXHR, textStatus, errorThrown) {
//...
});
If I just remove #ResponseBody from the method definition, Thymeleaf complains,
org.thymeleaf.exceptions.TemplateInputException: Error resolving template [addOrUpdate], template might not exist or might not be accessible by any of the configured Template Resolvers
I followed the ResponseEntity example here, but it didn't help -- same error, JS goes into the Error section with Unexpected End of Input.
#ResponseBody
#PostMapping("/addOrUpdate")
public ResponseEntity addOrUpdate(#RequestBody String json) throws Exception {
service.addOrUpdate(json);
return new ResponseEntity(HttpStatus.OK);
}

With dataType : 'json', you are telling jQuery that you're expecting JSON as a response. An empty response is no valid JSON, and the error message Unexpected end of JSON input is telling you exactly that.
If you intend not to return anything from the addOrUpdate controller method, remove the #ResponseBody annotation, as there is no response body, and stick to the ResponseEntity but use HttpStatus.NO_CONTENT instead to inform clients in your response that there's no content to be expected. Also, change your dataType to something that may be empty, like 'text'.

As the exception says, the point of failure is input.
You need to send json format input.
$.ajax({
type : "post",
dataType : 'json',
contentType : 'text/plain',
url : 'addOrUpdate',
data : {id: id}
...

FINAL SOLUTION based on digitalbreed's answer
Controller
#PostMapping("/addOrUpdate")
public ResponseEntity<String> addOrUpdate(#RequestBody String json) throws Exception {
try {
service.addOrUpdate(json);
return new ResponseEntity<String>(HttpStatus.OK); // No exceptions
}
catch (Exception e) {
log.error("Error", e);
return new ResponseEntity<String>(HttpStatus.BAD_REQUEST); // This will enable JS to catch the Exception from Ajax
}
}
JS
$.ajax({
type : "post",
dataType : 'text', // Returns a ResponseEntity, not JSON (Void method)
contentType : 'text/plain',
url : 'addOrUpdate',
data : somedata
})
.then(function() {
//...
})
.fail(function(jqXHR, textStatus, errorThrown) {
//... - will come here for a ResponseEntity of 'Bad Request'
});

Related

ModelView, Ajax and Json return

In my code, i have two RequestMapper in my Controller which is designed this way :
#Controller
#RequestMapping("/myHostel.html")
public class HostelController
{
#RequestMapping(method = RequestMethod.GET)
public ModelAndView getText()
{
// do some cool stuff but not the point here
}
#RequestMapping(method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public String getMyUrl()
{
String myVariable;
return "{\"myUrl\": \""+myVariable+"\""}";
}
}
And my ajax code :
function openNewTab() {
$.ajax({
url : 'myHostel.html',
type: "POST",
dataType: "json",
beforeSend: function(xhr) {
xhr.setRequestHeader("Accept", "application/json");
},
success : function(response){
console.log(response);
window.open(response.url, '_blank');
},
error: function(jqXHR, exception, errorThrown)
{
console.log(jqXHR.status);
console.log(exception);
console.log(errorThrown);
}
});
}
and my button is kinda like this :
<button tabindex="0" id="mySweetButton" class="btn btn-primary"
onclick="openNewTab();" >
Open a new tab
</button>
And what i get is :
200
parsererror
SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data
--
I've tried with putting a session variable in the model and a making a window.open(URL_IN_SESSION);
But if you reload the page, it's calling it again.
Making a c:remove on the variable when it's not used to cancel this problem but to no avail.
I have to get a variable from my ModelView after some previous call and open it in ajax (or javascript whatever as long as it works) to have my main page and my new tab with the custom URL.
If anyone has a idea on what i'm doing wrong ? (I need a custom URL made in my controller by previous GET call with user choices.)
Thank you for reading !
Solved by making just another GET requestMapping using no parameters and with value = ("/myHostel.html/getMyUrl.html")
One of the problem was the filters that only allowed .html url for the mapping.
The other was the JSON, just using :
#RequestMapping(method = RequestMethod.GET, value = "/getUrl.html")
public ResponseEntity<String> sendUrl()
{
return new ResponseEntity<>(getMyUrl(), HttpStatus.OK);
}
And parsing the return in ajax :
function openNewTab() {
$.ajax({
url : 'myHostel.html/getUrl.html',
type: 'GET',
dataType: 'text',
success : function(data){
window.open(data, '_blank');
}
});
}
And it solved the problem.

Spring Exception: org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported

I have a ResponseEntiy that receives a comment:
#RequestMapping(value="/save-comment", method=RequestMethod.POST)
#ResponseBody
public ResponseEntity<?> saveComment(#RequestParam("name") String comment, #RequestParam("id") long id) {
SiteUser user = authController.getUser();
String cleanedCommentBody = htmlPolicy.sanitize(comment);
StatusUpdate status = statusUpdateService.getOneById(id);
Comment createdcomment = new Comment();
createdcomment.setCommentdate(new Date());
createdcomment.setCommenttext(cleanedCommentBody);
createdcomment.setStatusUpdate(status);
createdcomment.setSiteUser(user);
commentService.createComment(createdcomment);
return new ResponseEntity<>(null, HttpStatus.OK);
}
The code in my JSP works fine.... it sends the values to my Controller method and the method receives it, process the information and saves the new comment in the database, but after that, showing the same page.... it gives me the error. But other POST request I have work fine.
http://192.168.160.128:8080/viewonestatus/58
Exception: org.springframework.web.HttpRequestMethodNotSupportedException:
Request method 'POST' not supported
Failed URL: http://192.168.160.128:8080/viewonestatus/58
Exception message: Request method 'POST' not supported
The AJAX snippet is that gives an ok code is:
.....
<c:url var="saveComment" value="/save-comment" />
.....
function saveComment(text) {
//alert("El texto es...text " + text);
editComment(text, "${status.id}", "${saveComment}");
}
function editComment(text, id, actionUrl) {
var token = $("meta[name='_csrf']").attr("content");
var header = $("meta[name='_csrf_header']").attr("content");
$.ajaxPrefilter(function(options, originalOptions, jqXHR) {
jqXHR.setRequestHeader(header, token);
});
$.ajax({
'url' : actionUrl,
data : {
'name' : text,
'id' : id
},
type : 'POST',
success : function() {
alert("Ok");
},
error : function() {
alert("error");
}
});
}

Spring MVC: Redirect in #ResponseBody

I want to redirect to another .jsp in spring mvc method. I don't want to use javascripts methods like: window.location.replace(url).
My method:
#RequestMapping(value= "loginUser", method=RequestMethod.POST)
public #ResponseBody String loginUser (#RequestParam("name") String name, #RequestParam("password") String password){
return "";
}
You can't do the redirect from Spring when your request expects json response. You can set a parameter for redirect so that when you enter the success block you can check the parameter to redirect using window.location.reload();. For example, from a similar post, check this answer,
Redirect on Ajax Jquery Call
One idea is to let the the browser know that it should redirect by
adding a redirect variable to to the resulting object and checking for
it in JQuery
$(document).ready(function(){
jQuery.ajax({
type: "GET",
url: "populateData.htm",
dataType:"json",
data:"userId=SampleUser",
success:function(response){
if (response.redirect) {
window.location.href = response.redirect;
}
else {
// Process the expected results...
}
},
error: function(xhr, textStatus, errorThrown) {
alert('Error! Status = ' + xhr.status);
}
});
});
You can alternatively add a response header for redirect like response.setHeader("REQUIRES_AUTH", "1") and in jQuery success,
success:function(response){
if (response.getResponseHeader('REQUIRES_AUTH') === '1'){
window.location.href = 'login.htm';
}
else {
// Process the expected results...
}
}
Refer the similar question: Spring Controller redirect to another page
Include an HttpServletResponse parameter and call sendRedirect(String).
Or, don't use #ResponseBody at all, and return the model/view you want to use.

ajax bad request only in mapped controller

In my spring mvc project i have 2 controller, one of them mapped like that:
#Controller()
#RequestMapping("/draft")
I am trying to send some data from ajax like that:
$.ajax({
type : 'get',
url : 'http://localhost:8080/FootballManager/draft/draftplayer',
dataType : "json",
data : {
'playerID' : playerID,
'username' : username,
'leaguename' : leaguename
},
response : 'text',
success : function(data) {
if (data == 1) {
alert("player drafted");
} else {
alert("player not drafted");
}
},
error : function(XmlHttpRequest, textStatus, errorThrown) {
_requesComplete = true;
alert("error= " + errorThrown);
}
and method in controller:
#RequestMapping(value="/draftplayer",method = RequestMethod.GET)
public #ResponseBody
String draftPlayer(#RequestParam("playerID") int playerID,
#RequestParam("username") String username, #RequestParam("leaguename") String leaguename,HttpSession session) {
try {
...
return "1";
} catch (Exception e) {
return "0";
}
}
And I always get Bad Request, but if I put this method into another controller, which has no #RequestMapping annotation in class reference, and change url to
url : 'http://localhost:8080/FootballManager/draftplayer',
it works perfectly. I spent a lot of time for this issue, why it happens like that? (Sorry for my english..)
Problem solved. I have method in my controller, which mapped like draft/{leaguename}, and when in send request to draft/draftplayer, it mapped to first method

how to send an object from spring controller to jsp through Ajax

I have a transaction object and I am trying to send the object to the front page. I have no problem when I try to send a string, but I couldn't send an object.
So this is my controller:
#RequestMapping(value="/result/helloajax", method=RequestMethod.GET)
#ResponseBody
public MyTransaction helloahjax() {
System.out.println("hello Ajax");
MyTransaction tran = MyTransaction.getInstance();
tran.setId(123);
return tran;
}
#RequestMapping(value="/result", method=RequestMethod.GET)
public String show() {
return "result";
}
and this is my ajax call
button
<div class="result"></div>
function doajax() {
$.ajax({
type : 'GET',
url : '${pageContext.request.contextPath}/result/helloajax',
success : function(response) {
$('.result').html(response.id);
},
error: function() {
alert("asda");
}
});
};
I search around and see that other developers used "response.result.id" but I couldn't make it neither. Any suggestion please.
I would suggest to change your code like below.
1.Include JSON library to your classpath and add produces="application/json" attribute to RequestMapping for the helloahjax method.
#RequestMapping(value="/result/helloajax", method=RequestMethod.GET,produces="application/json")
2.Include dataType in your ajax call,like below
$.ajax({
type : 'GET',
dataType : 'json',
url : '${pageContext.request.contextPath}/result/helloajax',
success : function(response) {
var obj = JSON.parse(response);
//Now you can set data as you want
$('.result').html(obj.id);
},
error: function() {
alert("asda");
}
});
The URL would change to below when you are returning JSON from the controller method. In this case you don't need to parse the response. Instead you can directly access the object variables as response.abc
${pageContext.request.contextPath}/result/helloajax.json

Resources