How can I write a JSONObject to a firebase database node - java

I am currently trying to migrate an app to firebase from a SQLDatabase. I have done all the work to convert the database to a JSONObject. Is there a way I can just fill a user node in firebase with this object?
I tried to write the JSONObject with
database.getReference("/" + user.getUid() + "/").setValue(jsonObject);
this returns the error
com.google.firebase.database.DatabaseException: No properties to serialize found on class org.json.JSONObject
I'm trying to avoid breaking apart the object and posting individual values seperatly because this could be error prone and I can't risk corrupting data with a messed up loop... Thanks for any help.

You can convert the json into an object using ObjectMapper:
ObjectMapper mapper = new ObjectMapper();
User user = mapper.readValue(jsonObject.toString(), User.class);
https://fasterxml.github.io/jackson-databind/javadoc/2.7/com/fasterxml/jackson/databind/ObjectMapper.html
Then you can use the instance of the class User in setValue():
database.getReference("/" + user.getUid() + "/").setValue(user);
From the docs:
In addition, you can set instances of your own class into this location, provided they satisfy the following constraints:
The class must have a default constructor that takes no arguments
The class must define public getters for the properties to be assigned. Properties without a public getter will be set to their default value when an instance is deserialized

Related

Getting "declares multiple JSON fields named" error when serializing with GSON

Type type = new TypeToken<HashMap<String , MovieDb>>() {}.getType();
gson.fromJson(json, type); //ERROR HERE !!!
When I convert from Json to the hashmap object it works fine without minifying enabled. But when minify is enabled it gives me the following error at this line:
java.lang.IllegalArgumentException: class a.a.a.a.b declares multiple JSON fields named a
at com.google.b.b.a.i.a(ReflectiveTypeAdapterFactory.java:172)
at com.google.b.b.a.i.a(ReflectiveTypeAdapterFactory.java:102)
at com.google.b.e.a(Gson.java:458)
at com.google.b.b.a.b.a(CollectionTypeAdapterFactory.java:53)
at com.google.b.e.a(Gson.java:458)
at com.google.b.b.a.i.a(ReflectiveTypeAdapterFactory.java:117)
at com.google.b.b.a.i.a(ReflectiveTypeAdapterFactory.java:166)
at com.google.b.b.a.i.a(ReflectiveTypeAdapterFactory.java:102)
at com.google.b.e.a(Gson.java:458)
at com.google.b.b.a.g.a(MapTypeAdapterFactory.java:126)
at com.google.b.e.a(Gson.java:458)
at com.google.b.e.a(Gson.java:926)
at com.google.b.e.a(Gson.java:892)
at com.google.b.e.a(Gson.java:841)
at com.techy.nateshmbhat.moviego.i.onPreExecute(MovieInterface.java:180)
at android.os.AsyncTask.executeOnExecutor(AsyncTask.java:648)
at android.os.AsyncTask.execute(AsyncTask.java:595)
at com.techy.nateshmbhat.moviego.i.b(MovieInterface.java:101)
at com.techy.nateshmbhat.moviego.a.a(Activity_InTheaterMovies.java:55)
Your error is most propably because you minify two fields to a same name a. Something like:
#SerializedName("a")
Long veryLongFieldName;
#SerializedName("a")
Long anotherVeryLongFieldName;
Note that these can be either in the same class or if using inheritance it is enough that they are in the same inheritance tree. Gson can not assign two values to one minimized field name a.
It could of course also be that you have minimized some field to a name that is already reserved by some other unminimized field.
I've faced this issue when I had context property/variable in the model class

Bind JSON response with dynamic keys to Java object

I have a json response coming from MongoDB and in its current form I have a pojo like below to bind these month field values:-
#JsonProperty("Feb-2017")
private Float feb2017;
The problem is that these month names change with time and those values will no longer be bound to the java object.The POJO in turn is an attribute of two other objects that represent this json. I cannot change the json structure in the Db and have tried creating this pojo at runtime following this answer but I cannot figure out how to reference this object across other POJOs .
Is there any other way I could approach this problem?
Thanks.
In your POJO, add a class member as follows:
private Map<String, Object> months = new HashMap<>();
Then create a method annotated with #JsonAnySetter:
#JsonAnySetter
public void set(String key, Object value) {
months.put(key, value);
}
This method works as a fallback handler for all unrecognized properties found in the JSON document.

Backward compatibility with JSON

I have a java application which saves the fields of an object to a file and load them later again.
I used so far a modified version of java.util.properties.Properties file (the properties were written in the order they were put in the properties object). I defined for each field a property-key and use the following function to set the property in the properties object
properties.setProperty(PROPERTY_KEY_FIELD_X, field_x);
and used the following function if I want to read back from the properties file
field_x = properties.getProperty(PROPERTY_KEY_FIELD_X, ""));
where I can add a default value which will be choosed, when there is no property with the specified key. As I maybe add some fields in the future in the class from which the fields were saved in the file, I used this option with the default value to set a field to some defined value for the case I load a properties file which was written with an older version of this class.
So far it works but with some obvious disadvantage, for example I can't use the same property key more than once, I have to add some kind of indices like 1_PROPERTY_KEY, 2_PROPERTY_KEY. Thats why I came across JSON.
I'm not very familiar with JSON and all the things we can achieve with it. But I know I could use it to save the fields of an object to the JSON notation and read it back for example with Gson
//Object to JSON
Gson gson = new Gson();
String json = gson.toJson(object);
//JSON to Object
object = gson.fromJson(json);
But I assume this will fail, if the class is a newer version (i.e. some new fields) when try to read back from the JSON. How can I treat this? Do I have to take care of every seperate field similar to the the current implementation with properties? For example like this (with com.google.gson), assuming jsonString is the string read from the file:
//try/catch block omitted
JSONParser parser = new JSONParser();
JSONElement json = parser.parse(jsonString);
field_x = json.getAsString("field_x");
and take care if something failed to set default values to the fields?
Or is there a completely different approach without JSON or is JSON in general suitable for my use-case?
I'm not an expert of JSON too. But I used it sometimes with Jackson and I think Gson is very similar. If you want to use versioned objects just assure in your object constructor that fields are given with a default value (outside correct values range). Jackson will match only those json fields where it finds a correspondent filed in th Java object. Otherwise the default value is kept.
With GSON, you get to define your model as an object. As an example:
public class Configuration
{
private String x;
private String y;
}
Later, you may adjust Configuration to have an additional field, z:
public class Configuration
{
private String x;
private String y;
private String z;
}
When you use GSON to deserialise your JSON file that does not contain a value for z, it will be left null (or whatever the Java default value for that type is).
Since you have an object, you can define getters that substitute a default value if one is not specified:
public String getZ()
{
if (this.z == null)
{
return "the default z value";
}
return this.z;
}
If you're not goind to send data across network, I think you don't need Json but use native Java classes (ie properties). It's reduntant object creation

Gson fromJson returning empty JsonObject

So, I've got a String that is the result of a toJson method I've implemented on a class, and have confirmed in my test code that it is the correct Json representation of my class. My goal is to turn this String into a JsonObject and pass it to a constructor, using Gson. However, I'm running into an odd problem.
This is the code I'm calling:
Gson gson = new Gson();
JsonObject jObj = gson.fromJson(jsonString, JsonObject.class);
I have used literally this exact same snippet of code before in many places in my project, for other classes, and it has worked fine. I even copied one of those functional snippets of code into this test class and tried it. However, every version I try results in the same thing--jObj is an empty set of brackets.
I don't understand how it's happening. I've confirmed that jsonString has all the fields it should need. Why is Gson returning an empty JsonObject? No exceptions are being thrown.
Ok so i know this is a little old but I had the same exact issue. The resolution was changing the jar file. I had a similar code sample working in another project but then I was experiencing the exact same problem in another. Well the problem was an older gson-2.1.jar. Updated the problem application to the matching gson-2.3.1.jar and all was working. Hope this helps.
From your comment that says the string is {"varName":1, "otherVarName":2, "thirdVarName":3.4}, looks like the serialized object was a Map. You may need to specify the type token:
gson.fromJson(jsonString, new TypeToken<Map<K,V>>() {}.getType());
where K and V are the key and value types of the map. If it is not a Map, specify whatever class the jsonString was obtained from.
For my case, I was accidentally using the following initializer in my dagger module.
Gson gson = new GsonBuilder()
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.create()
I removed the setFieldNamingPolicy and it worked.
I had this issue as well.
I was using
return gson.fromJson(response, JsonObject::class.java)
And I was receiving an object with only the default values populated.
I had to explicitly define the serialized names for each property in my JsonObject class that was different from how it was named in the json response.
For example, if in the json I was parsing the field name was "total_score', but my JsonObject had a field named "totalProperty", I had to use the #SerialedName annotation to define the relationship.
#SerializedName("total_score")
val TotalScore : Int = 0

Sending a variable to the Mapper Class

I am trying to get an input from the user and pass it to my mapper class that I have created but whenever the value always initialises to zero instead of using the actual value the user input.
How can make sure that whenever I get the variable it always maintain the same value. I have noticed that job1.setMapperClass(Parallel_for.class); creates an instance of the class hence forcing the variable to reinitialize to its original value. Below is the link to the two classes. I am trying to get the value of times from RunnerTool class.
Link to Java TestFor class
Link to RunnerTool class
// setup method in the Mapper
#Override
public void setup(Context context) {
int defaultValue = 1;
times = context.getConfiguration().getInt("parallel_for_iteration", defaultValue );
LOG.info(context.getConfiguration().get("parallel_for_iteration") + " Actually name from the commandline");
LOG.info(times + " Actually number of iteration from the commandline");
}
// RunnerTools class
conf.setInt(ITERATION, times);
You should note that mapper class will be recreated on many cluster nodes so any initalization done to the instance of the mapper class when running the job will not affect other nodes. Technically relevant jar file/s will be distributed among nodes and then mappers will be created there.
So as pointed in the answer above, the only way to pass information to the mappers is using Configuration class.
Mapper get's initialized by reflection, so you can not let the user interact with the mapper class.
Instead you have your Configuration object, which you have to provide if you're setting up your job. There you can set this using conf.set("YOUR KEY", "YOUR VALUE"). In your Mapper class you can override a method called setup(Context context), there you can get the value using context.getConfiguration().get("YOUR KEY"). And maybe save to your mapper local variable.

Categories