I am trying to build a JSON string as server response with the aid of the Jackson library. If the route is not 0 I am getting tis response {"status":201,"routes":null} but I have problem to set the status variable to 204 in the SDBean class if the routeD is 0 I am getting in the console this output {"status":204,"routes":[1,9,3]} but in POSTMAN chrome extension the respose takes too long and I am getting this output The response status was 0.
Check out the W3C XMLHttpRequest Level 2 spec for more details about when this happens.
I want to get the following if routeD is not 0 to get {"status":201} else {"routes": {1,3,9}}
How can I manage that with Jakson?
Receiver class:
#Path("/data")
public class Receiver {
#POST
#Consumes(MediaType.APPLICATION_JSON)
public Response storeData(Data data) {
Database db = new Database();
String macD = data.getMac();
int routeD = data.getRoute();
double latD = data.getLatitude();
double longD = data.getLongitude();
double speedD = data.getSpeed();
SDBean bean = new SDBean();
if (routeD != 0) {
bean.status = db.insertData(macD, routeD, latD, longD);
return Response.status(bean.status).entity(bean.toJson()).build();
} else {
bean.routes = db.detectRoute(latD, longD);
return Response.status(bean.status).entity(bean.toJson()).build();
}
}
}
SDBean class:
import java.util.ArrayList;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class SDBean {
public int status;
public ArrayList<Integer> routes;
public String toJson() {
ObjectMapper mapper = new ObjectMapper();
String json = null;
if(status == 0){
this.status = 204;
}
try {
json = mapper.writeValueAsString(this);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return json;
}
}
Your problem with 0 response due to you don't initialize your int value inside bean. When you try to analize your code :
//Inside Receiver
return Response.status(bean.status).entity(bean.toJson()).build();
In this line you first get value from status field from bean. It's initialize with default value of 0 (Oracle documentation about primitive data types and default values) and next you map it toJson() where you set it's value to status response 204 in this line :
//Inside SDBean
if(status == 0){
this.status = 204;
}
I suggest one of this resulutions:
Initialize variable inline:
public int status = 204;
If you need some additional logic you could use static initialization block
static {
//additional logic here
status = 204;
}
Or simply use constructor in your case:
public SDBean(){
//additional logic here
status = 204;
}
For more info here you have documentation: Initializing fields.
Also you don't add anything to your ArrayList. Try to initialize it inside your bean inline:
public ArrayList<Integer> routes = new ArrayList<Integer>();
or if you use jdk 1.7+ use diamond interfece instead
public ArrayList<Integer> routes = new ArrayList<>();
And now you can use it to add your data inside storeData class:
bean.routes.add(yourIntValue);
// EDIT:
package com.gmail.at.mironiuk.kacper.stack.overflow.wtf;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
#Path("/data")
public class Receiver {
#POST
#Consumes(MediaType.APPLICATION_JSON)
public Response storeData(Data data) {
Database db = new Database();
SDBean bean = new SDBean();
String macD = data.getMac();
int routeD = data.getRoute();
double latD = data.getLatitude();
double longD = data.getLongitude();
double speedD = data.getSpeed();
if (routeD != 0) { // here you always will have null or empty case you only set your status here
bean.status = db.insertData(macD, routeD, latD, longD); // In this if try to add sth to your list
bean.status = 204;
return Response.status(bean.status).entity(bean.toJson()).build(); //Expected result {"status":"204", "routes": []}
} else { // here your List will be this whats you returns from
bean.routes = db.detectRoute(latD, longD); // <- this function and i don't know what function returns
return Response.status(bean.status).entity(bean.toJson()).build(); //Expected result {"status":"204", "routes": [?,?,?]}
}
}
}
I hope that I help you
Related
Data is not added to List. The program gets data from a GraphQL server and filter it through a switch statements, then appends it to the corresponding list. However, the list is empty if accessed outside the switch statement. If you print one of the list in the switch statement, it will print correctly, however if you print it in the getter functions, it will not return anything.
What is wrong with it? The scope? I tried putting the initialization in a few places like on the same function or on the constructor however the result is the same.
package sukebei.anilog.data.source.AniList;
import android.util.Log;
import com.apollographql.apollo.ApolloCall;
import com.apollographql.apollo.ApolloClient;
import com.apollographql.apollo.api.Response;
import com.apollographql.apollo.exception.ApolloException;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import okhttp3.OkHttpClient;
import AniList.UserMediaQuery;
import AniList.UserMediaQuery.Data;
import AniList.type.MediaType;
/* Data Received Example
[
Entry {
__typename = MediaList,
progress = 0,
progressVolumes = null,
score = 0.0,
status = PLANNING,
notes = null,
repeat = 0,
media = Media {
__typename = Media,
chapters = null,
volumes = null,
idMal = 17082,
episodes = 12,
title = Title {
__typename = MediaTitle, romaji = Aiura
}
}
},
Entry {
__typename = MediaList,
progress = 0,
progressVolumes = null,
score = 0.0,
status = PLANNING,
notes = null,
repeat = 0,
media = Media {
__typename = Media,
chapters = null,
volumes = null,
idMal = 33218,
episodes = 1,
title = Title {
__typename = MediaTitle,
romaji = Kimi no Koe wo Todoketai
}
}
}
]
*/
public class AniList {
private static final String BASE_URL = "https://graphql.anilist.co";
private List<UserMediaQuery.Entry> planningMedia = new ArrayList<UserMediaQuery.Entry>();
private List<UserMediaQuery.Entry> currentMedia = new ArrayList<UserMediaQuery.Entry>();
private List<UserMediaQuery.Entry> completedMedia = new ArrayList<UserMediaQuery.Entry>();
private List<UserMediaQuery.Entry> droppedMedia = new ArrayList<UserMediaQuery.Entry>();
private List<UserMediaQuery.Entry> pausedMedia = new ArrayList<UserMediaQuery.Entry>();
private List<UserMediaQuery.Entry> repeatingMedia = new ArrayList<UserMediaQuery.Entry>();
private OkHttpClient okHttpClient;
private ApolloClient apolloClient;
public AniList() {
okHttpClient = new OkHttpClient.Builder().build();
apolloClient = ApolloClient.builder()
.serverUrl(BASE_URL)
.okHttpClient(okHttpClient)
.build();
}
public void loadUserData(String username, MediaType mediaType) {
UserMediaQuery mediaQuery = UserMediaQuery.builder()
.username(username)
.type(mediaType)
.build();
apolloClient.query(mediaQuery).enqueue(new ApolloCall.Callback<Data>() {
#Override public void onResponse(#NotNull Response<Data> dataResponse) {
for (UserMediaQuery.List data : dataResponse.data().userMediaList().lists()) {
for (UserMediaQuery.Entry entry: data.entries()) {
switch(entry.status()) {
case PLANNING:
planningMedia.add(entry);
break;
case CURRENT:
currentMedia.add(entry);
break;
case COMPLETED:
completedMedia.add(entry);
break;
case DROPPED:
droppedMedia.add(entry);
break;
case PAUSED:
pausedMedia.add(entry);
break;
case REPEATING:
repeatingMedia.add(entry);
break;
}
}
}
}
#Override
public void onFailure(#NotNull ApolloException t) {
Log.e("AniList Source", t.getMessage(), t);
}
}
);
}
public List getPlanningMedia() {
return planningMedia;
}
public List getCurrentMedia() {
return currentMedia;
}
public List getCompletedMedia() {
return completedMedia;
}
public List getDroppedMedia() {
return droppedMedia;
}
public List getPausedMedia() {
return pausedMedia;
}
public List getRepeatingMedia() {
return repeatingMedia;
}
}
This prints the data however when you print it in the getter function it does not print the data.
for (UserMediaQuery.List data : dataResponse.data().userMediaList().lists()) {
for (UserMediaQuery.Entry entry: data.entries()) {
if (entry.status() == MediaListStatus.PLANNING) {
planningMedia.add(entry);
Log.d("planning", planningMedia.toString());
}
}
}
apolloClient.query(mediaQuery).enqueue executes code in async, which means it enqueues the request and so the array list will be empty until the request is being done and is successful from another thread.
You might be using the getter directly without waiting for the callback to finish. If that's the case check out the following possible solutions.
If you are waiting for the request to finish to display something on your UI, you might want to bind the data to UI again by using something like notifyDataSetChanged() in case of RecyclerView for instance. Similarly, if you want to use this data for something else you should probably use a callback mechanism.
Hope this helps !!
I currently use handlebars in java (com.github.jknack.handlebars)
and have a handlebars helper method to get a link (with some logic behind)
{{ getLink data.node}}
which just render the url /subfolder/link.html
In my handlebars template I now only want to print the url (a-tag) when the helper method returns a non empty string (e.g. there is a link available)
I tried it with
{{#if getLink data.node }}
Link-Text
{{/if}}
but no link was rendered
What would be the correct syntax for my if?
Thanks
RCX
Edit:
getLink Helper Method in LinkHelper.class
public CharSequence getLink(JsonObject node, Options options) throws IOException {
String link = fetchLink(node);
if(link != null){
return link;
}
return "";
}
registered via
HandlebarsTemplateEngineImpl.getHandlebars().registerHelpers(new LinkHelper());
Handlebars.java is not well documented and missing couple of unit tests (consider to contribute if this answer helped), for some reason calling nested JsonObject removed at this commit, you can still call nested String, but there is a trick with parentheses.
Full example:
import com.github.jknack.handlebars.Context;
import com.github.jknack.handlebars.Handlebars;
import com.github.jknack.handlebars.Helper;
import com.github.jknack.handlebars.Template;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.Map;
public class HandlebarsJavaTest {
public static void main(String[] args) throws IOException {
Handlebars handlebars = new Handlebars();
Gson gson = new Gson();
handlebars.registerHelper("getLink", (Helper<Map<String, Object>>) (jsonObject, options) -> {
String link = fetchLink(jsonObject);
return link != null ? link : "";
});
String data = "{'data':{'node':'/bla.html', 'node2':'inside node2'}}";
// Pay attention to parentheses !!!
// {{#if (getLink data.node)}} throws ClassCastException, java.lang.String cannot be cast to java.util.Map
String rawTemplate = "{{#if (getLink data)}} Link-Text {{/if}}";
Type type = new TypeToken<Map<String, Object>>(){}.getType();
Map<String, Object> map = gson.fromJson(data, type);
Template template = handlebars.compileInline(rawTemplate);
Context context = Context.newBuilder(map).build();
System.out.println(template.apply(context));
}
private static String fetchLink(Map<String, Object> map) {
try {
return map.get("node").toString();
} catch (NullPointerException npe) {
return null;
}
}
}
Output:
Link-Text
If node is just a string ( same output )
public static void main(String[] args) throws IOException {
Handlebars handlebars = new Handlebars();
Gson gson = new Gson();
handlebars.registerHelper("getLink", (Helper<String>) (node, options) -> node != null ? node : "");
String data = "{'data':{'node':'/bla.html', 'node2':'inside node2'}}";
// Pay attention to parentheses !!!
String rawTemplate = "{{#if (getLink data.node)}} Link-Text {{/if}}";
Type type = new TypeToken<Map<String, Object>>(){}.getType();
Map<String, Object> map = gson.fromJson(data, type);
Template template = handlebars.compileInline(rawTemplate);
Context context = Context.newBuilder(map).build();
System.out.println(template.apply(context));
}
If you insist node is an object using this.[data] or this.[data.node] will not do the work, working example for the same output:
import com.github.jknack.handlebars.Context;
import com.github.jknack.handlebars.Handlebars;
import com.github.jknack.handlebars.Helper;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
public class HandlebarsJavaTest {
public static void main(String[] args) throws Exception {
System.out.println(
new Handlebars()
.registerHelper("getLink", (Helper<JsonObject>) (json, options) -> {
try {
// logic here
return json.get("data").getAsJsonObject().get("node").getAsJsonObject().get("link").getAsString();
} catch (NullPointerException npe) {
return null;
}
})
// Pay attention to parentheses !!
.compileInline("{{#if (getLink this) }} Link-Text {{/if}}")
.apply(
Context
.newBuilder(
new Gson()
.fromJson(
"{ 'data': { 'node': { 'link': '/bla.html' }, 'node2': 'inside node2' } }",
JsonObject.class
)
).build()
)
);
}
}
If you have time, consider to contribute to this open source by adding proper documentation or at least unit tests {{#if (method param)}}.
According to the source code
package com.github.jknack.handlebars;
public class IfBlockTest extends AbstractTest {
#Test
public void falsy() throws IOException {
// empty string
shouldCompileTo("{{#if value}}true{{else}}false{{/if}}", $("value", ""), "false");
BTW, the #if built-in helper will return False for empty string, so if getLink will execute return ""; the if condition will not and the text will not be rendered, to assert this you can add {{else}} before the closing if {{/if}} and see that what is rendered.
I have a textfield which uses autocomplete mixin on tapestry. The mixin is working fine as it is, but I am having a problem with tagging the values of list of names with duplicate values. Now I am wondering if I can somehow pass the id of the data on autocomplete upon selection.
Here is my code for pupulating the list.
List<String> onProvideCompletionsFromUserName(String partial) {
List<String> matches = new ArrayList<String>();
String partialUpper = partial.toUpperCase();
List<User> users = clientFinder.findUsers();
// int i = 0;
for (User user : users){
String name = NameUtil.toName(user.getFirstName(), user.getFamilyName());
if (name.toUpperCase().contains(partialUpper)) {
matches.add(name );
// if (i++ >= 5) {
// break;
// }
}
}
return matches;
}
Is there a way for me to pass the ID with the list like
(List onProvideCompletionsFromUserName)?
Has anyone encountered this problem as well ? Thanks for your response.
The only way I was able to do it was by extending the Autocomplete mixin with my own version, as the configure method in the mixin is marked protected. Here is my class. Note that I am firing my own event. You will have to give your own values for label, value and uid in the providecompletions handler. The zone parameter is the zone you want to update when the user clicks and item in the completion list.
Mixin:
import java.util.ArrayList;
import java.util.List;
import org.apache.tapestry5.BindingConstants;
import org.apache.tapestry5.ComponentResources;
import org.apache.tapestry5.annotations.OnEvent;
import org.apache.tapestry5.annotations.Parameter;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.json.JSONLiteral;
import org.apache.tapestry5.json.JSONObject;
import org.got5.tapestry5.jquery.mixins.Autocomplete;
public class UserAutocomplete extends Autocomplete {
public static final String CHANGE_EVENT_NAME = "autocompleteUser";
#Inject
private ComponentResources resources;
#Parameter(defaultPrefix=BindingConstants.LITERAL)
private String zone;
#OnEvent(value = "provideCompletions")
public List<JSONObject> autoComplete(String query) {
List<JSONObject> strings = new ArrayList<JSONObject>();
if(query != null) {
for(User u : service.searchUsers(query.trim())) {
JSONObject so = new JSONObject();
String name = u.getName();
so.put("label", name);
so.put("value", name);
so.put("uid", u.getId());
strings.add(so);
}
}
return strings;
}
protected void configure(JSONObject config) {
config.put("url", resources.createEventLink("autocomplete").toURI());
String url = resources.createEventLink(CHANGE_EVENT_NAME).toURI();
config.put("options", new JSONObject().put("select", new JSONLiteral("function(e, d) {var zone = $('#" + zone + "'); if (!zone) { return; } "
+ "zone.tapestryZone('update', {url: '" + url + "'+'/'+d.item.uid});}")));
}
}
Page Template:
<t:textfield value="query" autocomplete="off" t:mixins="UserAutocomplete" t:zone="resultZone" />
Page Class:
...
#InjectComponent
private Zone resultZone;
#OnEvent(value = UserAutocomplete.CHANGE_EVENT_NAME)
void userChange(Integer id) {
User selectedUser = service.findUser(id);
renderer.addRender(resultZone);
}
I have a JSON REST endpoint response and I wanted to get the value of hotelNbr from it. How do i do it ?
{
"found": [
{
"hotelNbr": 554050442,
"hotelAddress": "119 Maven Lane, New Jersey",
}
],
"errors": []
}
I am using the below code to get it but it fails in below mentioned line:
public List<Hotel> RDS_POST_HotelDetails(String HotelName, String sUrl) throws Exception, IOException {
Gson gson = new GsonBuilder().setPrettyPrinting().create();
// Create your http client
CloseableHttpClient httpclient = HttpClientBuilder.create().build();
// Create http Put object
HttpPost ohttppost = new HttpPost(sUrl);
// Message Body
StringEntity input = new StringEntity(
"{\"hotelNbr\":[\""+HotelName+"\" ]}"
);
// Set content type for post
input.setContentType("application/json");
// attach message body to request
ohttppost.setEntity(input);
// submit request and save response
HttpResponse response = httpclient.execute(ohttppost);
// Get response body (entity and parse to string
String sEntity = EntityUtils.toString(response.getEntity());
List<Hotel> hotelobject = new ArrayList<Hotel>();
// Create a type token representing the type of objects in your json response
// I had to use the full class path of TYPE because we also have a Type class in our project
java.lang.reflect.Type cType = new TypeToken<List<Hotel>>() {
}.getType();
// Convert to Array object using gson.fromJson(<json string>,
// <type>)
hotelObject = gson.fromJson(sEntity, cType); // I am getting error here
String hotelNumber = hotelObject.get(0).getFound().get(0).getItemNbr().toString();
}
Please find the Hotel.java class below
package com.hotels.company;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Hotel {
#SerializedName("found")
#Expose
private List<Found> found = null;
#SerializedName("errors")
#Expose
private List<Object> errors = null;
public List<Found> getFound() {
return found;
}
public void setFound(List<Found> found) {
this.found = found;
}
public List<Object> getErrors() {
return errors;
}
public void setErrors(List<Object> errors) {
this.errors = errors;
}
}
Please find Found.java class below :
package com.hotels.company;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Found {
#SerializedName("hotelNbr")
#Expose
private Integer hotelNbr;
#SerializedName("hotelAddress")
#Expose
private String hotelAddress;
public Integer getHotelNbr() {
return hotelNbr;
}
public void setHotelNbr(Integer hotelNbr) {
this.hotelNbr = hotelNbr;
}
public String getHotelAddress() {
return hotelAddress;
}
public void setHotelAddress(String hotelAddress) {
this.hotelAddress = hotelAddress;
}
}
I tried finding some examples in StackOverflow questions but didn't get solution for mine. Any help will be appreciated.
The JSON you are parsing is not well formatted..
There is a comma after "hotelAddress" remove that
Correct JSON would be:
{
"found":[
{
"hotelNbr":554050442,
"hotelAddress":"119 Maven Lane, New Jersey"
}
],
"errors":[ ]
}
I found a couple of issues:
Json is not valid. Observe there is a comma at the end of "hotelAddress": "119 Maven Lane, New Jersey",. Remove it.
You are trying to deserialize the json into List<Hotel>, but the json mentioned is not a list. Either update the json or deserialise it into Hotel object instead of List.
I have a project where you can ask for resources that are served by jax-rs in the json format. Everything works properly in the browser when I query the rest URL the json appears.
Now I want my GWT project to request those resources and process them and show them in my interface. The simplest way I found to do so is using a request builder and an overlay. Code is lower. The problem is, it seems when the code is running it never goes into the actual RequestCallback(). The status string is never changed. I thought it could be a SOP so I added the <add-linker name="xs"/> but still doesn't work. Any ideal?
package com.workoutcell.client;
//import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.JsArray;
import com.google.gwt.http.client.*;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.Response;
/**
*
* #author
*/
public class RestToInfoSession{
String queryReturn = null;
JsArray<InfoJSO> arrayOfInfo = null;
String host = "http://localhost:8080/mysite";
String restModule = "/calendar/getinfo";
String id = null;
String year = null;
String month = null;
String status = "Not Initialized";
public RestToInfoSession(String id, String year, String month){
this.id =id;
this.year = year;
this.month = month;
String url = host + restModule + "/"+this.id + "/"+this.year + "/"+this.month;
RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, url);
try {
status = "Initialized at Url " + builder.getUrl();
Request request = builder.sendRequest(null, new RequestCallback() {
public void onError(Request request, Throwable exception) {
// Couldn't connect to server (could be timeout, SOP violation, etc.)
status = "Error on connecting to Server";
}
public void onResponseReceived(Request request, Response response) {
if (200 == response.getStatusCode()) {
// arrayOfInfo = jsonToJsArray(response.getText());
status = "JSON has been Fetched. Result is:" + response.getText();
} else if(0 == response.getStatusCode()) {
status = "Error is 0";
} else {
status = "Error in JSON Request:" + response.getStatusCode();
//response.getStatusText();
}
}
});
} catch (RequestException ex) {
status = "Error in Request Builder Startup";
}
}
//get an jso object in array
private final native JsArray<InfoJSO> jsonToJsArray(String json) /*-{
return eval(json);
}-*/;
public JsArray<InfoJSO> getInfoArray (){
return arrayOfInfo;
}
}
UPDATE: My problem is the same as Referring to a non-final variable data inside an inner class . I wasn't aware of asynchronous calls working mechanism. I still don't know how to pass my response.getText() to update a label that isn't part of my RestToInfoSession class any ideas?
Consider using the RestyGWT project. It will make calling JAXRS JSON resources as easy as using GWT-RPC. Plus you can typically reuse the same request response DTOs from the server side on the client side.
I have put a timer that checks every 1000ms if my json string has updated from null to the xhttp requested data. This works, but I got a feeling there is a more elegant way of resolving this problem.