I push data to Firebase using Order object, the question is I want the first letter of every child name capital. I defined the property like "Complain" but in Firebase it still shows as "complain", I dont know how to make it.
The current structure of the Firebase:
The structure I want:
I defined the property like this:
#Data
public class Order implements Serializable {
#SerializedName("Complain")
private String Complain;
public Order() {
Complain = "";
}
public String getComplain() {
return Complain;
}
public void setComplain(String complain) {
Complain = complain;
}
}
I push data to Firebase like this:
Map<String, Object> map = new HashMap<>();
map.put(orderSavePath, order);
reference.updateChildren(map).addOnCompleteListener(listener);
The Firebase JSON serialization name is controlled by the annotation PropertyName.
public class Order implements Serializable {
private String Complain;
public Order() {
Complain = "";
}
#PropertyName("Complain")
public String getComplain() {
return Complain;
}
#PropertyName("Complain")
public void setComplain(String complain) {
Complain = complain;
}
}
The annotation needs to be on both the getter and the setter. Alternatively you can just use public fields and reduce the class to:
public class Order {
#PropertyName("Complain")
public String Complain;
}
Related
Hi I would like to register the name and surname of the users in the database as an example using a model. The data is stored in the database, but does not send the names I use in the model as child names. Instead, it saves "a, b, c, d ..." What is the reason of this?
Created database:
"-LMqLmS09gGKjR-s9CML" : {
"a" : "Robin",
"b" : "Hood"
}
The database I want to create:
"-LMqLmS09gGKjR-s9CML" : {
"firstname" : "Robin",
"lastname" : "Hood"
}
User.java (Model):
public class User {
public String fistname;
public String lastnname;
public User(String fistname, String lastnname) {
this.fistname = fistname;
this.lastnname = lastnname;
}
public String getFistname() {
return fistname;
}
public void setFistname(String fistname) {
this.fistname = fistname;
}
public String getLastnname() {
return lastnname;
}
public void setLastnname(String lastnname) {
this.lastnname = lastnname;
}
}
MainActivity.java:
public class MainActivity extends AppCompatActivity {
String firstname="Robin";
String lastname="Hood";
private DatabaseReference mDatabase;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FirebaseApp.initializeApp(this);
mDatabase = FirebaseDatabase.getInstance().getReference();
String key = mDatabase.push().getKey();
User users = new User(firstname,lastname);
mDatabase.child(key).setValue(users);
}
}
I finally found the answer. It's because I used proguard for security. Proguard shuffles the code you type so that other people cannot see the code after creating the .APK. Firebase was automatically classified because it also confused the names of the child. I solved the problem by leaving the model classes out of the proguard.
Android Firebase stores custom object members with alphabet keys (e.g. "a", "b", "c") only when installed via a release apk
Hi all I can't think of a better example to illustrate my point so do let me know If my example has some errors. But hopefully this example will get my point through.
class A {
String CATEGORY = "A";
public String getCATEGORY() {
return CATEGORY;
}
}
class B extends A {
String CATEGORY = "B";
#Override
public String getCATEGORY() {
return CATEGORY;
}
}
class C extends A {
String CATEGORY = "C";
#Override
public String getCATEGORY() {
return CATEGORY;
}
}
public class MyClass {
private List<A> array = Arrays.asList(new A(), new B(), new C());
public MyClass() {}
}
Now if I upload MyClass onto firebase using setValue for example, firebase will show me the properties of class A, B and C. However, when I read the data from firebase and call sth like getValue(MyClass.class) the List it returns me are all of type A and the subclasses are not preserved. Is there a workaround to allow firebase to preserve the class types uploaded?
If you use Firebase's default serializer, it simply writes all public properties and fields to the database. Say that you store a single instance of each class, it'd be:
-L1234567890: {
cATEGORY: "A"
},
-L1234567891: {
cATEGORY: "B"
},
-L1234567892: {
cATEGORY: "C"
},
There won't be enough knowledge in the database for the SDK to reinflate the correct sub-class. While you and I can see that the cATEGORY value matches the class name, the Firebase SDK has no such knowledge.
It won't be too hard to write your own custom deserializer for this data though, taking a DataSnapshot with the values above and reinflating the correct class and values.
You could also do a hybrid: detect the class type directly, and then tell Firebase what class to read:
String cat = snapshot.child("cATEGORY").getValue(String.class)
Class clazz = "C".equals(cat) ? C.class : "B".equals(cat) ? B.class : A.clas;
A object = snapshot.getValue(clazz);
I created an object to send some data to firebase. As an example, I use firebase user example:
public class User {
public String username;
public String email;
public User() {
// Default constructor required for calls to DataSnapshot.getValue(User.class)
}
public User(String username, String email) {
this.username = username;
this.email = email;
}
}
I want to encode property names that are sent to firebase. Currently keys are sent using variable names. I want to encode keys something like Useraname and Email, like Gson is doing. I don't want to change variable names.
#SerializateName("Username")
public String username;
#SerializateName("Username")
public String email;
I used #SerializateName(), but is not working. Same with #PropertyName that is used by Firebse, is not working. What I can use in order to serializare custom keys?
Update 1
public class Pojo {
#PropertyName("Guid")
public String guid;
#PropertyName("Name")
public String name;
public String getPojoGuid() {
return guid;
}
public void setPojoGuid(String guid) {
this.guid = guid;
}
}
As you can see in the image, it saves keys based on variable names. I changed property name from annotation for one field and when i save it, it ignores it, but when i change variable name, it save as new entry with key for that new varialbe name.
In this documentation is a method toMap(). If i do like that, is working (is not convenient for me), but is not working with #PropertyName.
Update 2
If i mark getters and setters with #Exclude and class with #IgnoreExtraProperties is working. I don't have to use toMap() method example from documetation. Is using specified name from #PropertyName. Not a good thing in my opinion, create confuses.
The Firebase SDK uses the annotation it finds for the property whenever it gets or sets its value. That means you need to consider how Firebase gets/sets the value, and annotate each place it looks.
Since you're declaring a getter method, Firebase will use that to get the value of the property. It will use the field for setting the value. So the annotation needs to be on both:
public class Pojo {
#PropertyName("Guid")
public String guid;
#PropertyName("Name")
public String name;
#PropertyName("Guid")
public String getPojoGuid() {
return guid;
}
#PropertyName("Guid")
public void setPojoGuid(String guid) {
this.guid = guid;
}
}
If you'd have getters and setters, the annotation would need to be on those, but not on the fields anymore:
public class Pojo {
private String guid;
private String name;
#PropertyName("Guid")
public String getPojoGuid() {
return guid;
}
#PropertyName("Guid")
public void setPojoGuid(String value) {
guid = value;
}
#PropertyName("Name")
public void setPojoGuid(String guid) {
this.guid = guid;
}
#PropertyName("Name")
public void setPojoGuid(String value) {
name = value;
}
}
What you are looking for is the feature of SDK Version 9.2 in which you can now use a new #PropertyName attribute to specify the name to use when serializing a field from a Java model class to the database. This replaces the #JsonProperty attribute.
#PropertyName("Username")
public String username;
#PropertyName("Email")
public String email;
See also this post in which Frank van Puffelen explains very clearly this concept.
#PropertyName :
Marks a field to be renamed when serialized. link
you have to use #PropertyName with public fields and no need for getters/setters
I have a model class to store Firebase User information. Inside of the model class I have a HashMap to store all of the data inside. Once I have stored the data, the I push the Hashmap into the Firebase database. The values store fine, but I cannot access the values. Every time I try to access them, I get an error saying that I am attempting to invoke a virtual method on a null object reference.
mDatabase.child("users").child(mUserId).addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot ChildSnapshot, String s) {
// These two lines of code give the error.
User author = ChildSnapshot.child("profile").getValue(User.class);
String author_username = author.getUsername();
These give me the error. I am attempting to grab data from the child of the snapshot. Why is this giving me an error? Is there a better way to do this?
JSON Firebase snapshot:
Model class:
//TODO model class for the user. This way I can set the values for each user. I will be adding more values in the future.
public class User {
public HashMap<String, String> hashMap = new HashMap<String,String>();
public User() {
}
public User(String username) {
hashMap.put("username",username);
}
public String getUsername(){
return hashMap.get("username");
}
}
In case somebody else was struggling with this issue, I wanted to give an answer. Inside of my ChildEventListener, the profile is the key in this situation so when I use ChildSnapshot.child("profile").getValue(User.class) it returns a null value. Also, (I'm not quite sure why this is) the value of the username was stored in a different class called User_message which was used to store the message. so my updated code looks something like this:
mDatabase.child("users").child(mUserId).addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot ChildSnapshot, String s) {
User_message author = ChildSnapshot.getValue(User_message.class);
String author_username = author.getUsername();
I was facing the same problem and spent more than 5 hours. I added Default Constructor of the model and this solves my problem.
public class User {
public String email;
public String name;
public User() {
}
public User(String email, String name) {
this.email = email;
this.name = name;
}}
I hope this will help you. Thanks
I'm using rushorm for sqlite object serializing and storage. It work pretty cool so far. The problem is that I wan't to store following Request object:
public class Request extends RushObject {
private String url;
private RequestParamsStorable params;
public Request() {}
public Request(String aUrl, RequestParamsStorable aParams)
{
this.url = aUrl;
this.params = aParams;
}
public String getUrl()
{
return this.url;
}
public RequestParams getParams()
{
return this.params;
}
}
As you can see I need to store RequestParams object. In order to store it, as I obviously cannot make it to extend RushObject I made a subclass and made it to implement Rush as per docs instructions:
public class RequestParamsStorable extends RequestParams implements Rush {
public RequestParamsStorable() {}
#Override
public void save() { RushCore.getInstance().save(this); }
#Override
public void save(RushCallback callback) { RushCore.getInstance().save(this, callback); }
#Override
public void delete() { RushCore.getInstance().delete(this); }
#Override
public void delete(RushCallback callback) { RushCore.getInstance().delete(this, callback); }
#Override
public String getId() { return RushCore.getInstance().getId(this); }
}
It didn't throw any errors and calling save() on Request object went smoothly. When I ask for stored objects like that:
List<Request> remainingsInDB = new RushSearch().find(Request.class);
I indeed receive stored Request objects, with proper url, however RequestParamsStorable is empty(""). I checked and when I save them, they definetely had values, and are not empty.
So the question is where I'm wrong?
Regards,
If your parent class RequestParams contains fields declared as final, they will not be restored.
As reference you can see the RushORM source code
ReflectionClassLoader.java
for (Field field : fields) {
field.setAccessible(true);
if (!annotationCache.get(clazz).getFieldToIgnore().contains(field.getName())) {
if (!loadJoinField(object, rushColumns, annotationCache, field, joins, joinTables)) {
if(rushColumns.supportsField(field)) {
String value = values.get(counter);
if(value != null && !value.equals("null")) {
rushColumns.setField(object, field, value);
}
counter++;
}
}
}
}
You should either remove final modifier of the fields or create wrapper object which will be stored in the db and then restore RequestParams from it
Okay the problem indeed is fields declared as final in RequestParams. #Stuart Campbell properly noted RequestParams reference. Now what I'm trying as a workaround is to store all properties(except Wrappers) as JSONObject, store this JSONObject as String and then restore state from it. I'm facing some issues with JsonWritter and didn't solved my issue yet. Not sure if it is a good idea to post relevant code here, or to post new question though?