Retrieving String from JAX-RS Response - java

In short terms, I simplified the problem a lot. I am calling this code, and the response is received with status 200 (OK):
Receiver.java:
Response response = componentInstanceService.getResource(componentResourceType);
However, I don't know how can I retrieve the String contained in the body from this method:
Sender.java:
#Override
public Response getResource(ComponentResourceType resourceType) {
String path = getPath();
return Response.ok(this.getClass().getResourceAsStream(path)).build();
}
Please note that the communication between classes is working fine, as long as the Response is OK, however, how can I retrieve the String that Response contains?
This is what I would like to do roughly:
Receiver:
String result = componentInstanceService.getResource(componentResourceType);

The documentation for Response makes this pretty clear:
static Response.ResponseBuilder ok(java.lang.Object entity)
Create a new ResponseBuilder that contains a representation.
And:
abstract java.lang.Object getEntity()
Return the response entity.
In other words, the object you passed to Response.ok is the entity. You can retrieve it with the Response’s getEntity() method.
Obviously, you will need to cast it:
Response response = componentInstanceService.getResource(componentResourceType);
InputStream dataSource = (InputStream) response.getEntity();
Then you can read the stream as text. You haven’t mentioned the charset of your text files, so I’ll assume it’s UTF-8:
String result;
try (Scanner scanner = new Scanner(dataSource, StandardCharsets.UTF_8)) {
result = scanner.useDelimiter("\\z").next();
}
Update:
I suspected this might happen. You are returning a raw InputStream, which has no information about what type of data it is.
Change Sender.java to return a DataSource:
#Override
public DataSource getResource(ComponentResourceType resourceType) {
String path = getPath();
return new URLDataSource(this.getClass().getResource(path));
}
This way, the JAX-RS service will not only return HTTP 200 OK, but will also return a Content-Type header corresponding to the intuited type of your file.
You should then be able to invoke the method with:
DataSource dataSource = componentInstanceService.getResource(componentResourceType);
String result;
try (Scanner scanner = new Scanner(dataSource.getInputStream(), StandardCharsets.UTF_8)) {
result = scanner.useDelimiter("\\z").next();
}
There actually is a more robust way to read a DataSource. You can wrap it in a DataHandler:
DataSource dataSource = componentInstanceService.getResource(componentResourceType);
DataHandler handler = new DataHandler(dataSource);
DataFlavor flavor = DataFlavor.selectBestTextFlavor(
handler.getTransferDataFlavors());
if (flavor == null) {
// This should never happen with text files.
throw new IllegalArgumentException(
"Data has no flavors capable of supplying text.");
}
String result;
try (Reader reader = flavor.getReaderForText(handler)) {
StringBuilder s = new StringBuilder();
int c;
while ((c = reader.read()) >= 0) {
s.append((char) c);
}
result = s.toString();
} catch (UnsupportedFlavorException e) {
// Since we started with a flavor provided by the DataHandler,
// we should never get here.
throw new RuntimeException(e);
}

If you want to read the string from the body simply use
String result = componentInstanceService.getResource(componentResourceType).readEntity(String.class);

Related

Append parameters to an existing url in Spring boot Java?

I am trying to call a rest api and get the data from the api. I need to add dynamic parameters to the url in spring boot. I am a bit lost as how should I go about it. Can anyone kindly suggest me something?
RestTemplate restTemplate = new RestTemplate();
String consumeJSONString = restTemplate.getForObject("https://maps.googleapis.com/maps/api/geocode/json?latlng=5.47686,-73.961452&key=YOUR_API_KEY"
, String.class);
I would like to append latlng and api key in the url dynamically. I would really appreciate any suggestions.
You have to use the following variation of getForObject method
restTemplate.getForObject(url, responseType, uriVariables);
So it becomes..
String url = "https://maps.googleapis.com/maps/api/geocode/json?latlng={latlng}&key={key}";
Map<String, Object> uriVariables = new HashMap<>();
uriVariables.put("latlng", "5.47686,-73.961452");
uriVariables.put("key", "YOUR_API_KEY");
String consumeJSONString = restTemplate.getForObject(url, String.class, uriVariables);
As i got a solution to dynamic variable
where this is a Rest Url
#RequestMapping(value = "/studentdetail")
public User detailStudent(#RequestParam(value = "userid", required = true) String userid) throws SQLException { /*your task goes here*/}
and this is what i m sending the dynamic params as userid which can be anything hopefully it will help u a lot
URL url = new URL("http://localhost:9090/testpapers?userid=" + userid);
URLConnection conn = url.openConnection();
conn.setDoOutput(true);
OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream());
String s1=URLEncoder.encode(postDataParams, "UTF-8");
writer.write(s1);
writer.flush();
String line;
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
while ((line = reader.readLine()) != null)
{
System.out.println(line);
}
writer.close();
reader.close();
}
If using Spring Framework, we have org.springframework.web.util.UriTemplate which does this in a structured way
Default URI in application.properties
we can define a parametrized uri in properties file. For eg
url.template.google.maps=https://maps.googleapis.com/maps/api/geocode/json?latlng={latitude},{longitude}&key={api_key}
Initialize UriTemplate
The template that we defined in properties file can now be read in a #PostConstruct block and stored in UriTemplate variable. I am saying #PostConstruct just to save trips to fetch the template for each request
#Value("${url.template.google.maps}")
private String googleMapsUri;
private UriTemplate googleMapsServiceUriTemplate;
#PostConstruct
private void init() throws URISyntaxException {
googleMapsServiceUriTemplate= new UriTemplate(googleMapsUri);
}
Expand variables and get URI
Now that we have everything, let's expand and get the uri
Given these values, call below method to get the URI
String latitudeValue = "5.47686";
String longitudeValue = "-73.961452";
String apiKeyValue = "api_key_value";
Below method would take the necessary values, create a map with these values and then expand the uri template to populate the values. We get a nicely structured URI this way.
pubic URI getGoogleMapsServiceUri(latitudeValue, longitudeValue, apiKeyValue) {
Map<String, String> templateVariables = new HashMap<>();
templateVariables.put("latitude", latitudeValue); //could use a variable here
templateVariables.put("longitude", longitudeValue); //could use a variable here
templateVariables.put("api_key", apiKeyValue); //could use a variable here
URI googleMapsServiceUri = googleMapsServiceUriTemplate.expand(templateVariables);
System.out.println("URL is " + googleMapsServiceUri.getPath());
return googleMapsServiceUri;
}

Get all path variable

I want to develop a service that return a json file.
#RequestMapping(value = "/{fileName}/**", method = RequestMethod.GET, produces = { "application/json" })
public String jsonREST(#PathVariable String fileName) {
StringBuilder jsonBuilder = new StringBuilder();
logger.info("===> File name: " + fileName);
try {
BufferedReader bf = new BufferedReader(new FileReader("fileName + ".json"));
String line = null;
while ((line = bf.readLine()) != null) {
jsonBuilder.append(line);
}
} catch (Exception e) {
System.out.println("Error Parsing: - ");
}
return jsonBuilder.toString();
}
I need to get the path for example if the json file is in subdirectory or else.
use cases:
localhost:8080/my-directory/my-sub-dir/my-json-file
localhost:8080/my-json-file
Would you have any idea how I can get the hole path for example
my-directory/my-sub-dir/my-json-file
Or if you have another solution to do the same job, I will be very happy for that
Best regards
You can get the full request url by having Spring inject the HttpServletRequest and getting it as follows:
#RequestMapping(value = "/{fileName}/**", method = RequestMethod.GET, produces = { "application/json" })
public String jsonREST(HttpServletRequest request, #PathVariable String fileName) {
String uri = request.getRequestURI();
//Do your stuff here
}
Seems like you don't need a servlet container to achieve this. If I get what you are trying to do, you want to serve the json files statically. Try tweaking this:
https://spring.io/blog/2013/12/19/serving-static-web-content-with-spring-boot

mocking a url connection object that is dependent on a string parameter

A newcomer to the world of mocks. Wondering how I could test the following method by the use of a mock object (mockito, preferrably, since I'm starting off on it)
public class WeatherServiceImpl implements IWeatherService {
private static final Logger LOGGER=LoggerFactory.getLogger(WeatherServiceImpl.class);
#Override
public String getWeatherDataFromWeb(String cityName){
return run(cityName);
}
public String run(String city){
long threadId=Thread.currentThread().getId();
String myId=String.format(" (Thread ID: %d)",threadId);
LOGGER.info(" ");
//System.out.println("\n Initializing...");
LOGGER.info(" 1.============Initializing...============"+myId);
//format the string so that all 'space' characters are replaced by '%20'
String cityFormatted=city.replaceAll(/\s+/,"%20")
//HTTP Get Request
String url="http://api.openweathermap.org/data/2.5/weather?q="+cityFormatted;
URL obj=new URL(url);
LOGGER.info(" 2.>>>>>>>>>>>> OPENING Conn."+myId)
URLConnection conn=(HttpURLConnection) obj.openConnection();
LOGGER.info(" 3.<<<<<<<<<<<< CONN. OPENED."+myId)
//use GET
conn.setRequestMethod("GET");
//Get response code
LOGGER.info(" 4.---> Sending 'GET' request to URL: "+url+myId);
int responseCode=conn.getResponseCode();
LOGGER.info(" 5.<--- Got Response Code: "+responseCode+myId);
StringBuffer response = new StringBuffer();
//Check for validity of responseCode
if(responseCode==200) {
BufferedReader inn = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String inputLine;
while ((inputLine = inn.readLine()) != null) {
response.append(inputLine);
}
inn.close();
} else {
response.append("ERROR:$responseCode");
}
//System.out.println("\n Done.");
LOGGER.info(" 6.============ Done.============"+myId);
LOGGER.info(" ");
return response;
}
}
It would be nice to test the method 'run', with some arguments that return code 200, or some arguments that return an error code. For that matter, I think I need to be able to define a mock representation for the URL class (obj), but since this is directly dependent on the 'city' parameter, I'm not sure how to inject this dependency on an instance of the URL class (obj) using mock. Any suggestion is welcome.
One way would be to have a getStringURL(String s) method in a new class (like some helper class) and then inject that class in your WeatherServlceImpl. You can mock this helper class and make the getStringURL() return a Mock URL object. Once you have that, you can mock all the method calls on this URL object.

how to read multipart entity from android in jersey web service

i am getting multipart entity from android client as shown below.
HttpClient httpClient = new DefaultHttpClient();
HttpPost postRequest = new HttpPost(
"http://localhost:9090/MBC_WS/rest/network/mobileUserPictureInsert1");
MultipartEntity reqEntity = new MultipartEntity(
HttpMultipartMode.BROWSER_COMPATIBLE);
reqEntity.addPart("message", new StringBody("hi moni"));
postRequest.setEntity(reqEntity);
HttpResponse response = httpClient.execute(postRequest);
In jersey i am trying to retrieve message but getting only object.the code is:
#Path("/mobileUserPictureInsert1")
#POST
#Consumes("multipart/*")
public String create(MultiPart multiPart){
BodyPartEntity bpe = (BodyPartEntity) multiPart.getBodyParts().get(0).getEntity();
String message = bpe.toString();
here i AM getting some object ony not message value. what mistake i made.pl help me.
Yes the the right result. toString() will just use Object.toString(), which will result in
getClass().getName() + '#' + Integer.toHexString(hashCode())
which is most likely what you're seeing. Unless BodyEntityPart overrides the toString(), which it doesn't. You should instead be getting the InputStream with BodyEntityPart.getInputStream(). Then you can do whatever with the InputStream.
A simple example:
#POST
#Consumes("multipart/*")
public String create(MultiPart multiPart) throws Exception {
String message;
try (BodyPartEntity bpe
= (BodyPartEntity) multiPart.getBodyParts().get(0).getEntity()) {
message = getString(bpe.getInputStream());
}
return message;
}
private String getString(InputStream is) throws Exception {
StringBuilder builder = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(is))) {
String line;
while((line = reader.readLine()) != null) {
builder.append(line).append("\n");
}
}
return builder.toString();
}
On another note: You are already using the Jersey multipart support, you can make life easier and just use its annotation support. For instance, you can just do
#POST
#Consumes("multipart/*")
public String create(#FormDataParam("message") String message){
return message;
}
That is much easier. The #FormDataParam("message") gets the body name that you defined here:
reqEntity.addPart("message", new StringBody("hi moni"));
and converts to to String. As long as there's a MessageBodyReader available for the Content-Type of the body part, it should be able to be auto-converted.
See more on Multipart support
Here's another example showing a file upload

Google GSON not parsing JSON in Java retrieved from a WebMethod in a C# website

I have an ASP.NET website that uses C# to create JSON via a WebMethod, the webmethod is then called from a Java android application via an http post. I provide the webmethod with a page id and it returns the page contents, in this case it returns the content for an error page.
This is the JSON returned by the webmethod:
D/WebInterface( 2353): {"d":[{"intId":2418,"strName":"Error 404","strTitle":"Ooo
ps, I couldn\u0027t find that!","strSummary":"Error 404, I couldn\u0027t find th
e page you\u0027re looking for.","strBody":"\u003cp\u003eYou could try browsing
the website or checking that you typed the URL correctly, if you came to this pa
ge from another site, please let me know and thanks for visiting.\u003c/p\u003e"
,"strUpdateDate":null,"strCreateDate":null}]}
I use Google GSON in my Android app to create an object from the JSON but it returns null no matter what I do. Here is my Google GSON method:
public static Containerdata resultsFromJson(String json)
{
try
{
GsonBuilder gsonBuilder = new GsonBuilder();
Gson gson = gsonBuilder.create();
Containerdata results = gson.fromJson(json, Containerdata.class);
Log.d("WebInterface", "RETURNING OBJECT FROM JSON");
return results;
}
catch(Exception e)
{
Log.d("WebInterface", "Error: Malformed JSON.");
return null;
}
}
This method returns Containerdata which is below:
public class Containerdata {
public List<Containerdata.Node> d;
public class Node
{
int intId;
String strName;
String strTitle;
String strSummary;
String strBody;
String strUpdateDate;
String strCreatedate;
}
}
Containerdata returned by resultsFromJson is always null no matter what I do to the json returned by the webmethod and I have no idea why. This is the method that gets my JSON from my WebMethod:
// Gets json in the form of a string from a web service
public static String dataFromWeb(String url, String postData)
{
Log.d("WebInterface", "Loading from web");
try
{
HttpURLConnection httpcon = (HttpURLConnection) ((new URL(url).openConnection()));
httpcon.setDoOutput(true);
httpcon.setRequestProperty("Content-Type", "application/json");
httpcon.setRequestProperty("Accept", "application/json");
httpcon.setRequestMethod("POST");
httpcon.connect();
byte[] outputBytes = postData.getBytes("UTF-8");
OutputStream os = httpcon.getOutputStream();
os.write(outputBytes);
os.close();
InputStream response = httpcon.getInputStream();
Log.d("WebInterface", Helpers.convertStreamToString(response));
return Helpers.convertStreamToString(response);
}
catch(Exception e)
{
Log.d("WebInterface", "failed from web... " + e.toString());
return "";
}
}
Could anyone please help and point me in the right direction, I'd be very greatful.
Thanks a lot in advance!
The problem is in the following code...
InputStream response = httpcon.getInputStream();
Log.d("WebInterface", Helpers.convertStreamToString(response));
return Helpers.convertStreamToString(response);
You're basically trying to read the InputStream twice. The first time is when you log the response and the second time is when you try to return the response. The problem is you can't read a stream when it has already been read (OK, you can but that requires different code).
If you want to log the response then read the string locally and then log it and return it...
InputStream response = httpcon.getInputStream();
String responseString = Helpers.convertStreamToString(response);
Log.d("WebInterface", responseString);
return responseString;

Categories