trying to get to an Android App random recipes from Spoonacular. For some reason, I'm not getting the data from the json. I know how to do this in Javascript, but that's no use to me in Java.
My repository file:
public class RecipeRepository {
private static final String API_KEY = "472f31ce4a5e4e5792ca9ab6d1833e51";
private static final String URL = "https://api.spoonacular.com/recipes/random?apiKey=%s";
private final Application application;
private final MutableLiveData<ArrayList<Recipe>> recipeLiveData;
private final ArrayList<Recipe> arrayList = new ArrayList<>();
public RecipeRepository(Application application) {
this.application = application;
recipeLiveData = new MutableLiveData<>();
}
public void getDayRecipe() {
Ion.with(application)
.load(String.format(URL,API_KEY)).asJsonObject()
.setCallback((e, result) -> {
Log.i( "getRandomRecipe",result.getAsJsonPrimitive().toString());
parseResults(result);
});
}
public String removeAbles(String text) {return text.substring(1,text.length()-1); }
private void parseResults(JsonObject result) {
JsonObject randomRecipe = (JsonObject) result.getAsJsonArray("recipes").get(0);
String title = String.valueOf(randomRecipe.get("title"));
String instructions = String.valueOf(randomRecipe.get("Instructions"));
//ingredients
//image
recipeLiveData.setValue(arrayList);
}
public MutableLiveData<ArrayList<Recipe>> getRecipeLiveData() {
return recipeLiveData;
}
}
I get a 'variable is never used' with title, instructions and removeAbles
Related
Hey why are Firebase Logs telling me that following data is undefined:
In unity i have following class:
public class Question
{
private string question;
private string answerA;
private string answerB;
private string answerC;
private string answerD;
private string rightAnswer;
public Question(string question, string answerA, string answerB, string answerC, string answerD, string rightAnswer)
{
this.question = question;
this.answerA = answerA;
this.answerB = answerB;
this.answerC = answerC;
this.answerD = answerD;
this.rightAnswer = rightAnswer;
}
}
When i click a button i create a object of Question and transform it into a JSON:
submitButton.onClick.AddListener(() =>
{
Question myQuestion = new Question(questionField.text, answerAField.text,
answerBField.text, answerCField.text, answerDField.text, rightAnswer.text);
string json = JsonUtility.ToJson(myQuestion);
firebaseManager.createQuestion(json);
});
finally i pass the JSON string to following function:
public void createQuestion(string json)
{
var function = FirebaseFunctions.DefaultInstance.GetHttpsCallable("createQuestion");
function.CallAsync(json).ContinueWithOnMainThread(task =>
{
if (task.IsCompleted)
Debug.Log("done");
});
}
My firebase function is just printing some fields of the JSON but the problem is that my firebase function says that the data is undefined:
exports.createQuestion = functions.https.onCall((data, context) => {
console.log(data.answerA);
console.log(data.answerB);
return 0;
});
When i use a Dictionary<string,object> instead of the JSON string then it is working but i wanna know why the JSON solution is not working?
SOLUTION
had to change the code on the server:
exports.createQuestion = functions.https.onCall((data, context) => {
var myObject = JSON.parse(data);
console.log(myObject.answerA);
console.log(myObject.answerB);
return 0;
});
Put this attribute on top of your data class
[System.Serializable]
Classes without that wont serialize.
Make the fields you want to serialize public, Private fields wont serialize.
[System.Serializable]
public class Question
{
public string question;
public string answerA;
public string answerB;
public string answerC;
public string answerD;
public string rightAnswer;
public Question(string question, string answerA, string answerB, string answerC, string answerD, string rightAnswer)
{
this.question = question;
this.answerA = answerA;
this.answerB = answerB;
this.answerC = answerC;
this.answerD = answerD;
this.rightAnswer = rightAnswer;
}
}
I am using the below code to receive Tweets from Twitter4j Search API in the form of JSON response. I am receiving the result in the form of List as specified in Twitter4j search API in the line
List<Status> tweets = result.getTweets();
The problem is that the tweets returned as List where one Status entry is having non-empty and non-null GeoLocation whereas another Status entry is having a null or empty GeoLocation. Since to retrieve the relevant fields from each Status entry (i.e. Tweet), I iterate over the List and call getters which is throwing me null for the Status entries where the GeoLocation field is null.
The approach I tried to follow:
I created a POJO TweetJSON_2 (defined at the bottom of the post) with the relevant fields and their getters and setters. I am using Jackson ObjectMapper to handle null values like below:
JsonGenerator generator = new JsonFactory().createGenerator(os);
generator.setPrettyPrinter(new DefaultPrettyPrinter());
TweetJSON_2 rawJSON;
ObjectMapper mapper = new ObjectMapper();
//mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
mapper.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false);
mapper.setSerializationInclusion(Include.NON_NULL);
// ... rawJSON is populated ...
mapper.writeValue(generator, rawJSON);
However, when I am trying to get the geoLocation field from Status, using the below line which is marked with **
List<Status> tweets = result.getTweets();
I am getting the Java NullPointerException as follows:
[Mon Apr 20 11:32:47 IST 2015]{"statuses":[{"retweeted_status":{"contributors":null,"text":"<my text>",**"geo":null**,"retweeted":false,"in_reply_to_screen_name":null,"truncated":false,"lang":"en","entities":{"symbols":[],"urls":[],"hashtags": ... &include_entities=1","since_id_str":"0","completed_in":0.029}}
**Exception in thread "main" java.lang.NullPointerException
at analytics.search.twitter.SearchFieldsTweetsJSON_2.main(SearchFieldsTweetsJSON_2.java:78)**
For example: If I input a json String as
String s = "{\"first\": 123, \"second\": [{\"second_first\":null, \"second_second\":null}, {\"second_third\":null}, null], \"third\": 789, \"fourth\":null}";
The output should be like
"{\"first\": 123, \"third\": 789}";
What I want, is to replace all null elements from JSONArrays and all null key-value pairs from JSONObjects no matter at whatever level they are nested in my JSON response.
Object vs Tree Model Approach
I tried the Object Model parsing mechanism which is a javax.json.stream.JsonParser.Event based method but would need multiple times of access and object replacement on the JSON String depending on at what level the null is nested making this approach very complicated. At the same time if I use Tree Model mechanism, the entire JSON response would have to be stored as a Tree which may overflow my JVM heap memory because the JSON size can be pretty large based on my query parameters. I need to find a workable solution to overcome this problem. Any suggestions on solving the above discussed problem will be highly appreciated.
The code is as follows:
public class SearchFieldsTweetsJSON_2 {
/* Searches specific fields from Tweets in JSON format */
public static void main(String[] args) throws FileNotFoundException, IOException {
if (args.length < 2) {
System.out.println("java twitter4j.examples.search.SearchTweets [query][outputJSONFile]");
System.exit(-1);
}
ConfigurationBuilder cb = new ConfigurationBuilder();
cb.setDebugEnabled(true)
.setOAuthConsumerKey("XXXXXXXXXXXXXXXXXXXXXXXXXX")
.setOAuthConsumerSecret("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
.setOAuthAccessToken("NNNNNNNNN-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
.setOAuthAccessTokenSecret("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
.setJSONStoreEnabled(true);
Twitter twitter = new TwitterFactory(cb.build()).getInstance();
try {
Query query = new Query(args[0]);
QueryResult result;
File jsonFile = new File(args[1]);
System.out.println("File Path : " + jsonFile.getAbsolutePath());
OutputStreamWriter os = new OutputStreamWriter(new FileOutputStream(jsonFile));
JsonGenerator generator = new JsonFactory().createGenerator(os);
generator.setPrettyPrinter(new DefaultPrettyPrinter());
TweetJSON_2 rawJSON;
ObjectMapper mapper = new ObjectMapper();
//mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
mapper.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false);
mapper.setSerializationInclusion(Include.NON_NULL);
do {
result = twitter.search(query);
List<Status> tweets = result.getTweets();
for (Status tweet : tweets) {
rawJSON = new TweetJSON_2();
rawJSON.setStatusId(Long.toString(tweet.getId()));
rawJSON.setUserId(Long.toString(tweet.getUser().getId()));
rawJSON.setUserName(tweet.getUser().getScreenName());
rawJSON.setStatusText(tweet.getText());
rawJSON.setGeoLocation(tweet.getGeoLocation().toString()); **<< Giving error at tweet.getGeoLocation() since GeoLocation is null**
mapper.writeValue(generator, rawJSON);
System.out.println(rawJSON.toString());
}
} while ((query = result.nextQuery()) != null);
generator.close();
System.out.println(os.toString());
} catch (TwitterException te) {
te.printStackTrace();
System.out.println("Failed to search tweets : " + te.getMessage());
System.exit(-1);
}
}
}
I have defined my TweetJSON_2 Java object as follows:
public class TweetJSON_2 {
public String statusId;
public String statusText;
public String userId;
public String userName;
public String geoLocation;
public String getStatusId() {
return statusId;
}
public void setStatusId(String statusId) {
this.statusId = statusId;
}
public String getStatusText() {
return statusText;
}
public void setStatusText(String statusText) {
this.statusText = statusText;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getGeoLocation() {
return geoLocation;
}
public void setGeoLocation(String geoLocation) {
this.geoLocation = geoLocation;
}
#Override
public String toString() {
return "TweetJSON_2 [ statusId = " + statusId + ", statusText = " + statusText + "]";
}
}
I have tried with reconfiguring my POJO in the below way and it successfully replaced all the nulls as specified in the setter methods. Didn't need to follow either Tree or Event-based model parsing of JSON string. HTH
The modified TweetJSON_2 POJO:
public class TweetJSON_2 {
public Long statusId = null;
public String statusText = null;
public Long userId = null;
public String userName = null;
public GeoLocation geoLocation = null;
public Long getStatusId() {
if (this.statusId==null)
return new Long(0L);
return statusId;
}
public void setStatusId(Long statusId) {
if (statusId==null)
this.statusId = new Long(0L);
else
this.statusId = statusId;
}
public String getStatusText() {
if (this.statusText==null)
return new String("");
return statusText;
}
public void setStatusText(String statusText) {
if (statusText==null)
this.statusText = new String("");
else
this.statusText = statusText;
}
public Long getUserId() {
if (this.userId==null)
return new Long(0L);
return userId;
}
public void setUserId(Long userId) {
if (userId==null)
this.userId = new Long(0L);
else
this.userId = userId;
}
public String getUserName() {
if (this.userName==null)
return new String("");
return userName;
}
public void setUserName(String userName) {
if (userName==null)
this.userName = new String("");
else
this.userName = userName;
}
public GeoLocation getGeoLocation() {
if (this.geoLocation==null)
return new GeoLocation(0.0,0.0);
return geoLocation;
}
public void setGeoLocation(GeoLocation geoLocation) {
if (geoLocation==null)
this.geoLocation = new GeoLocation(0.0,0.0);
else
this.geoLocation = geoLocation;
}
#Override
public String toString() {
return "TweetJSON_2 [ statusId = " + statusId + ", statusText = " + statusText + "]";
}
}
I've created a set of classes (pojos) that need to be transformed into json. because i have a constraint that json field names adhere to a certain format, i've settled on gson as my library of choice, as it allows for annotations of field names.
so, i have json field names like asset_type, preview_image_thumbnail, etc. along with that, any metadata fields must have the format, metadata:<metadata-field-name>.
so, what this comes down to is that my metadata:tags and metadata:site annotations will not be transformed by gson, since they are not valid json field names, according to gson, at least.
all works well, except for those darned metadata field names. my goal is to have output like the following:
{
"name": "Test Remote Asset",
"description": "test-remote-asset",
"asset_type": "remote_asset",
"duration": 172360,
"stream_urls": {
"flash": "http://www.test-site.com/videos/a-video.flv",
"iphone": "http://www.test-site.com/videos/a-video.3gp",
"ipad": "http://www.test-site.com/videos/a-video.3gp",
"source_file": "http://www.test-site.com/videos/a-video.mp4"
},
"metadata:tags": "tag1,tag2,tag3",
"metadata:site": "test-site"
}
here is the exception i get when attempting to transform my class to json:
java.lang.IllegalArgumentException: metadata:tags is not a valid JSON field name.
and here is the class i want to transform:
public class RemoteAsset {
/** The video's name **/
private String name;
/** The video's description **/
private String description;
/** The video asset type **/
#SerializedName("asset_type")
private String assetType;
/** The video's duration, in milliseconds **/
private long duration;
/** The video's thumbnail preview URL **/
#SerializedName("preview_image_url")
private String previewImageUrl;
/** The video's OpenCms Structure ID **/
#SerializedName("external_id")
private String externalId;
/** The video's various streaming URLs **/
#SerializedName("stream_urls")
private StreamUrls streamUrls;
/** The video's tags, coma-separated **/
#SerializedName("metadata:tags")
private String metadataTags;
/** The video's host site **/
#SerializedName("metadata:site")
private String metadataSite;
public String getMetadataTags() {
return metadataTags;
}
public void setMetadataTags(String metadata_tags) {
this.metadataTags = metadata_tags;
}
public String getMetadataSite() {
return metadataSite;
}
public void setMetadataSite(String metadata_site) {
this.metadataSite = metadata_site;
}
public RemoteAsset() {
this.streamUrls = null;
this.assetType = null;
this.previewImageUrl = "";
this.metadataSite = "";
this.metadataTags = "";
this.externalId = "";
this.description = "";
this.duration = 0L;
this.name = "";
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return this.description;
}
public void setDescription(String description) {
this.description = description;
}
public String getAssetType() {
return this.assetType;
}
public void setAssetType(ASSET_TYPE asset_type) {
this.assetType = asset_type.getTypeName();
}
public long getDuration() {
return this.duration;
}
public void setDuration(long duration) {
this.duration = duration;
}
public String getPreviewImageUrl() {
return this.previewImageUrl;
}
public void setPreviewImageUrl(String preview_image_url) {
this.previewImageUrl = preview_image_url;
}
public String getExternalId() {
return this.externalId;
}
public void setExternalId(String external_id) {
this.externalId = external_id;
}
public StreamUrls getStreamUrls() {
return this.streamUrls;
}
public void setStreamUrls(StreamUrls stream_urls) {
this.streamUrls = stream_urls;
}
#Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("RemoteAsset [name=").append(this.name)
.append(", description=").append(this.description)
.append(", assetType=").append(this.assetType)
.append(", duration=").append(this.duration)
.append(", previewImageUrl=").append(this.previewImageUrl)
.append(", externalId=").append(this.externalId)
.append(", streamUrls=").append(this.streamUrls).append("]");
return builder.toString();
}
}
The problem is that those can't be mapped directly to Java variables because you can't have a colon in a variable name. You need to use the Gson #SerializedName annotation. The following works at least in Gson version 2.2.2:
public static void main( String[] args )
{
String json = "{\"some:field\":\"foo\"}";
Gson gson = new Gson();
MyClass mc = gson.fromJson(json, MyClass.class);
json = gson.toJson(mc);
System.out.println(json);
}
class MyClass
{
// String some:field; <- You can do that!
#SerializedName("some:field")
String someField;
}
Output:
{"some:field":"foo"}
Following is the response in Json i am getting after making get request to Http API Format,
[{"name":"test","tracing":false},{"name":"dyn1","tracing":false},
{"name":"dyn2","tracing":false},{"name":"esb","tracing":false}]
Could you please post a sample code to parse this json object to get individual Host object with name and tracing.
Thanks,
Amol
String myDataAsAString = "[{\"name\":\"test\",\"tracing\":false},{\"name\":\"dyn1\",\"tracing\":false},
{\"name\":\"dyn2\",\"tracing\":false},{\"name\":\"esb\",\"tracing\":false}]";
JSONArray hostArray = JSONArray.fromObject(myDataAsAString);
for(int i = 0; i < hostArray.size(); i++)
{
JSONObject hostObject = hostArray.getJSONObject(i);
String hostName = hostObject.getString("name");
boolean tracing = hostObject.getBoolean("tracing");
...your code for each element here
}
You can yse GSON library http://code.google.com/p/google-gson/
Try:
import com.google.gson.Gson;
public class Test {
public static void main(String[] args){
String json = "[{'name':'test','tracing':false},{'name':'dyn1','tracing':false},\n" +
"{'name':'dyn2','tracing':false},{'name':'esb','tracing':false}]";
HostObj[] hostObjects = new Gson().fromJson(json, HostObj[].class);
}
class HostObj {
private String name;
private boolean tracing;
HostObj() {
}
public String getName() {
return name;
}
public void setName(String name) {
name = name;
}
public boolean isTracing() {
return tracing;
}
public void setTracing(boolean tracing) {
tracing = tracing;
}
}
}
Is it possible to serialize an object using toJson(object) and have the toJson-parser ignore certain methods?
We have a method in a User class (getSocial - which is concerned with Facebook integration) that makes the toJson()-parsing fail - and we'd like it go ignore that method when serializing if possible.
Can this be done?
You can just iterate the object and rewrite it to Map or List with specified values only.
Note that if you are choosing your objects with Ebean it fetches whole object, also data, which shouldn't be fetched (as password or other credentials)
use fastjson & PropertyFilter:
Sample Code
import com.alibaba.fastjson.serializer.JSONSerializer;
import com.alibaba.fastjson.serializer.PropertyFilter;
import com.alibaba.fastjson.serializer.SerializeWriter;
PropertyFilter filter = new PropertyFilter() {
public boolean apply(Object source, String name, Object value) {
return false;
}
};
SerializeWriter out = new SerializeWriter();
JSONSerializer serializer = new JSONSerializer(out);
serializer.getPropertyFilters().add(filter);
A a = new A();
serializer.write(a);
String text = out.toString();
Assert.assertEquals("{}", text);
PropertyFilter
PropertyFilter filter = new PropertyFilter() {
public boolean apply(Object source, String name, Object value) {
if("name".equals(name)) {
return true;
}
return false;
}
};
SerializeWriter out = new SerializeWriter();
JSONSerializer serializer = new JSONSerializer(out);
serializer.getPropertyFilters().add(filter);
A a = new A();
a.setName("chennp2008");
serializer.write(a);
String text = out.toString();
Assert.assertEquals("{\"name\":\"chennp2008\"}", text);
ValueObject:
public static class A {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}