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

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.

Related

Retrieving String from JAX-RS Response

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);

Jersey WebTarget vs HTTPURLConnection

I'm learning web services using Java. I'm technically a noob, this is the code I've written, which works, I just don't know which method has what advantage over another, like which one is more secure? Which one will be more faster?
I'm not asking for complete too broad an answer. A short concise one will do.
I've created a REST service using Jersey 2.x and I've created client to consume the said REST service.
POST resource is as follows,
#POST
#Path("postactivity")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public String createActivity(
#QueryParam("id") int id,
#QueryParam("description") String description,
#QueryParam("duration") int duration,
#QueryParam("name")String name)
{
//My code that creates Activity object from QueryParams is here.
}
Now I've created a Client which is a Java Application. I'm consume the above REST Service above in following two ways.
Method 1 Using HTTPURLConnection
private static void doPost(){
QueryString qs = new QueryString("id", "123"); //QueryString is a class created to build query, not important to the question.
qs.add("duration", "12");
qs.add("description", "This is description");
qs.add("name", "This is Name");
String url = "http://localhost:8080/webservices/webapi/activities/activity?" + qs;
URL obj;
try {
obj = new URL(url);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestProperty("Content-Type","application/json");
con.setRequestMethod("POST");
con.setRequestProperty("User-Agent", "Mozilla 5.0");
con.setDoOutput(true);
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
Activity activity = GSON.fromJson(response.toString(), Activity.class); //This is for checking if i'm getting correct data back which I'm sending.
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Method 2 Using WebTarget available via Jersey
private static void doPost(){
Response entity = webTarget
.path("activities/postactivity")
.queryParam("id",2204)
.queryParam("description","Foo")
.queryParam("duration",100)
.queryParam("name", "Bar")
.request()
.post(null);
String entityRead = entity.readEntity(String.class);
System.out.println(entityRead);
Activity activityRead = GSON.fromJson(entityRead, Activity.class);
}
Thanks.
Honestyl i have two things to write to you:
1. The HttpURLConnection is the Java personal way of doing a retrieve of a web affiliate (like web services) but you have a better and stress-free way of doing it with Jersey and this will make things faster and smoother for you. For some persons they even say that the Jersey style is the High-level API while the HttpURLConnection is called the low-level API.
2. Your question was able to provide me with a necessary solution to a problem i have had for the past two days with consuming a #Queryparam POST webmethod. I really appreciate this.
Thanks

jquery ajax returns element not found

I have a REStful webservice (java, jersey) to do some stuff.
every function that calls an ajax request (GET or POST) with an url to the REST controller works fine... except of the recent ones and I do not know why.. i tried everything and stuck with this problem for nearly three days (wrote 3 different functions, changed from GET to POST, rewrote the function with new pathannotiation, tried to call on pageload.. renamed everything), I realy appreciate ANYTHING that could help me...
if the url contains rest/* the controller forwards it to the class which implements the needed functions..
JS function
function testFunc() {
$.ajax({
url: "rest/name/wut",
type: "GET",
contentType: "application/json;charset=utf-8",
success: function(response) {
alert("LSKDFJLSDKJFLKSD " + response);
},
error: function(response) {
alert("ma oidaaaa " + JSON.stringify(response));
}
});
};
Java Code in the RESTClass...
#GET
#Path("/wut")
#Produces(MediaType.APPLICATION_JSON)
private String wut() {
JSONObject json = new JSONObject();
json.put("print", "wuut");
return json.toString();
}
It does not matter if the method is doing anything useful or not... it just returns 404 no element found.
(it is not even called) Therefore i tried different new methods in the RESTClass... like:
#GET
#Path("/wut")
#Produces(MediaType.APPLICATION_JSON)
private String wut() throws IOException {
URL url = new URL(url);
StringBuffer response = new StringBuffer();
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
BufferedReader in = new BufferedReader(new InputStreamReader(
connection.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
return response.toString();
}
I am using this snipped in another method, which is working.. I replaced the real URL with "url" for posting btw.
I also tried different MediaTypes: WILDCARD, TEXT/PLAIN...
And to just return a String...
Anyone any ideas (and SORRY for the bad english, I am really desperate so i did not do a spellcheck and english is not my native :( )
Two ideas:
First, declare your wut() method as public: public String wut()
Second, try to call your method in a browser, for example http://localhost/rest/name/wut and see what happens
I would try to use an absolute path:
Change:
url: "rest/name/wut",
to
url: "/rest/name/wut",
The error message tells me that, your client did not try the address the server provides.

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

Send and receive JSON to REST WebService in Jersey Java

I am new to Jersey Java REST WebService framework. I am trying to write a service method which consumes and produces JSON. My service code is below. It is simplest code, just for studying purpose.
#Path("/myresource")
public class MyResource {
#Path("/sendReceiveJson")
#GET
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public String sendReceiveJson(String name)
{
System.out.println("Value in name: " + name);
return "{\"serviceName\": \"Mr.Server\"}";
}
}
And following is JerseyClient code.
public class Program {
public static void main(String[] args) throws Exception{
String urlString="http://localhost:8080/MyWebService/webresources/myresource/sendReceiveJson";
URL url=new URL(urlString);
URLConnection connection=url.openConnection();
connection.setDoOutput(true);
OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream());
out.write("{\"clientName\": \"Mr.Client\"}");
out.close();
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String decodedString;
while ((decodedString = in.readLine()) != null) {
System.out.println(decodedString);
}
in.close();
}
}
But when i run service and then client, i am unable to send/receive JSON data. I get Exception at connection.getInputStream() which is
Server returned HTTP response code: 405 for URL: http://localhost:8080/hellointernet/webresources/myresource/sendReceiveJson
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1625)
Please guide me, what needs to correct, or whether i am in wrong direction.
Your resource method is annotated as #GET which means any input data would have to be query string parameters.
In this context #Consumes(MediaType.APPLICATION_JSON) doesn't make a lot of sense as only APPLICATION_FORM_URLENCODED is supported via GET.
When you client calls setDoOutput(true) it probably switches your HTTP call to a POST hence causing the 405 Method Not Allowed.
If you want to consume JSON you should change your #GET annotation with #POST instead. Your client call should then work if it's indeed a POST. You can specify it with the following method:
HttpURLConnection httpCon = (HttpURLConnection) url.openConnection();
httpCon.setDoOutput(true);
httpCon.setRequestMethod("POST");
This API is pretty low level though, so I'd highly recommend you use Jersey's Client API instead. See https://jersey.java.net/documentation/1.17/client-api.html

Categories