Avoid calling toString with Objectmapper [Java 8] - java

I achieved what I was trying to accomplish, however, I am not satisfied with the unnecessary(?) string-parsing to arrive to my goal.
Here is the simplified code:
HttpURLConnection con = null;
URL url = new URL(URL);
con = (HttpURLConnection) url.openConnection();
// set connection parameters and make a GET-call
con.setRequestMethod("GET");
//Must be a better way?
InputStream inputStream = con.getInputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder response = new StringBuilder();
String currentLine;
//Build the string from the response from con
while ((currentLine = in.readLine()) != null)
response.append(currentLine);
in.close();
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(response.toString());
// I only want the child-node
String myArray = jsonNode.get("parent").get("child").toString();
// Map the response to my object
List<Car> car = objectMapper.readValue(myArray, new TypeReference<List<Car>>(){});
There is so much manual parsing like
Reading the Http connection input stream to StringBuilder, then calling toString().
Retrieving the JsonNode and calling toString()
jsonNode.get("parent").get("child").toString()
to achieve my goal. I am by no means any senior- developer, and I gladly take advice and how I can remove "unnecessary" parsing.
The response from the API-call is in JSON already
Can only use HttpURLConnection-class for the API-call.
My Car class:
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"id",
"color"})
public class Car {
#JsonProperty("id")
public String id;
#JsonProperty("color")
public String color;
}

It is glad to see you want to improve your code.
Reading the input stream to StringBuilder and calling jsonNode.toString() is really unnecessary. In most of the case, there is always an useful API for your need.
Here is my suggestions:
Use ObjectMapper#readTree(InputStream) to simplify the part for consuming the HTTP input stream.
JsonNode jsonNode = objectMapper.readTree(con.getInputStream());
After retrieving the target JsonNode, create a JsonParser and then call
JsonParser jsonParser = new TreeTraversingParser(jsonNode.get("parent").get("child"));
objectMapper.readValue(jsonParser,new TypeReference<List<Car>>(){});

Related

How I can save values to hash map from api?

try {
String apikey = "-------";
String url = "https://freecurrencyapi.net/api/v2/latest?apikey=" + apikey + "&base_currency=USD";
URL urlForGetRequest = new URL(url);
String readLine = null;
HttpURLConnection conection = (HttpURLConnection) urlForGetRequest.openConnection();
conection.setRequestMethod("GET");
int responseCode = conection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
BufferedReader in = new BufferedReader(new InputStreamReader(conection.getInputStream()));
StringBuffer response = new StringBuffer();
while ((readLine = in.readLine()) != null) {
response.append(readLine);
}
in.close();
System.out.println(response.toString());
} else {
throw new Exception("Error in API Call");
}
} catch (Exception ex) {
ex.printStackTrace();
}
How I can save values from api to Hashmap List? Where key will be first worth (e.g "JPY") and value will be worth of "JPY" (E.G 115).
I wanted to use Jackson lib, but I didn't find any information for how to do it.
enter image description here
What you're describing is caching. There are quite a few libraries to handle this, I would recommend EHCache, but I'm sure newer libraries have sprung up since last I did this kind of work. You should be using a framework to facilitate web calls. If you execute your calls from Spring, there are a set of annotations you can use that will do the caching for you behind the scenes.
Instead of having buffer reader consider using RestTemplate i,e
RestTemplate restTemplate = new RestTemplate();
String yurDestinationUrl= "http://blablalba";
ResponseEntity<String> response
= restTemplate.getForEntity(yurDestinationUrl + "/1", String.class);
ObjectMapper mapper = new ObjectMapper();
JsonNode root = mapper.readTree(response.getBody());
JsonNode name = root.path("name");
//then add extracted JsonNode to your desired map or list as you prefer
You can create a POJO (Plain Old Java Object) from the json response that you are dealing with.
There is an IntelliJ plugin which called RoboPOJOGenerator or by other websites which you can easily find with this search json to pojo
Or you can create that POJO manually.
After creating this class you should create gson from json string like below:
Gson gson = new Gson();
// JSON string to Java object
Currencies currencies = gson.fromJson(response.toString(), Currencies.class);
Finally you have a meaningful object instance which you can use/manipulate easily as you wish.

Issue trying to use JsonNode to access an external secured RESTful service

I am writing a Java class to access a third-party public REST API web service, that is secured using a specific APIKey parameter.
I can access the required Json array, using the JsonNode API when I save the json output locally to a file.
E.g.
JsonNode root = mapper.readTree(new File("/home/op/Test/jsondata/loans.json"));
But, if I try to use the live secured web URL with JsonNode
E.g.
JsonNode root = mapper.readTree(url);
I am getting a:
com.fasterxml.jackson.core.JsonParseException: Unexpected character ('<' (code 60))
which suggests that I have a type mismatch. But I am assuming that it is more likely to be a connection issue.
I am handling the connection to the REST service:
private static String surl = "https://api.rest.service.com/xxxx/v1/users/xxxxx/loans?apikey=xxxx"
public static void main(String[] args) {
try {
URL url = new URL(surl);
JsonNode root = mapper.readTree(url);
....
}
I have also tried to use:
URL url = new URL(surl);
HttpURLConnection httpcon = (HttpURLConnection) url.openConnection();
InputStream isr = httpcon.getInputStream();
JsonNode root = mapper.readTree(isr);
with the same result.
When I remove the APIKey I receive a Status 400 Error. So I think I must not be handling the APIKey parameter.
Is there way to handle the call to the secured REST service URL using JsonNode? I would like to continue to use the JsonNode API, as I am extracting just two key:value pairs traversing multiple objects in a large array.
Just try to simply read response into string and log it to see what's actually going on and why you do not receive JSON from server.
URL url = new URL(surl);
HttpURLConnection httpcon = (HttpURLConnection) url.openConnection();
InputStream isr = httpcon.getInputStream();
try (BufferedReader bw = new BufferedReader(new InputStreamReader(isr, "utf-8"))) {
StringBuilder sb = new StringBuilder();
String line;
while ((line = bw.readLine()) != null) { // read whole response
sb.append(line);
}
System.out.println(sb); //Output whole response into console or use logger of your choice instead of System.out.println
}

How to read json data from HttpURLConnection

I am using HttpURLConnection from application1 to get json data from applicaton2. 'applicaton2' sets json data in Rest response object. How can i read that json data after getting response in application1.
Sample code:
Application1:
url = "url to application2";
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.connect();
Application2":
List<ModelA> lListModelAs = Entities data;
GenericEntity<List<ModelA>> lEntities = new GenericEntity<List<ModelA>>(lListModelAs) {};
lResponse = Response.ok(lEntities ).build();
I need to read above json data from urlConnection from response.
Any hints? Thanks in advance.
After setting up your HttpURLConnection.
BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
StringBuilder response = new StringBuilder();
String line;
JsonObject obj = new JsonParser().parse(reader).getAsJsonObject();
boolean status = contentObj.get("status").getAsBoolean();
String Message = contentObj.get("msg").getAsString();
String Regno = contentObj.get("regno").getAsString();
String User_Id = contentObj.get("userid").getAsString();
String SessionCode = contentObj.get("sesscode").getAsString();
You can download the gson jar here enter link description here
Use dedicated library for json serialization/deserialization, Jackson for example. It will allow you to read json content directly from InputStream into POJOs that maps the response. It will be something like that:
MyRestResponse response=objectMapper.readValue(urlConnection.getInput(),MyRestResponse.class);
Looking good isnt it??
Here you have Jackson project GitHub page with usage examples.
https://github.com/FasterXML/jackson
You can use gson library
https://github.com/google/gson for parsing your data
Gson gson = new Gson();
YourClass objOfYourClass = gson.fromJson(urlConnection.getInputStream(), YourClass.class);

Trying to extract from JSON when it's null

Will try to explain my question here.
I have a program that is suppose to parse through an incoming JSON-file that I receive from a web-crawler.
public static void Scan(Article article) throws Exception
{
//When running program, creates a error text-file inside java Project folder
File file = new File("errorlogg.txt");
FileWriter fileWriter = new FileWriter(file, true);
// if file doesn't exists, then create it
if (!file.exists())
{
file.createNewFile();
}
//Setting up an URL HttpURLConnection given DOI
URL urlDoi = new URL (article.GetElectronicEdition());
//Used for debugging
System.out.println("Initial DOI: " + urlDoi);
//Transform from URL to String
String doiCheck = urlDoi.toString();
//Redirect from IEEE Xplore toe IEEE Computer Society
if(doiCheck.startsWith("http://dx."))
{
doiCheck = doiCheck.replace("http://dx.doi.org/", "http://doi.ieeecomputersociety.org/");
urlDoi = new URL(doiCheck);
}
HttpURLConnection connDoi = (HttpURLConnection) urlDoi.openConnection();
// Make the logic below easier to detect redirections
connDoi.setInstanceFollowRedirects(false);
String doi = "{\"url\":\"" + connDoi.getHeaderField("Location") + "\",\"sessionid\":\"abc123\"}";
//Setting up an URL to translation-server
URL url = new URL("http://127.0.0.1:1969/web");
URLConnection conn = url.openConnection();
conn.setDoOutput(true);
conn.setRequestProperty("Content-Type", "application/json");
OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream());
writer.write(doi);
writer.flush();
String line;
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
while ((line = reader.readLine()) != null )
{
//Used to see of we get something from stream
System.out.println(line);
//Incoming is JSONArray, so create new array and parse fill it with incoming information
JSONArray jsonArr = new JSONArray(line);
JSONObject obj = jsonArr.getJSONObject(0);
//Check if names from DBLP is the same as translators get
//AuthorName, from field creators
JSONArray authorNames = obj.getJSONArray("creators");
ArrayList<Author> TranslationAuthors = new ArrayList<Author>();
Here is the bit of the code that I'm talking about. As you can see I wanna run this code when I get some information from the bufferreader.
My problem is that my program doesn't seem to skip when I don't get a valid JSON. Instead it runs to this line of code:
JSONArray authorNames = obj.getJSONArray("creators")
And then is forced to exit since it can't get the field "creators" since there is none.
How can I do to make sure that my program don't encounter this problem? How can I easy put it in the error-logg file that I create that I could't collect any information.
I think you are working with a org.json.JSONObject? If that's so, there is a has method, which can be used to avoid the JSONException in case the key does not exist.
JSONArray authorNames = null;
if (obj.has("creators")) {
authorNames = obj.getJSONArray("creators");
}

com.fasterxml.jackson.databind.JsonMappingException: No content to map due to end-of-input

I need to map a JSON array object with java POJO class.
I wrote the code like this:
// execute the client with get method
InputStream inputStream = getMethod.getResponseBodyAsStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
ObjectMapper objectMapper = new ObjectMapper();
JsonFactory jsonFactory = new JsonFactory();
List<OwnerDetail> owners = new ArrayList<>();
JsonParser jsonParser = jsonFactory.createJsonParser(inputStream);
if (jsonParser.nextToken() != null && jsonParser.)
{ // end-of-input
owners = objectMapper.readValue(bufferedReader, TypeFactory.defaultInstance().constructCollectionType(List.class, OwnerDetail.class));
}
The above block is giving me following error:
com.fasterxml.jackson.databind.JsonMappingException: No content to map due to end-of-input
at [Source: java.io.BufferedReader#5e66c5fc; line: 1, column: 1]
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:164)
at com.fasterxml.jackson.databind.ObjectMapper._initForReading(ObjectMapper.java:3029)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:2971)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2128)
Any help would be appreciated. Thanks.
After reading response the data from the response is consumed.
If your code is in interceptor you could try creating response again and return as below:
Request request = chain.request();
Response originalResponse = chain.proceed(request);
final ResponseBody original = originalResponse.body();
// if(request.url().toString().equalsIgnoreCase(string)){
if (originalResponse.code() == HttpURLConnection.HTTP_OK) {
try {
String response = originalResponse.body().string();
JSONObject mainObject = new JSONObject(response);
// your mapping - manipulation code here.
originalResponse = originalResponse.newBuilder()
.header("Cache-Control", "max-age=60")
.body(ResponseBody.create(original.contentType(),
mainObject.toString().getBytes()))
.build();
} catch (JSONException | IOException e) {
e.printStackTrace();
}
}
return originalResponse;
Here response is created again and returned.
Do let me know any update.
The use of both inputStream and bufferedReader seems wrong. If you've made a JsonParser for the input, it is probably best to continue using it for the object mapping. There might be a problem with the buffered reader eagerly reading all the content from the stream, leaving nothing for the JSON parser to read.
There also looks to be a section missing from your code, in the if condition.
Something like this:
if (parser.isExpectedStartArrayToken()) {
owners = mapper.readValue(parser, mapper.getTypeFactory().constructCollectionType(List.class, OwnerDetail.class));
}
Extra notes:
It's recommended not to wrap streams in buffering/decoding (InputStreamReader) before passing to Jackson as Jackson's parsers have heavily optimised this process already
Actually, wrapping InputStreamReader in BufferedReader is practically always redundant as InputStreamReader does buffer content
TypeFactory and JsonFactory can both be obtained from an ObjectMapper instance
No need to initialise owners to an empty list that will get overridden anyway-- declare it without initialisation and use an else to set the default only when necessary
I guess you should use OutputStreamWriter to deserialize your response.
OutputStreamWriter wr = new OutputStreamWriter(con.getOutputStream());
wr.write(auth.toString());
wr.flush();

Categories