How to read JSON from file and replace objects with value? - java

I need to read JSON from file and replace few objects.
For example, I have class User.java
public class User {
String username;
String email;
String city;
String code;
}
and JSON:
{
"variables":
{
"user":
{
"value":
{
"username": "$USERNAME",
"email": "$EMAIL",
"city": "$CITY"
}
}
}
}
I have two questions:
How can I read JSON from file? Read JSON will be send by WebClient POST API.
How can I replace $USERNAME, $EMAIL and $CITY? I won't hardcode it.
I have register form. When someone complete form, it will be replaced for $...
Firsty, I got hardcode JSON to string but I need read it from file
class JSONClass {
static String toFormat(User user) {
String jsonUserRegister = "{\n" +
" \"variables\":\n" +
" {\n" +
" \"user\": \n" +
" {\n" +
" \"value\":\n" +
" {\n" +
" \"username\": \"" + user.getUsername() + "\",\n" +
" \"email\": \"" + user.getEmail() + "\",\n" +
" \"city\": \"" + user.getCity() + "\",\n" +
" \"code\": \"" + user.getCode() + "\"\n" +
" } }\n" +
" }\n" +
"}";
return jsonUserRegister;

This can be achieved using Spring Boot to set up the backend to receive client calls. So to get Task 1a working, we need below
#RestController
public class JsonReaderController {
#Autowired
private ResourceLoader resourceLoader;
#PostMapping(value = "/read-json")
public String fileContent() throws IOException {
return new String(Files.readAllBytes(
resourceLoader.getResource("classpath:data/json- sample.json").getFile().toPath()));
}
}
Above code simply reads file content and returns as String. Note default response is Json.
Now that we have the backend done, we need Task 1b - Sending the POST request.
private String readJsonFile() throws IOException {
final OkHttpClient client = new OkHttpClient();
final String requestUrl = "http://localhost:8080/read-json";
Request request = new Request.Builder()
.url(requestUrl)
.post(RequestBody.create(JSON, ""))
.build();
try (Response response = client.newCall(request).execute()) {
//we know its not empty given scenario
return response.body().string();
}
}
readJsonFile method makes a POST request - using OkHttp to our backend bit (done in Task 1a) and returns the content of the file as json.
And for Task 2 - replacing $USERNAME, $EMAIL and $CITY with appropriate values. For this, we will use the Apache commons-text library.
public static void main(String[] args) throws IOException {
String fileContent = new ReadJsonFromFile().readJsonFile();
User user = new User("alpha", "alpha#tesrt.com", "Bristol", "alpha");
Map<String, String> substitutes = new HashMap<>();
substitutes.put("$USERNAME", user.getUsername());
substitutes.put("$EMAIL", user.getEmail());
substitutes.put("$CITY", user.getCity());
substitutes.put("$CODE", user.getCode());
StringSubstitutor stringSubstitutor = new StringSubstitutor(substitutes);
//include double quote prefix and suffix as its json wrapped
stringSubstitutor.setVariablePrefix("\"");
stringSubstitutor.setVariableSuffix("\"");
String updatedContent = stringSubstitutor.replace(fileContent);
System.out.println(updatedContent);
}
Hope this helps.

Related

How do I get a value from such a JSON Response

This is What i get as a response from the PlacesApi after making a request.
But the issue is that i cant get the value of "photo_reference".
The issue is also the Objects being in Arrays and all , the whole response looks confusing.
Below is what i have tried in android studio Java
private void getUserLocationImage(String mLocationName) {
String url = "https://maps.googleapis.com/maps/api/place/findplacefromtext/json?input="+mLocationName+"&inputtype=textquery&fields=photos&key="+R.string.google_api;
// prepare the Activities Request
JsonObjectRequest getWeatherRequest = new JsonObjectRequest(Request.Method.GET, url, null,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
JSONArray dataArray = response.getJSONArray("candidates");
JSONObject photosObj = dataArray.getJSONObject(0);
JSONArray photosArray = photosObj.getJSONArray("photos");
JSONObject photoRefObj = photosArray.getJSONObject(0);
String imageRef = photoRefObj.get("photo_reference").toString();
Toast.makeText(HomeLandingPageActivity.this, ""+imageRef, Toast.LENGTH_SHORT).show();
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d("Error.Response", error.toString());
}
});
// add it to the RequestQueue
queue.add(getWeatherRequest);
}
This is the Error
org.json.JSONException: Index 0 out of range [0..0)
This is what the response is in the Web
{
"candidates" : [
{
"photos" : [
{
"height" : 4160,
"html_attributions" : [
"\u003ca href=\"https://maps.google.com/maps/contrib/111684034547030396888\"\u003eCaroline Wood\u003c/a\u003e"
],
"photo_reference" : "CmRaAAAAQkMptoZgWJHING5qIR5_abXvnxjhHHEOHmDRH3ZpXUrar5PfpN5tQhhPoPwYmTDjpdVmXeT3T9klnrdK4xMvuudPm309UxMcx_ddbiu6E4shWYaPFn4gO4Diq4mOM46EEhCoo3TLpUbrWhInjelgVtYZGhSDJPyoRefWJ8WIcDs8Bk8VXAwHyQ",
"width" : 3120
}
]
}
],
"status" : "OK"
}
Try to use Gson library for deserilization your response. http://tutorials.jenkov.com/java-json/gson.html
It's very simple way to get any values from response
At first need create class with response model
import java.util.List;
public class ResponseBody {
public List<Candidates> candidates;
public static class Candidates {
public List<Photos> photos;
public static class Photos {
public int height;
public int width;
public String photo_reference;
public List<String> html_attributions;
}
}
}
Then just get your response as String and deserilize it:
String json = "{\n" +
" \"candidates\" : [\n" +
" {\n" +
" \"photos\" : [\n" +
" {\n" +
" \"height\" : 4160,\n" +
" \"html_attributions\" : [\n" +
" \"\\u003ca href=\\\"https://maps.google.com/maps/contrib/111684034547030396888\\\"\\u003eCaroline Wood\\u003c/a\\u003e\"\n" +
" ],\n" +
" \"photo_reference\" : \"CmRaAAAAQkMptoZgWJHING5qIR5_abXvnxjhHHEOHmDRH3ZpXUrar5PfpN5tQhhPoPwYmTDjpdVmXeT3T9klnrdK4xMvuudPm309UxMcx_ddbiu6E4shWYaPFn4gO4Diq4mOM46EEhCoo3TLpUbrWhInjelgVtYZGhSDJPyoRefWJ8WIcDs8Bk8VXAwHyQ\",\n" +
" \"width\" : 3120\n" +
" }\n" +
" ]\n" +
" }\n" +
" ],\n" +
" \"status\" : \"OK\"\n" +
"}";
Gson gson = new Gson();
ResponseBody responseBody = gson.fromJson(json, ResponseBody.class);
System.out.println("responseBody = " + responseBody.candidates.get(0).photos.get(0).photo_reference);
I got this:
responseBody = CmRaAAAAQkMptoZgWJHING5qIR5_abXvnxjhHHEOHmDRH3ZpXUrar5PfpN5tQhhPoPwYmTDjpdVmXeT3T9klnrdK4xMvuudPm309UxMcx_ddbiu6E4shWYaPFn4gO4Diq4mOM46EEhCoo3TLpUbrWhInjelgVtYZGhSDJPyoRefWJ8WIcDs8Bk8VXAwHyQ

Is there any method to get TraceId of Zipkin in Java Code

I want to retrieve the TraceId of Zipkin, is there any method to get it ?
If service 2 is getting traceId from service 1, you can take the traceId from requestHeader in your java code. Otherwise sleuth generate a new traceId in service 2.
To get the trace Id In java
#Autowired
private Tracer tracer;
Just do
tracer.getCurrentSpan().traceIdString();
Hello you can also get the x-b3-traceid header information from the request, I created a Util class for that -> https://gist.github.com/walterwhites/067dd635986e564aafdb5ac559073b0f
public final class DebugUtils {
private static String PURPLE = "\033[0;35m"; // PURPLE
private static String RED = "\u001B[31m"; // RED
private static String RESET = "\u001B[0m";
public static class ZipkinDebug {
private static String url = "http://localhost:9411/zipkin/traces/";
public static void displayTraceUrl(HttpServletRequest request) {
String traceId = request.getHeader("x-b3-traceid");
System.out.println(PURPLE + "DebugUtils:ZipkinDebug -> " + url + traceId + RESET);
}
}
public static class RequestInfo {
public static void displayAllRequestHeaders(HttpServletRequest request) {
Enumeration<String> headerNames = request.getHeaderNames();
System.out.println(RED + "DebugUtils:RequestInfo -> " + RESET);
headerNames.asIterator().forEachRemaining(header -> {
System.out.println("Header Name:" + header + " " + "Header Value:" + request.getHeader(header));
});
}
public static void displayRequestHeader(HttpServletRequest request, String headerName) {
System.out.println(RED + "DebugUtils:RequestInfo -> Header Name:" + headerName + " " + "Header Value:" + request.getHeader(headerName) + RESET);
}
}
}
Then in your main class you just need to call
ZipkinDebug.displayTraceUrl(request);

Call WS Rest Java with AngularJS

I've a problem with call WS Rest Java. I call the WS but the parameters isn't passed.
My java code:
#POST
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response setUser(#FormParam("name") String name, #FormParam("surname") String surname, #FormParam("email") String email,
#FormParam("phone") String phone, #FormParam("skype") String skype, #FormParam("password") String password){
try {
FileOutputStream fis = new FileOutputStream("/home/File.txt");
PrintStream ps = new PrintStream(fis);
String s = "name: "+name+"\nSurname: "+surname+"\nEmail: "+email+"\nPhone: "+phone+"\nSkype: "+skype+"\nPassword: "+password;
ps.println(s);
ps.close();
fis.close();
UserDAO userdao = new UserDAO(0,name,surname,email,phone,skype);
userdao.save();
...
return Response.status(200).entity(new ObjectMapper().writeValueAsString("OK!")).header("Access-Control-Allow-Origin", "*").build();
} catch (Exception e) {
e.printStackTrace();
return Response.status(500).entity("ERROR!").header("Access-Control-Allow-Origin", "*").build();
}
}
Angular call:
data = {
name: $scope.reg_name,
surname: $scope.reg_surname,
email: $scope.reg_email,
phone: $scope.reg_phone,
skype: $scope.reg_skype,
password: $scope.reg_password
}
$http.post(baseUrl+'user/',data,{
headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
});
If i log data on angular data are set, the call working but i've an error when i create AccountDAO object because the parameters are null. To test the parameters values i create a file and put here the value, the content are this:
name: null
Surname: null
Email: null
Phone: null
Skype: null
Password: null
Any one have idea why not pass the parameters?
Thanks!
Solved:
data = "name=" + $scope.reg_name +
"&surname=" + $scope.reg_surname +
"&email=" + $scope.reg_email +
"&phone=" + $scope.reg_phone +
"&skype=" + $scope.reg_skype +
"&password=" + $scope.reg_password;
}
$http.post(baseUrl+'user/',data,{
headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
})
Thanks grizzly!
You are sending data as JSON. Change it to form data string:
data = "name=" + $scope.reg_name +
"&surname=" + $scope.reg_surname +
"&email=" + $scope.reg_email +
"&phone=" + $scope.reg_phone +
"&skype=" + $scope.reg_skype +
"&password=" + $scope.reg_password;
}
$http.post(baseUrl+'user/',data,{
headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
})

JestResult.getSourceAsObjectList - for "#timestamp" or seemingly any field starting with "#"

How would JestResult.getSourceAsObjectList be used to map the field "#timestamp"? Actually, I cannot figure out how to map any field with a name starting with "#". It keeps getting set to "null".
For example if the Elasticsearch query returns
{
"_id": "Vhv2OE1SNSeSg285UYQRQ",
"#version": "1",
"#timestamp": "2014-12-19T01:18:06.454Z"
"type": "hdfs"
}
and there is a matching POJO Java class
import io.searchbox.annotations.JestId;
public class ElasticsearchLog {
#JestId
private String _id;
private String version;
private String timestamp;
private String type;
#Override
public String toString() {
return "ElasticsearchLog{" +
"_id='" + _id + '\'' +
", version='" + version + '\'' +
", timestamp='" + timestamp + '\'' +
", type='" + type + '\''
' }';
}
Then doing
import io.searchbox.client.JestClient;
import io.searchbox.client.JestClientFactory;
import io.searchbox.client.JestResult;
import io.searchbox.client.config.HttpClientConfig;
import io.searchbox.core.Search;
import java.util.List;
public class JESTClient {
public static void main(String[] args) throws Exception {
String clusterIP = "localhost";
String port = "9200";
//setup client
JestClientFactory factory = new JestClientFactory();
factory.setHttpClientConfig(new HttpClientConfig
.Builder("http://" + clusterIP + ":" + port)
.multiThreaded(true)
.build());
JestClient client = factory.getObject();
Search search = new Search.Builder("{ \"query\": { \"match_all\": {} } }")
.addIndex("_all")
.build();
JestResult result = client.execute(search);
List<ElasticsearchLog> resultLogs = result.getSourceAsObjectList(ElasticsearchLog.class);
for(ElasticsearchLog log: resultLogs){
System.out.println(log);
}
Prints out
ElasticsearchLog{_id='Vhv2OE1SNSeSg285UYQRQ', version='null', timestamp='null', type='hdfs'}
So the "#version" and "#timestamp" are not getting mapped properly.
JsonObject itself seems to be just fine with "#" symbols:
import com.google.gson.JsonObject;
public static void main(String[] args){
JsonObject testy = new JsonObject();
testy.addProperty("#timestamp", "zzz");
System.out.println(testy.get("#timestamp"));
}
Outputs: "zzz"
What is the proper usage of JestResult.
getSourceAsObjectList to map a json field with a name starting with "#"?
Note: This is for
<dependency>
<groupId>io.searchbox</groupId>
<artifactId>jest</artifactId>
<version>0.1.4</version>
</dependency>
Searchly support to the rescue!
Email response from support#searchly.com
Ferhat Sobay replied:
Problem in here is #version requires a Java field as '#version' which is not possible with Java lang. #SerializedName annotation comes to rescue, had to dig a little but works!
So try below;
public class ElasticsearchLog {
#JestId
private String _id;
#SerializedName("#version")
private String version;
#SerializedName("#timestamp")
private String timestamp;
private String type;
#Override
public String toString() {
return "ElasticsearchLog{" +
"_id='" + _id + '\'' +
", version='" + version + '\'' +
", timestamp='" + timestamp + '\'' +
", type='" + type + '\''
' }';
}
Best,
#Ferhat

Sending data stream to multiple URLs using org.apache.commons.httpclient.HttpClient

Firstly, let me say I not a java programmer, I am a programmer on the IBM Iseries. However, I've been tasked with changing a current java application that currently sends a stream of data to one URL that will allow that same stream of data to be sent to multiple URLs based on a properties file. Our java app runs on the Iseries and we are using the org.apache.commons.httpclient.HttpClient class to send the data and the response is processed. Everything works great right now, but I wanted to see if anyone could point me in the right direction to complete this task.
Essentially, I need to send the same block of data to multiple URLs within the same thread or instance. I'm not sure if its possible or the best way to try to complete this. So, is there a way to create multiple instances within the same thread that will send the same data stream to multiple URLs? Before you start commenting I will say again that I am not a java programmer and I wasn't even sure how to phrase the question.
Added code sample:
public class Replication_CC implements TextProcessor {
public static String VERSION = "v2014.1.0";
static Logger log = Logger.getLogger(Replication_CC.class);
String url;
int retries = 1;
public Replication_CC(Properties p) {
super();
url = p.getProperty("url");
log.info("Service URL set to " + url);
retries = PropertiesUtil.getOptionalIntProperty(p, "retries", 1);
log.info("Retries set to " + retries);
}
public static void main(String[] args) throws Exception {
log.info("Replication " + VERSION);
log.info("Initializing...");
Properties p = PropertiesUtil.loadProperties(Replication_CC.class.getResource("/Replication_CC.properties"));
DQServer server = new DQServer(p, new Replication_CC(p));
server.run();
}
public String process(String request) throws Exception {
long processStart = System.currentTimeMillis();
String response = null;
for (int i=0; i<=retries; i++) {
try {
response = send(request, url);
if (response!=null) break;
}
catch (Exception e) {
log.warn("Error processing: " + e.getMessage());
if (i<retries) {
log.warn("Trying again (retry " + (i+1) + "...");
}
else {
log.error("Giving up on this transaction.");
break;
}
}
}
long processFinished = System.currentTimeMillis();
log.info("Request was processed in " + (processFinished-processStart) + "ms.");
return response;
}
public String send(String request, String url) throws Exception {
log.debug("Creating request...");
HttpClientParams params = new HttpClientParams();
params.setParameter("http.useragent", "http-api / Replication");
HttpClient client = new HttpClient(params);
PostMethod post = new PostMethod(url);
/*
List<NameValuePair> params = new ArrayList<NameValuePair>();
for (String key : globalRequest.keySet()) {
params.add(nvp(key, globalRequest.get(key)));
}
*/
post.setRequestBody(request);
// Log the request
if (log.isDebugEnabled()) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
post.getRequestEntity().writeRequest(baos);
baos.close();
log.debug("HTTP Request: \n" + StringUtils.repeat("*", 100) + "\n" + "Content Type: "
+ post.getRequestEntity().getContentType() + "\n" + "Content Length: "
+ post.getRequestEntity().getContentLength() + "\n" + "Request Headers: "
+ ArrayUtils.toString(post.getRequestHeaders()) + "\n" + "Request Params: " + baos.toString() + "\n" +
StringUtils.repeat("*", 100));
}
try {
log.info("Sending request...");
int responseCode = client.executeMethod(post);
//log.debug(String.format("Http Response Code [%s]", responseCode));
log.debug("Http Response Code [" + responseCode + "]");
if (responseCode == HttpStatus.SC_OK) {
String charset = post.getResponseCharSet();
log.debug("Response Character Set [" + charset + "]");
/*
byte[] body = post.getResponseBody();
String response = new String(body, charset);
*/
String response = IOUtils.toString(post.getResponseBodyAsStream());
log.debug("Response Body: \n" + response);
return response;
}
else {
throw new Exception(post.getStatusLine().toString());
}
}
catch (IOException ioe) {
log.error(ioe);
throw ioe;
}
finally {
post.releaseConnection();
}
}
One simple way is to include multiple URL's in the existing url property separated by a unique character. I chose "|" (pipe) in this example because it's highly unlikely to see a pipe in a normal url.
Java identifies methods by name and parameter signature. We can use that to our advantage by adding a String url parameter to the existing process method and creating a new process(String request) method that will split and iterate over the url's. The only downside is that it will only return the last response to the DQServer class.
public String process(String request) throws Exception {
String response;
for (String u : url.split("\\|")) {
response = process(request, u);
}
return response;
}
public String process(String request, String url) throws Exception {
long processStart = System.currentTimeMillis();
String response = null;
for (int i=0; i<=retries; i++) {
try {
response = send(request, url);
if (response!=null) break;
}
catch (Exception e) {
log.warn("Error processing: " + e.getMessage());
if (i<retries) {
log.warn("Trying again (retry " + (i+1) + "...");
}
else {
log.error("Giving up on this transaction.");
break;
}
}
}
long processFinished = System.currentTimeMillis();
log.info("Request was processed in " + (processFinished-processStart) + "ms.");
return response;
}
The complete sample is available on GitHub Gist.

Categories

Resources