Spring : Convert Response Entity to JSON - arrays

From my rest client, i am hitting a web service and getting my response in the form of String {"code":"00000","msg":"Success"> . Now I am converting this in the form of JSONObject which i can then use further. But i am not able to. Below is the code i am using . Please guide.
private ResponseEntity<String> test()
{
final String uri = "URL";
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);
ResponseEntity<String> result = restTemplate.exchange(uri, HttpMethod.GET, entity, String.class);
System.out.println(result);
//This part is not working.
try {
JSONObject arr = new JSONObject((result));
for (int i = 0; i < arr.length(); i++) {
JSONObject abc = arr.getJSONObject(i);
System.out.println("test1 : " + abc.getString("test1"));
System.out.println("test2 : " + abc.getString("test2"));
System.out.println("test3 : " + abc.getString("test3"));
}
} catch (Exception e) {
}
return result;
}

Instead of converting to a generic JSONObject, you should create a class matching your response.
Spring will map the response to your model class using Jackson(behind the scenes). There is no need for converting it yourself.
So Let's say, you create a class
class Response {
String code;
String message:
//Gettes and Setters
}
Now you can change your code a bit like this
ResponseEntity<Response> result = restTemplate.exchange(uri, HttpMethod.GET, entity, Response.class);
Now if you useresult.getBody(), this would give your Response object, which you can use

One form is using JSONObject
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<version>1.1</version>
<scope>${scope}</scope>
</dependency>
import org.json.simple.JSONObject;
JSONObject json = new JSONObject();
json.put("key1", value1);
json.put("key2", value2);

Related

Spring Boot endpoint for downloading File automatically

I want to make a Spring Boot endpoint for downloading file. I Have tried this things but the file does not download automatically... I get only file content in the body...
#RequestMapping(value = "/files", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
#ResponseBody
public ResponseEntity<FileSystemResource> getFile(#RequestParam(name = "start") String start) {
return new ResponseEntity<>(new FileSystemResource(myService.makeFile(start)),
HttpStatus.OK);
}
Another one that I have tried is this:
#RequestMapping(value = "/download", method = RequestMethod.GET, produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public String download(HttpServletResponse response, #RequestParam(name = "start") String start)
{
response.setContentType("application/force-download");
FileReader fr = new FileReader(myService.makeFile(start));
return IOUtils.toString(fr);
}
I have read that MediaType.APPLICATION_OCTET_STREAM_VALUE will force it to download but nothing happened in my case.
You are on the right track, you just need to set one response header Content-Disposition to attachment; filename=YOUR_FILE_NAME.
Try This:
#RequestMapping(value = "/files", method = RequestMethod.GET, produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public FileSystemResource getFile(#RequestParam(name = "start") String start, HttpServletResponse response) {
response.setHeader("Content-Disposition", "attachment; filename=" + "YOUR_FILE_NAME");
return new FileSystemResource(myService.makeFile(start));
}

getJSONObject(int) is undefined for the type JSONArray

I am getting an JSON array in response from rest webservice and I want to iterate over it to get the various attributes of it. There are multiple json array with the same name and only the attributes values and different. For this I have tried various code snippets. I have mentioned all my tried code snippets with the error I got.
ResponseEntity<String> response = restTemplate.exchange("xyz.com",
HttpMethod.GET, entity, String.class);
JSONParser parser=new JSONParser();
System.out.println("Response is"+response.getBody());
try{
//JSONObject outerObject = (JSONObject)parser.parse(response.getBody()); Class Cast Exception
//JSONObject jsonObj = new JSONObject(response.getBody()); jsonobject must begin with {
JSONArray jsonArray = (JSONArray) parser.parse(response.getBody());
for (int i = 0; i < jsonArray.size(); i++)
{
/*JSONObject object = jsonArray.getJSONObject(i);*/// getJSONObject(int) is undefined for the type JSONArray
}
}catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
The Webservices response is like
[
{"mutualFund":{"fundCode":"xyz","fundName":"123","isin":"IE000"}},
{"mutualFund":{"fundCode":"xyz","fundName":"123","isin":"xyz"}},
{"mutualFund":{"fundCode":"xyz","fundName":"123","sedol":"WB1"}}
]
You don't have to use Parser, becuase json array constructor takes string as paramter
Download the following JSON lib to make the json easy to parse
ResponseEntity<String> response = restTemplate.exchange("xyz.com",
HttpMethod.GET, entity, String.class);
System.out.println("Response is"+response.getBody());
try{
JSONArray outerObject = new JSONArray(response.getBody());
for(JSONObject object: outerObject)
{
// Your Logic
}
}catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

500 Error - Unable to select and perform a post action

I am not good with Web API. Here is my problem. I send an Json serialized object from my Windows Form Application. The object is an Entity table. When I do a get response it returns a 500 server error. Basically I plan to have multiple post methods in one controller which I may not be doing right. So I need you guys to guide me on what I have been doing wrong.
Here is my Controller:
[ResponseType(typeof(HttpWebResponse)), HttpPost, ActionName("MerchandiseApi")]
public HttpResponseMessage PostMain(IList<IMF_Main> mainFromConsolidator)
{
if (!ModelState.IsValid)
return Request.CreateResponse(HttpStatusCode.BadRequest, 2);
using (var anthill = new AnthillConsolidatorEntities())
{
var main = new IMF_Main();
foreach (var item in mainFromConsolidator)
{
main.BrandID = item.BrandID;
main.ItemID = item.ItemID;
main.CategoryID = item.CategoryID;
main.SubCategoryID = item.SubCategoryID;
main.ClassID = item.ClassID;
main.GenderID = item.GenderID;
main.CoaID = item.CoaID;
main.SubCoaID = item.SubCoaID;
main.First_SRP = item.First_SRP;
main.Current_SRP = item.Current_SRP;
main.Previous_SRP = item.Previous_SRP;
main.isSenior = item.isSenior;
main.isActive = item.isActive;
main.DateCreated = item.DateCreated;
anthill.IMF_Main.Add(main);
anthill.SaveChanges();
}
}
return Request.CreateResponse(HttpStatusCode.OK, 1);
}
Here's my WebApiConfig:
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "MerchandiseApi",
routeTemplate: "api/{controller}/{action}"
);
}
Here is where the Uri gets built: I have 2 more tables to send but I will start with this. This goes to my first Post method to the server
var jsonMain = JsonConvert.SerializeObject(consolidatorEntities.IMF_Main, Formatting.None);
HttpPost("http://localhost:50826/api/Merchandise/PostMain", jsonMain) == 1.ToString()
public string HttpPost(string uri, string json)
{
string content = "";
try
{
var request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = "POST";
request.Accept = "application/json";
request.ContentType = "application/json";
byte[] bodyBytes = Encoding.UTF8.GetBytes(json);
request.GetRequestStream().Write(bodyBytes, 0, bodyBytes.Length);
request.GetRequestStream().Close();
var response = (HttpWebResponse)request.GetResponse();
var sr = new StreamReader(response.GetResponseStream(), Encoding.GetEncod
ing("UTF-8"));
content = sr.ReadToEnd();
sr.Close();
}
catch (Exception ex)
{
MessageBox.Show("Error sending data to Anthill \nException: " + ex, "Monytron - Consolidator", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
return content;
}
Problem
The main problem is with your routing. Routes will check in order so when you post a request to http://localhost:50826/api/Merchandise/PostMain and you have these routes in order:
"api/{controller}/{id}"
"api/{controller}/{action}"
So the first route will match:
If your PostMain method is the only action with [HttpPost], then mainFromConsolidator will be null in your foreach loop you will receive a NullReferenceException that result in a 500 error.
If you have multiple method decorated with [HttpPost], then the call is ambiguous between those actions and you will receive an InvalidOperationExpception with "Multiple actions were found that match the request" message that result in a 500 error.
The other problem is you are using an ActionName("MerchandiseApi") but didn't post to that action.
Solution
You can use multiple solutions. As an option you can define only one route:
"api/{controller}/{action}/{id}"
This way you can create a controller that contains actions like these:
public class SomeController
{
// matches GET /api/some/action1
[HttpGet]
public HttpResponseMessage Action1()
// matches GET /api/some/action2/5
[HttpGet]
public HttpResponseMessage Action2(int id)
// matches POST /api/some/action3
[HttpPost]
public HttpResponseMessage Action3(SomeType someParameter)
// matches POST /api/some/action4
[HttpPost]
public HttpResponseMessage Action4(SomeType someParameter)
}
Anyway if you decide to define multiple routes, pay attention that routes will match in order and also if you used ActionName attribute, then use that name in url to call that action.

Send emails with attachments in salesforce via sendgrid

I am trying to generate a pdf and attach to an email and send it.
I am using salesforce and sendgrid.
I am able to send emails but the problem is when I try to attach the pdf, the email is with the attachment, but this is broken, the file is not empty, but the pdf says is broken (I think is a problem of conversion)
here is the code
Messaging.EmailFileAttachment efa = new Messaging.EmailFileAttachment();
PageReference pdf = Page.include_attachment;
pdf.getParameters().put('id', 'xxxxxxxxxxxxxxxxxx');
blob fileBody = pdf.getContentAsPDF();
efa.setBody(fileBody);
efa.setFileName('test.pdf');
efa.setContentType('application/pdf;charset=UTF-8;');
send('xxxxx#xxxx.com','Test','Body Test', fileBody);
I tryied using
pdf.getContentAsPDF();
and
pdf.getContent();
but the result is the same.
Send method
public static void send(String emailRecipient, String emailSubject, String emailBody, Blob att){
Boolean success=true;
//construct the body of the request
String requestBody='';
requestBody += 'to='+EncodingUtil.urlEncode(emailRecipient,'UTF-8');
requestBody += '&from='+EncodingUtil.urlEncode(user.Email,'UTF-8');
requestBody += '&fromname='+EncodingUtil.urlEncode(user.Name,'UTF-8');
requestBody += '&subject='+EncodingUtil.urlEncode(emailSubject,'UTF-8');
requestBody += '&text='+EncodingUtil.urlEncode(emailBody.trim(),'UTF-8');
requestBody += '&html='+EncodingUtil.urlEncode(emailBody.trim(),'UTF-8');
requestBody += '&api_user=xxxxx';
requestBody += '&api_key=xxxxx';
requestBody += '&files[attachment.pdf]=#'+ EncodingUtil.base64Encode(att);
//construct request
HttpRequest req = new HttpRequest();
req.setEndpoint('https://sendgrid.com/api/mail.send.json');
req.setMethod('POST');
req.setBody(requestBody);
try{
//send request
Http h = new Http();
HttpResponse res = h.send(req);
//check response
String status = res.getStatus();
if(status.toUpperCase()=='OK'){
success=true;
}
else{
success=false;
}
}
catch(Exception e){
success=false;
}
}
Thank you
There is now a library/devtoolkit to do this for you. At the time of this writing it is in beta, but it is working. Disclaimer: I work at SendGrid and have just recently developed the library.
sendgrid-apex
You can rewrite your code to:
...
Blob att = pdf.getContentAsPDF();
public static void send(String emailRecipient, String emailSubject, String emailBody, Blob att){
SendGrid sendgrid = new SendGrid('username', 'password');
SendGrid.email email = new SendGrid.Email();
email.addTo(emailRecipient);
email.setFrom(user.Email);
email.setFromName(user.Name);
email.setSubject(emailSubject);
email.setText(emailBody.trim());
email.setHtml(emailBody.trim());
email.addAttachmentStream("attachment.pdf", att);
String response = sendgrid.send(email);
}

System.CalloutException: For input string: "password#app.fluidsurveys.com"

I am trying to access the fluid survey API in Sales force. I use the following code but it responds with an error.
The code for controller class is:
public class fluidSurvey{
public String tst{set;get;}
public String result{get;set;}
public PageReference chk() {
//if (!ApexPages.hasMessages())
result=getData();
return null;
}
public String getData()
{
HttpRequest req= new HttpRequest();
Http http = new Http();
req.setMethod('GET');
String url = 'https://username:password#app.fluidsurveys.com/api/v2/surveys/';
req.setEndpoint(url);
HttpResponse res = http.send(req);
String json = res.getBody().replace('\n','');
tst = json;
try {
JSONObject j = new JSONObject( json );
return parseJson(j);
} catch (JSONObject.JSONException e) {
return 'Error parsing JSON response from Google: '+e;
}
}
public String parseJson(JSONObject resp){
String detail =resp.getString('total');
return detail;
}
}
and the code for apex page is:
<apex:page controller="fluidSurvey">
<!-- Begin Default Content REMOVE THIS -->
<h1>Fluid Survey</h1>
<apex:form >
<apex:outputText value="{!tst}"></apex:outputText>
<apex:commandButton value="Submit" action="{!chk}"/>
</apex:form>
</apex:page>
but when I click the submit button it create the following error:
System.CalloutException: For input string: "password#app.fluidsurveys.com"
Error is in expression '{!chk}' in component <apex:page> in page fluid-page
You need to explicitly set the Authorization header.
Try the following code:
public String getData()
{
HttpRequest req= new HttpRequest();
Http http = new Http();
req.setMethod('GET');
String authString = 'username:password';
String url = 'https://app.fluidsurveys.com/api/v2/surveys/';
req.setEndpoint(url);
req.setHeader('Authorization', 'BASIC ' + EncodingUtil.base64Encode(Blob.valueOf(authString)));
HttpResponse res = http.send(req);
String json = res.getBody().replace('\n','');
try {
JSONObject j = new JSONObject( json );
return parseJson(j);
} catch (JSONObject.JSONException e) {
return 'Error parsing JSON response from Google: '+e;
}
}
I don't believe you can use the username:password#host format to pass authenticate info in the URL for Callouts, you have to explicitly set an Authentication HTTP header in your request to pass the credentials instead. (exactly how you do this will depend on what authentication types the server supports)

Resources