Convert a JSON String to a JSON Object - angularjs

I am making the following PUT request using AJAX to a RESTful web service. Before making the request, I convert the data returned from form submission (using ng-submit) to a JSON String:
var serializedData =angular.toJson(person);
I then send it as data in an AJAX call like this:
$http({
method: 'PUT',
url: myurl +person.personID,
data: serializedData,
headers: {
'Content-Type': 'application/json'
}
}).success(function(data) {
console.log("Success");
});
Now in my web service, I want to get this data and create a Java object:
#PUT
#Path("/person/{id}")
#Produces({ MediaType.APPLICATION_JSON })
#Consumes({MediaType.APPLICATION_JSON})
public Response updatePerson(#PathParam("id") String personID,
#Context HttpServletRequest httpRequest) {
Response.ResponseBuilder builder = Response.ok();
Person person =null;
String data =null;
BufferedReader reader =null;
StringBuffer buffer = new StringBuffer();
try
{
reader = new BufferedReader(new InputStreamReader(httpRequest.getInputStream()));
}
catch (IOException e1)
{
e1.printStackTrace();
e1.getCause().toString();
}
try
{
while((data =reader.readLine()) != null){
buffer.append(data);
}
}
catch (IOException e1)
{
e1.printStackTrace();
}
String bufferToString =buffer.toString();
try
{
person =JSONUtil.toObject(bufferToString, new TypeReference<Person>() {});
}
catch (JsonParseException e1)
{
// TODO Auto-generated catch block
e1.printStackTrace();
}
catch (JsonMappingException e1)
{
// TODO Auto-generated catch block
e1.printStackTrace();
}
catch (IOException e1)
{
// TODO Auto-generated catch block
e1.printStackTrace();
}
if (person == null) {
builder = Response
.status(Response.Status.NOT_FOUND.getStatusCode());
return builder.build();
}
try {
deviceService.update(dev);
JSONUtil.toJSONString(dev);
builder.entity(JSONUtil.toJSONString(dev));
} catch (JsonGenerationException e) {
} catch (JsonMappingException e) {
} catch (IOException e) {
return builder.build();
}
Here is a problem I cant seem to figure out. When the ajax call is made, data does reach to the web service, which means it is a JSON string because that is what angular.toJson does [https://docs.angularjs.org/api/ng/function/angular.toJson]. After reading it with the reader and converting it to a string and passing it to the JSONUtil.toObject(bufferToString, new TypeReference<Person>() {});, it gives me a 404 status code, meaning the person object is null. Now here is the weird thing I dont understand. If I do a get request for a Person object in POSTMAN client, edit a value in that JSON and send it as body of application/json type in a PUT request (from POSTMAN), then it works. I have checked through JSONLint that the JSON string that I receive from AJAX is valid.. Why is this happening?? I passed a string to the JSONUtil.toObject(bufferToString, new TypeReference<Person>() {});, which is what that method needs. Is it not in the right format? I cant seem to understand. Any help will be appreciated. Have been stuck on this for 4 hours now. Thank you.

I post this as an answer since I can't comment yet. The following is a suggestion to refactor code to make it easier to mantain. If doing so is not an option, I'd suggest you post the StackTrace printed on your console to provide further assistance.
Now the suggestion:
You should try JAX-B. It'd make your code much more manageable and free you from the hazzard of doing serialization and deserialization manually. You can use all JAX-B POJOs as parameters or return types:
#POST
public StatusDTO createStatus(StatusDTO dto) {
//your code here
}
All you need to do is create a POJO and annotate it with #XmlRootElement and you can use it directly as parameter in your Jersey services.
With this you can return the POJO and JAX-B will do the serialization, so you don't have to build the response manually either. Finally, whenever you need to return an error code, try throwing a WebApplicationException.

You need other solution to work with json in Java, in Spring use Jersey and Jackson and i catch the json objects to a java pojo, check this example https://github.com/ripper2hl/angular-todo/
and the code for catch object is very simple
#RequestMapping(method = RequestMethod.POST)
public Todo saveTodo(#RequestBody Todo todo){
return todoDao.save(todo);
}

Related

Axios POST request passing an empty object to Spring REST API end doing

I am in the middle of learning react/redux and decided to take an old JQuery UI that makes request to Spring REST API and rewrite it in React. I am using Axios to make the request. In my old Query UI , I do the following when a form is submitted.
var formInputs = $(form).serialize();
$.post("/addAttrItem", formInputs, function(updated){
refresh();
showRecord(updated);
displayControlMsg("Record below was added successfully");
}
This is handled by the following code below in Spring
#ResponseBody
#RequestMapping(value="/someURL", method=RequestMethod.POST)
public AttrItem restfulAdd(AttrItem item) throws Exception
{
item.setLastUpdate(new java.util.Date());
itemService.create(item);
return item;
}
When sending the request through JQuery, AttrItem item param populated with all right values sent in by JQuery
However when I try the following axios
axios.post(someUrl, data).then
(res => {
dispatch(addAttributeSync(res));
}).catch(error =>{
alert('add item failed ' + error);
}
the AttrItem item param while not null itself, is empty with none of the fields set to values from the form. I confirmed that the data object contains right data prior to the post request.
See if mapping the HTTP request body to the method argument item using #RequestBody annotation helps.
#ResponseBody
#RequestMapping(value="/someURL", method=RequestMethod.POST)
public AttrItem restfulAdd(#RequestBody AttrItem item) throws Exception
{
item.setLastUpdate(new java.util.Date());
itemService.create(item);
return item;
}
The following seems to have resolved the issue. In React I added header config
return dispatch => {
var config = {
headers: { 'Content-Type': 'application/json' },
};
axios.post(someUrl, data).then
(res => {
dispatch(addAttributeSync(res));
}).catch(error =>{
alert('add item failed ' + error);
}
And I modified my Spring Controller endpoint to set the consumes and produces attribute as follows.
#ResponseBody
#RequestMapping(value="/attributeItem", method=RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public AttributeItem restfulAdd(#RequestBody AttributeItem attributeItem) throws Exception
{
attributeItem.setLastUpdate(new java.util.Date());
attributeItemService.create(attributeItem);
return attributeItem;
}

Upload file from AngularJS to Spring Boot

I'm using AngularJS to make my front end and Java with Spring Boot to make my back end. I'm trying to import/upload a xlsx, xls, or ods file from the Angular to my Java, but whatever I do, the request doesn't send my file!
Java endpoint:
#PostMapping(value = "/upload/{type}")
#ResponseBody
private ResponseEntity<List<Rota>> importFile(#PathVariable("type") String type,
#RequestParam(required = false, value = "file") MultipartFile fileParam,
#RequestBody MultipartFile file) {
System.out.println("File: " + file.getName());
if(type.toUpperCase().equals("XLSX")){
System.out.println("XLSX!");
}else if(type.toUpperCase().equals("XLS")){
System.out.println("XLS!");
}else if(type.toUpperCase().equals("ODS")){
System.out.println("ODS!");
}else{
System.out.println("OPS!");
return new ResponseEntity<>(new ArrayList<>(), HttpStatus.UNSUPPORTED_MEDIA_TYPE);
}
return new ResponseEntity<>(new ArrayList<>(), HttpStatus.OK);
}
My request-id made using an Angular class prepared to only make requests. I'll post here the code that we use normally in the project and the code that actually worked but I can't use it.
DataFactory:
DataFactory.POST = function (url, entity, config = null) {
if (url && entity) {
return $http
.post(url, entity, config)
.then(res => $q.resolve(res.data), error => $q.reject(error));
}
};
The code that actually worked:
var xhr = new XMLHttpRequest;
xhr.open('POST', `${URL.CTM_ODS()}/rotas/upload/${type}`, true);
xhr.send(formData);
When I use Postman, sending the file through the body, the back end receives null, but when I use form-data from Postman, works fine!
Using the DataFactory I got the following stack on my back end:
WARN 16796 --- [p1002886236-126] org.eclipse.jetty.http.HttpParser : badMessage: java.lang.IllegalStateException: too much data after closed for HttpChannelOverHttp#78fd8670{r=2,c=false,a=IDLE,uri=}
Found the answer in this video: https://www.youtube.com/watch?v=vLHgpOG1cW4
My problem was that the AngularJS deserialize the file! So, what I've made was just put a config object saying to not do that:
DataFactory.POST(`${URL.CTM_ODS()}/rotas/upload/${type}`, formData, { transformRequest: angular.indentity, headers: { 'Content-Type': undefined } }).then(response => {
delete vm.importacao.arquivoCsv;
console.log('Response: ', response);
LoadingManager.hide();
});
As you can see, the difference is on the header object, can you see that we pass the content type as undefined and transformRequest: angular.indentity? That worked for me! If anyone has other way to do so, feel free to comment! Thanks and have a nice day!

Send a PDF as an attachment through Sendgrid

I'm using Sendgrid to send emails through an app on GAE. It's working fine, but I also want to be able to send PDFs as an attachment.
I'm not using Sendgrid.jar file in my project. I've just used Sendgrid.java. And this class has no methods by which i can add attachments. Can someone help me?
public static boolean sendEmail(String fromMail, String title, String toMail, String message) throws IOException {
Email from = new Email(fromMail);
String subject = title;
Email to = new Email(toMail);
Content content = new Content("text/html", message);
Mail mail = new Mail(from, subject, to, content);
Path file = Paths.get("file path");
Attachments attachments = new Attachments();
attachments.setFilename(file.getFileName().toString());
attachments.setType("application/pdf");
attachments.setDisposition("attachment");
byte[] attachmentContentBytes = Files.readAllBytes(file);
String attachmentContent = Base64.getMimeEncoder().encodeToString(attachmentContentBytes);
String s = Base64.getEncoder().encodeToString(attachmentContentBytes);
attachments.setContent(s);
mail.addAttachments(attachments);
SendGrid sg = new SendGrid("sendgrid api key");
Request request = new Request();
request.setMethod(Method.POST);
request.setEndpoint("mail/send");
request.setBody(mail.build());
Response response = sg.api(request);
if (response != null) {
return true;
} else {
return false;
}
}
Define above static method and call with relevant arguments as your program wants.
Here is the code of a servlet that sends a mail with a PDF as attachment, through Sendgrid:
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
....
ByteArrayOutputStream os = null;
try {
PDFGenerator pdfGenerator = new PDFGenerator(invoiceOut);
os = pdfGenerator.getPDFOutputStream();
} catch (Exception e) {
....
}
SendGrid sendgrid = new SendGrid(Constants.SENDGRID_API_KEY);
SendGrid.Email email = new SendGrid.Email();
email.addTo(....);
email.setFrom(....);
email.setFromName(....);
email.setSubject(....);
email.setHtml("......");
ByteBuffer buf = null;
if (os == null) {
//error...
} else {
buf = ByteBuffer.wrap(os.toByteArray());
}
InputStream attachmentDataStream = new ByteArrayInputStream(buf.array());
try {
email.addAttachment("xxxxx.pdf", attachmentDataStream);
SendGrid.Response response = sendgrid.send(email);
} catch (IOException e) {
....
throw new RuntimeException(e);
} catch (SendGridException e) {
....
throw new RuntimeException(e);
}
}
PDFGenerator is one of my classes in which getPDFOutputStream method returns the PDF as ByteArrayOutputStream.
I personally find it easier to directly construct the JSON request body as described in the API docs than to use Sendgrid's libraries. I only use the Sendgrid library for sending the request after I construct the JSON data myself.
When constructing the JSON data you need to specify at least a filename and the content (i.e., the PDF file). Make sure to Base64 encode the PDF file before adding it to the JASON data.
I'd include some code, but I do Python and not Java so not sure that would help.

angularjs sending request front to back-end

i am sending remove request from front-end using angularjs code for js is
var data = ersutils.getJsonCopy({"id" : $scope.resourceList[idx].id},$scope.resourceList[idx]);
ResourceService.remove(data, function(data){
//vm.dtInstance.reloadData(undefined, false);
$modalInstance.close();
}, function (resp){
if(resp.status == 500){
scope.modalinfo.message = "<code> this resource has booking(s) do you want to delete? </code>";
ResourceService.remove({'id': delRes}, function(){
//vm.dtInstance.reloadData(undefined, false);
$modalInstance.close();
})
}else{
scope.modalinfo.message = "<code> Unable to delete this Resource </code>";
}
});
here ersutils provide jsoncopy for multiple parameters...when i have sent this data to rest api it says that unsupported media type
restapi code for delete is
#DELETE
#Path("/{id:\\d+}")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public Response removeRes(#PathParam("id") int id,Map<String, Object> source){
Map<String, Object> resp = new HashMap<>();
//Map<String, Object> source=new HashMap<>();
try{
resp.put("response",service.removeRes(id,source));
return Response.status(Status.OK).entity(resp).build();
}catch(FrontErsException e){
resp.put("cause", e.getMessages());
return Response.status(Status.CONFLICT).entity(resp).build();
}catch(ErsException e){
resp.put("cause", e.getMessages());
return Response.status(Status.INTERNAL_SERVER_ERROR).entity(resp).build();
}
}
error is
angular.js:10514 DELETE http://localhost:8080/ers_dev/rest/resources/10?dynamicFields=%7B%22code%22…2016-05-27%22%7D&firstName=vinay&isHuman=true&name=N%2FA&typeName=Employee 415 (Unsupported Media Type)
Did you try using #Consumes(MediaType.APPLICATION_FORM_URLENCODED) instead of APPLICATION_JSON?
Don't know exactly what you're using for your backend, but uUsually DELETE requests doesn't care about request body, so params are URL encoded.

How to get different JSON content in the same $http.get

I'm using AngularJS to retrieve a list of objects from a Server. The server side is being made with Spring MVC.
So, I'd like to return a list of these objects as JSON format, but, I'd like to return an informative message object if the server coudn't retrieve the data for any reason.
Can I do it without encapsulating the List<> and the Message objects in a DTO (Data Transfer Object)?
How can I check on AngularJS the received JSON if it can be from 2 different types?
Here is a fragment of my controller class. It currently returns a list of the MyType I'd like to return. But the idea is to convert it to a generic type (Object, maybe?) and return from this request the list or the message, depending on the case.
#RequestMapping(value = RestPaths.LIST_MYTYPE_BY_OWNER, method = RequestMethod.GET)
public #ResponseBody List<MyType> listByOwner(#RequestBody Owner o) {
List<MyType> myType = myService.list(o);
return myType;
}
This is the service that consults the controller. How could I treat the data, considering that the JSON could have different formats?
this.listMyType = function(ownerId){
var deferred = $q.defer();
$http.get('/rest/my/list_by_owner',{})
.then(function (response) {
if (response.status == 200) {
deferred.resolve(response.data);
}
else {
deferred.reject('Error retrieving list of myType');
}
});
return deferred.promise;
}
I wouldn't use an exception for flow control. If both cases (list is empty or it is not) are valid, handle both of them in your handler method. Use ResponseEntity to encapsulate your response. Return a String message in one case (empty) and a List<MyType> in the other (not empty).
#RequestMapping(value = RestPaths.LIST_MYTYPE_BY_OWNER, method = RequestMethod.GET)
public ResponseEntity<?> listByOwner(#RequestBody Owner o) {
List<MyType> myType = myService.list(o);
if (myType.isEmpty()) {
return new ResponseEntity<>("The message", HttpStatus.NOT_FOUND);
}
return new ResponseEntity<>(myType, HttpStatus.OK);
}
All handler method return values are handled by HandlerMethodReturnValueHandler objects. The corresponding one for ResponseEntity is HttpEntityMethodProcessor. It handles the ResponseEntity's body the same way #ReponseBody would.
So a String would be written directly to the response as text/plain (or html) and the List<MyType> would be serialized to application/json by default (or whatever you have configured).
You can add response headers to the ResponseEntity which can also help determine how the content will be serialized (content-type, etc.).
My suggestion is to throw an exception, then add in a spring exception handler which sets the appropriate status code and message:
#RequestMapping(value = RestPaths.LIST_MYTYPE_BY_OWNER, method = RequestMethod.GET)
public #ResponseBody List<MyType> listByOwner(#RequestBody Owner o) {
List<MyType> myType = myService.list(o);
if (myType.size() == 0) {
throw new ResourceNotFoundException("List was empty");
}
return myType;
}
and
#ControllerAdvice
public class ControllerExceptionHandler {
#ExceptionHandler(ResourceNotFoundException.class)
public void handleException(Exception e, HttpServletReponse response) {
response.setStatus(HttpStatus.NOT_FOUND);
response.getOutputStream().write(e.message);
}
}
Here is a pretty good write up on spring mvc exception handling: https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc

Resources