IE SyntaxError: Expected '}' in JSON parsing from Java - java

I have a problem in one of my projects.
We have a backend in Java and a FrondEnd app in HTML and AngularJS (v1.4.6).
In the frondend we display a table contaning some records retrieved from Java in JSON format.
In Java we use GSON to convert an object to JSON format and then we will send to browser.
Here's my Java Code:
public class doSomething {
public void caricaFile(HttpServletRequest request, HttpServletResponse response, FiltriParameters filtri) throws IOException
{
RetObj r = caricaFile(request, response, filtri, ...);
response.getWriter().println(Utils.json(r));
}
}
public class Utils {
public final static String json(Object obj) {
return new GsonBuilder().serializeNulls().create().toJson(obj);
}
}
Here's our Angular Function
$scope.uploadFile = function(files) {
if (files.length == 0)
return;
openLoader();
var fd = new FormData();
//Take the first selected file
fd.append("file", files[0]);
$http.post(urlUploader, fd, {
withCredentials: true,
headers: {'Content-Type': undefined },
transformRequest: angular.identity
})
.success(function(response){
closeLoader();
response = angular.fromJson(response);
// do something
})
.error(
function(response){
closeLoader();
alert(response);
});
$( "#file-upload" ).val("");
}
In chrome everything works fine, the JSON get received then parsed and all the rows are showed in the html table.
In Internet Explorer we get the following error. "response is undefined" in error function
IE Console:
SyntaxError: Expected '}'
at uc (http://127.0.0.1:8085/HERMESCS2/js/generics/1-4-6angular.min.js?vid=120:15:463)
at Zb (http://127.0.0.1:8085/HERMESCS2/js/generics/1-4-6angular.min.js?vid=120:82:227)
at Anonymous function (http://127.0.0.1:8085/HERMESCS2/js/generics/1-4-6angular.min.js?vid=120:83:141)
at m (http://127.0.0.1:8085/HERMESCS2/js/generics/1-4-6angular.min.js?vid=120:7:320)
at cd (http://127.0.0.1:8085/HERMESCS2/js/generics/1-4-6angular.min.js?vid=120:83:125)
at d (http://127.0.0.1:8085/HERMESCS2/js/generics/1-4-6angular.min.js?vid=120:84:366)
at Anonymous function (http://127.0.0.1:8085/HERMESCS2/js/generics/1-4-6angular.min.js?vid=120:118:324)
at n.prototype.$eval (http://127.0.0.1:8085/HERMESCS2/js/generics/1-4-6angular.min.js?vid=120:132:441)
at n.prototype.$digest (http://127.0.0.1:8085/HERMESCS2/js/generics/1-4-6angular.min.js?vid=120:129:455)
at n.prototype.$apply (http://127.0.0.1:8085/HERMESCS2/js/generics/1-4-6angular.min.js?vid=120:133:234)
Here a pastebin with the JSON the backend returns to frontend/angular.
https://pastebin.com/zUiX3AtV
We already tested it and it's a valid JSON
Any Advice?

Problem Solved
I changed the content-type in the header response to: text/json somehow Internet Explorer is affected by this whereas Chrome/FireFox no!
public class doSomething {
public void caricaFile(HttpServletRequest request, HttpServletResponse response, FiltriParameters filtri) throws IOException
{
RetObj r = caricaFile(request, response, filtri, ...);
response.setContentType("text/json");
response.getWriter().println(Utils.json(r));
}
}

Related

Send a redirect from server to Angular

Trying to send a response.sendRedirect to an HTML page on my server But, the function on Angular side always trying to parse my HTML page to JSON. even though my I'm configuring my Observable generic to 'any'.
Looked everywhere couldn't find an answer.
Thank you everyone who tries to help.
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.getSession().invalidate();
String loginUrl = new Gson().toJson("login.html");
PrintWriter out = response.getWriter();
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
out.print(loginUrl);
out.flush();
}
public logOut():Observable<any> {
return this.client.get<any>("../Login");
}
public disconnect():void {
this.service.logOut().subscribe( content => {
}, fail => {
console.log(fail);
});
Unexpected token < in JSON at position 0 at JSON.parse
Http failure during parsing for http://localhost:8080/...
Disclaimer: I am not a JAVA API developer so there may be a more efficient way of doing the JAVA backend.
Okay, in order to get this to work you should update your code to be the following:
Backend:
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.getSession().invalidate();
String loginUrl = "index.html";
PrintWriter out = response.getWriter();
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
out.print(loginUrl);
out.flush();
}
Angular:
public logOut():Observable<string> {
return this.client.get<string>("../Login");
}
public disconnect():void {
this.service.logOut().subscribe(redirectUrl => {
const baseUrl = window.location.href.split('/').slice(0,4).join('/');
window.location.href = `${baseUrl}/${redirectUrl}`;
}, fail => {
// Do fail stuff
});
}
Update: Changed the redirect location based off of the comments.
IMO this solution is starting to get a bit dirty. It will work in a pinch but, in the long-run, I would recommend changing to a Angular-routing related solution similar to the solution posted by 'Thomas Cayne'
Daniel Mizrahi: do not send login.html back from the server. Send back something like this: '{"redirectTo": "login"}'.
First you need to import the angular router in your service:
import {Route} from "#angular/router"
Then inject it in your component constructor:
constructor(private route: Route) { }
Finally in your disconnect() method:
public disconnect():void {
this.service.logOut().subscribe( content => {
this.route.navigate([`/${content.redirectTo}`])
}, fail => console.log('Display fail error:', fail)
)
);
Also, disconnect() method might not be necessary because you can do the work from:
logOut(): Observable<any> {
return this.client.get<any>('../Login')
.pipe(
map(success => this.route.navigate([`/${success}`]),
catchError(fail => console.log('Display fail error:', fail)
// and then redirect somewhere
)
)
}

How to retrieve parameters from POST in XPages (java)

I want to use Domino as a backend, and html/jquery as a frontend for my web application. So I have:
$.ajax({
type: 'POST',
url: 'mydb.nsf/xpage.xsp',
contentType: 'application/json; charset=utf-8',
data: {
f1: "hello",
f2: "hello again"
},
success: function (response) {
console.log("SUCCESS");
},
error: function (error) {
console.log(error);
}
});
In Domino:
public static String doGet(HttpServletRequest req, HttpServletResponse res) throws JsonException, IOException, NotesException {
return doPost(req, res);
}
public static String doPost(HttpServletRequest req, HttpServletResponse res) throws JsonException, IOException, NotesException {
System.out.println("1) "+req.getAttribute("f1"));
System.out.println("2) "+req.getParameter("f1"));
System.out.println("3) "+req.getContentLength());
return "AllOK";
}
In firebug and domino log I see that POST goes trough ok, gets the response. But I can't figure out how to get params f1 and f2 in domino.
In domino log:
1) is null,
2) is null,
3) is 23.
Idea for later is to POST JSON, but for now it would be great to have this code working.
How to get POST parameters in domino via java?
(I see stackoverflow has a lot of similar questions answered, but couldn't find anything specific to my problem)
Thank you!
Use reg.getReader() or req.getInputStream() to read the body of the request with elements f1 and f2.
Here is an example how you can read the JSON data:
https://stackoverflow.com/a/3831791/2065611
req.getParameter() works only if content type is "application/x-www-form-urlencoded", not json.

Multipart request giving issues when received in rest service

I am trying to upload a file using multipart request through angularjs and receive the content on my Rest service. I am putting up this question here after trying several helps for last 4 days and tiring myself to utmost level. I would appreciate if you can fine tune my approach or suggest another approach (I am open to any suggestions which may work as I am out of ideas now).
Just a pointer, I have tried writing a servlet to read the multipart request sent through angularjs and I got the parts correctly. But I am still putting the angular code here for your reference as I am not better on both angular and rest.
Following is the html extract for file upload:
<div>
<input type="file" data-file-upload multiple/>
<ul>
<li data-ng-repeat="file in files">{{file.name}}</li>
</ul>
</div>
Followingis the angularjs directive code extract:
.directive('fileUpload', function () {
return {
scope: true, //create a new scope
link: function (scope, el, attrs) {
el.bind('change', function (event) {
var files = event.target.files;
//iterate files since 'multiple' may be specified on the element
for (var i = 0;i<files.length;i++) {
//emit event upward
scope.$emit("fileSelected", { file: files[i] });
}
});
}
};
})
Following is the angularjs controller code extract
//a simple model to bind to and send to the server
$scope.model = {
name: "test",
comments: "TC"
};
//an array of files selected
$scope.files = [];
//listen for the file selected event
$scope.$on("fileSelected", function (event, args) {
$scope.$apply(function () {
//add the file object to the scope's files collection
$scope.files.push(args.file);
});
});
//the save method
$scope.save = function() {
$http({
method: 'POST',
url: "/services/testApp/settings/api/vsp/save",
headers: { 'Content-Type': undefined },
transformRequest: function (data) {
var formData = new FormData();
formData.append("model", angular.toJson(data.model));
for (var i = 0; i < data.files.length; i++) {
formData.append("file" , data.files[i]);
}
return formData;
},
data: { model: $scope.model, files: $scope.files }
}).
success(function (data, status, headers, config) {
alert("success!");
}).
error(function (data, status, headers, config) {
alert("failed!");
});
};
And here is my rest service code:
#Path("/vsp")
public class SampleService{
#Path("/save")
#POST
#Consumes(MediaType.MULTIPART_FORM_DATA)
public void saveProfile(#FormParam("model") String theXml,
#FormParam("file") List<File> files) throws ServletException, IOException {
final String response = "theXML: " + theXml + " and " + files.size() + " file(s) received";
System.out.println(response);
}
}
And here is the response:
theXML: {"name":"test","comments":"TC"} and 1 file(s) received
The problem is that the content of the file is coming in path and I am not able to get the input stream to read the file. I even tried using
new ByteArrayInputStream(files.get(0).getPath().getBytes())
If the content is text (like txt or csv) it works, but if the content is any other file like xls etc, the retrieved content is corrupt and unusable. Also tried using Jeresy api, but with same result. Am I missing anything obvious? Any help is appreciated.
I came across a few links, but none worked for me. So finally, I had to write a servlet to read the multipart request and added the files and the request parameters as request attributes. Once the request attributes are set, I forwarded the request to my Rest service.
Just for the record, if the multipart request is read once to extract the parts, the request will not have the parts in the forwarded servlet. So I had to set them as request attributes before forwarding.
Here is the servlet code:
public class UploadServlet extends HttpServlet {
#Override
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// process only if its multipart content
RequestContext reqContext = new ServletRequestContext(request);
if (ServletFileUpload.isMultipartContent(reqContext)) {
try {
List<FileItem> multiparts = new ServletFileUpload(
new DiskFileItemFactory()).parseRequest(request);
ArrayList<FileItem> fileList = new ArrayList<FileItem>();
request.setAttribute("files", fileList);
for (FileItem item : multiparts) {
if (!item.isFormField()) {
fileList.add(item);
} else {
request.setAttribute(item.getFieldName(),
item.getString());
}
}
request.setAttribute("message", "success");
} catch (Exception ex) {
request.setAttribute("message", "fail"
+ ex);
}
} else {
request.setAttribute("message",
"notMultipart");
}
System.out.println(request.getRequestURI().substring(request.getRequestURI().indexOf("upload")+6));
String forwardUri = "/api" + request.getRequestURI().substring(request.getRequestURI().indexOf("upload")+6);
request.getRequestDispatcher(forwardUri)
.forward(request, response);
}
}
Any request starting with /upload/<rest api path> will be received by the servlet and once the attributes are set, they will be forwarded to /api/<rest api path>.
In the rest api, I used the following code to retrieve the parameters.
#Path("/vsp")
public class SampleService{
#Path("/save")
#POST
#Consumes(MediaType.MULTIPART_FORM_DATA)
public void saveProfile(#Context HttpServletRequest request,
#Context HttpServletResponse response) throws Exception {
// getting the uploaded files
ArrayList<FileItem> items = (ArrayList<FileItem>)request.getAttribute("files");
FileItem item = items.get(0);
String name = new File(item.getName()).getName();
item.write( new File("C:" + File.separator + name));
// getting the data
String modelString = (String)request.getAttribute("model");
// Getting JSON from model string
JSONObject obj = JSONObject.parse(modelString);
String responseString = "model.name: " + obj.get("name") + " and " + items.size() + " file(s) received";
System.out.println(responseString);
}
}

receiving json from message body

I'm trying to send a json String from an ajax call to a jersey web service. I've looked at many related questions and articles but I haven't been able to get anything to work. When I watch my calls from fiddler I can see the json in the body but when the method is hit the String is blank. Thanks for any help.
getFile: function() {
var urlXls = 'http://localhost:8080/KodiakWebS/Kodiak/KodiakXls/generateXls';
//var json = '{"xls":[{"name":"Pokemon","row":[{"data":"Lugia"},{"data":"Charzard"}]},{"name":"Types","row":[{"data":"Special"},{"data":"Fire"}]}]}'; //encodeURI();
var json = this.get('tempJSON');
urlXls = urlXls.replace(/\s/g, "");
$.ajax({
url: urlXls,
type: "POST",
data: json,
contentType: 'application/json; charset=utf-8', // ;charset=utf-8',
success: function(json, status)
window.location.assign(json.url);
alert("yay");
},
error: function(xhr, err) {
debugger;
alert(xhr+ " || " + err);
}
});
},
#POST
#Path("/generateXls")
#Consumes("application/json")
#Produces({ "application/xls" })
public Response sendWorkBook(final String json) throws Exception {
createWorkbook(json);
FileOutputStream sprdSht = new FileOutputStream("WorkBook.xls");
wb.write(sprdSht);
sprdSht.close();
System.out.println("all done");
StreamingOutput stream = new StreamingOutput() {
#Override
public void write(OutputStream outPut)
throws IOException,
WebApplicationException {
try {
wb.write(outPut);
} catch (Exception e) {
throw new WebApplicationException(e);
}
}
};
return Response.ok(stream).header("content-disposition", "attachment; filename = egisDoc.xls").build();
}
If you say you consume application/json, then I think you need to provide a Java object to model the JSON you are supplying.
If you do just want the JSON as a String, then you need to consume text/plain.
I typically have this when I use JAXRS:
#PUT
#Path("entities")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public SomeDomainObject updateSomeEntity(SomeDomainObject someDomainObject) {
// Whatever...
}
Where "SomeDomainObject" is just a POJO with getters and setters.
I normally use the JacksonJsonProvider implementation rather than the JAXB one, and the above style of controller works just fine with JSON marshalling for me. I don't even need to add any JSON annotations to the domain objects either.
I was able to get it working thanks to the suggestions from caprica and tinkering around a little bit. Not much changed in my code but here it is.
#PUT
#Path("/generateXls")
#Consumes("text/plain")
#Produces({ "application/xls" })
public Response sendWorkBook(String json) throws Exception {
System.out.println("json: " + json);
createWorkbook(json);
getFile: function() {
var urlXls = 'http://localhost:8080/KodiakWebS/Kodiak/KodiakXls/generateXls';
//var json = '{"xls":[{"name":"Pokemon","row":[{"data":"Lugia"},{"data":"Charzard"}]},{"name":"Types","row":[{"data":"Special"},{"data":"Fire"}]}]}'; //encodeURI();
var json = this.get('tempJSON');
urlXls = urlXls.replace(/\s/g, "");
$.ajax({
type: "PUT",
url: urlXls,
data: json,
contentType: 'text/plain; charset=utf-8', // ;charset=utf-8',
success: function(json, status) {
window.location.href = json.url;
//window.location.assign(json.url);
//alert("yay");
},
error: function(xhr, err) {
debugger;
alert(xhr+ " || " + err);
}
});
},
now on to trying to download xls file my service creates, hopefully I won't need to ask how to get what I have working (but if anyone has a method they're proud of and would like to share you're more than welcome too).
Thanks for the help.

jquery ajax call returns error on successful call to a servlet

I have a servlet that adds a user to a file on the server side.
I invoke it with a jqueries ajax call.
I can see on the server that the method is being called correctly and my user is added, but the error callback is being invoked on the jquery call. All the status text says is error.
Using firebug the response seems to be empty. Why can I not get a success jquery callback?
//Servlet Code
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String action = request.getParameter("action");
String responseStr = "";
if(action.equals("addUser"))
{
responseStr = addUser(request);
}
System.out.println("Reponse:" + responseStr);
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
response.getWriter().println(responseStr);
}
private String addUser(HttpServletRequest request) throws IOException
{
Storage s;
s = Storage.load();
String name = request.getParameter("name");
String imageUrl = request.getParameter("imageUrl");
User u = new User();
u.setName(name);
u.setImageUrl(imageUrl);
s.addUser(u);
s.save();
return "success";
}
.
//javascript code
function addUser() {
var name = $('#name').val();
var imageUrl = $('#imageUrl').val();
var url = "http://ws06525:8080/QCHounds/QCHoundServlet?action=addUser&name=${name}&imageUrl=${imageUrl}";
url = url.replace("${name}", name);
url = url.replace("${imageUrl}", imageUrl);
$('#result').html(url);
$.ajax({
url: url,
success: function( data ) {
$('#result').html(data);
},
error: function(jqXHR, textStatus, errorThrown)
{
alert("error: " + textStatus);
alert("error: " + errorThrown);
}
});
}
Aaargh! Feel like an idiot. It's a cross site scripting issue.
I was testing the call to the server from the html file on disk so my browser address was
file://projects/myproject/content/Users.html <<< Fail
instead of:
http://myboxname:8080/appname/Users.html <<< Works
The actual code is fine...
use this for learn what is the problem, it will be better for get solution i think
error: function(e){
alert(JSON.stringify(e))
}
For one thing the string "success" isn't valid json. If your ajax query is expecting json, that would fail it.
What if you returned "{ \"success\": true }" ?
EDIT
It looks like from your ajax call that the response shouldn't be json, why is your return content type json?
If it is true that firebug shows no response, your problem must be in the java code that writes the response.

Categories

Resources