GSON : Custom serialization for String - android

public class Data{
public String str; //String (that may contain line breaks) I need to serialize as it is.
}
Why I needed custom Serializer for string?
Without custom serializer it serializes this as object {"str":{"count": 292,"hashCode": 0} }
I need it to be {"str":"..............."}
How to do it with custom Serializer?
There are example of custom serializer for custom types, but could not find anything that helps to serialize String type.

Well, Gson supports strings out of box and you don't have to implement any string serializer and vice versa yourself. What I guess might happen to your case is merely importing a wrong string class, say import foo.bar.baz.String; or less obvious import foo.bar.baz.*, or you just have a String class implementation right in the package where your Data class is declared in. (This cannot explain what values were really assigned to str, though, -- it would never work in Java causing ClassCastException). A wrong class might be indicated with numeric count and hashCode without any char[]-declared fields, so I don't believe this is a java.lang.String in your case. Also, a more hypothetical thing here might be use of reflection that discarded the string type adapter out of your Gson instance, no matter how and how weird it sounds. In any case, you don't have to implement even a single line to serialize Java strings with Gson.
Regarding the accepted answer: it is suboptimal. If, for whatever reason, there is nothing wrong with your imports, your package does not declare a custom String class, and your Gson instances do not suffer from reflection surgery, but Gson still serializes such strings as nested objects (have no ideas why then), you'd only need a single special String type adapter without any need of creating type adapters for any class that uses that weird String as a field:
final Gson gson = new GsonBuilder()
.registerTypeAdapter(/*real.package.here.*/String.class, (JsonSerializer</*real.package.here.*/String>) (s, type, context) -> new JsonPrimitive(s.toString())) // whatever the real Java string is obtained
.create();

Try this
public class DataSerializer implements JsonSerializer<Data> {
#Override
public JsonElement serialize(Data data, Type typeOfSrc, JsonSerializationContext context) {
JsonObject object = new JsonObject();
object.addProperty("src", data.src);
return object;
}
}
Add this to Gson Like this
Gson gson = new GsonBuilder()
.registerTypeAdapter(Data.class, new DataSerializer())
.create();

Related

How to save Abstract object to Shared Preferences Android

I want to save abstract object to shared preferences.I get data with String from Shared preferences and when bind it to an Abstract class, I get some errors like that
"Caused by: java.lang.InstantiationException: Can't instantiate abstract class"
How to get abstract object from shared preferences?
Thanks
First of all, you cannot create an intance from an abstract class in java. You need to make something like this
public MyRealClass extends MyAbstractClass{
}
Your IDE should now tell you that you need to implement the needed methods from the abstract class.
You can now save the instance of MyRealClass to the SharedPreferences but only if you make it serializable or make the object to a JSON String. This can be done using libraries like GSON.
It is not possible to save an object to the SharedPrefs directly.
GSON will take your instance and transforms it into a string. This string can be saved and later if you need the object again you can give the string to GSON and it will transform it back into the object. The used representation is called JSON, which is a standard format (https://en.wikipedia.org/wiki/JSON)
To save
Gson gson = new Gson();
String json = gson.toJson(myRealClassInstance);
prefsEditor.putString("myobj", json);
prefsEditor.commit();
for later loading
Gson gson = new Gson();
String json = mPrefs.getString("myobj", "");
MyRealClass obj = gson.fromJson(json, MyRealClass.class);
For your Error: You can't create object of abstract class, you have to inherit abstract class to some class then only you can make an object to it.
Another one is, You can't store the object in shared preference. You can only store String, Integer, Boolean, Float, Long, and StringSet.
More info here.https://developer.android.com/reference/android/content/SharedPreferences.html

Realm with Gson alternative to ExclusionStrategy and custom typeadapters

So, I stated using Realm and encountered this known issue when combining it with Gson.
I started seeing some strange serialized outputs that were breaking the logic of my Rest API.
I have found that setting an ExclusionStrategy and writing custom serializers to each of my models will fix it. See this link.
But I have more than 20 models that are more likely to be changed in the future. So sticking to this workaround means that I will have to change the serializers every time I change the models and this seems to break this simplicity I thought I would have by using Realm and Gson together.
My question is: Is there another known workaround to bypass these limitation? Or It is the only choice I have?
Yes. Use the ExclusionStrategy, and use realm.copyFromRealm(managedRealmObject); before passing it to GSON.
ExclusionStrategy exclusionStrategy = new ExclusionStrategy() {
#Override
public boolean shouldSkipField(FieldAttributes f) {
return f.getDeclaringClass().equals(RealmObject.class);
}
#Override
public boolean shouldSkipClass(Class<?> clazz) {
return false;
}
};
Gson gson = new GsonBuilder()
.setExclusionStrategies(exclusionStrategy)
.create();
String json = gson.toJson(realm.copyFromRealm(myObject));

Practical use of #Ignore in Realm?

I've been trying to add Realm in my Android app. Their docs are pretty well explained & easy to follow. But it fails to explain this one particular area. I'm unable to figure out the practical use for the #Ignore annotation. I know that fields under this annotation are not persisted.
Can someone please share a few use cases. Also I wanted to know the scope of such fields. I mean, if I set an #Ignore field to some value, would that value be available to the other classes in my app for that particular launch session. If yes, then how do we access it? If no (which I guess is the case), then why do we need such a field anyway?
I've searched here and on web but couldn't find the relevant information. If out of my ignorance, I've missed upon some resource, please guide me to it.
Thanks.
Accordingly to the official documentation (see https://realm.io/docs/java/latest/) #Ignore is useful in two cases:
When you use GSON integration and your JSON contains more data than you want to store, but you still would like to parse it, and use right after.
You can't create custom getters and setter in classes extending RealmObject, since they are going to be overridden. But in case you want to have some custom logic anyway, ignored fields can be used as a hack to do that, because Realm doesn't override their getter & setters. Example:
package io.realm.entities;
import io.realm.RealmObject;
import io.realm.annotations.Ignore;
public class StringOnly extends RealmObject {
private String name;
#Ignore
private String kingName;
// custom setter
public void setKingName(String kingName) { setName("King " + kingName); }
// custom getter
public String getKingName() { return getName(); }
// setter and getter for 'name'
}
Ignored fields are accessible only from the object they were set in (same as with regular objects in Java).
UPDATE: As the #The-null-Pointer- pointed out in the comments the second point is out of date. Realm now allows having custom getters and setters in Realm models.
Here's a couple of real-world use cases:
1 - Get user's fullname:
public class User extends RealmObject {
private String first;
private String last;
#Ignore
private String fullName;
public String getFullName() {
return getFirst() + " " + getLast();
}
Get JSON representation of object:
public class User extends RealmObject {
private String first;
private String last;
#Ignore
private JSONObject Json;
public JSONObject getJson() {
try {
JSONObject dict = new JSONObject();
dict.put("first", getFirst());
dict.put("last", getLast());
return dict;
} catch (JSONException e) {
// log the exception
}
return null;
}
I've found it useful to define field names for when I am querying. For example
User.java
public class User extends RealmObject {
#Index
public String name;
#Ignore
public static final String NAME = "name";
}
And then later on I can do something like:
realm.where(User.class).equalTo(User.NAME, "John").findFirst();
This way if the schema changes from say name to id I don't have to hunt down every occurrence of "name".
Please see the the official documentation about #Ignore annotation:
The annotation #Ignore implies that a field should not be persisted to disk. Ignored fields are useful if your input contains more fields than your model, and you don’t wish to have many special cases for handling these unused data fields.

Android annotations REST send image

I use android annotations to communicate with the server. In one of the api calls I need to send some text data and an image, say, from gallery.
#Post("/items/addItem.php")
String addItem(Protocol protocol);
How do I attach a MultipartForm with an image along with the post request?
Just use the right Spring converter : FormHttpMessageConverter.
However, this converter only accepts MultiValueMap as method parameter. Please have a look at these two issues: #652 and #660.
If you really want to use any object as parameter, you have to implement your own custom FormHttpMessageConverter which will handle that by using reflection.
DayS is right. An as quotation, you must include the FormHttpMessageConverter in your Rest Interface definition inside the converters array:
#Rest(rootUrl = "http://api.yourapp.com", converters = {
MappingJacksonHttpMessageConverter.class,
StringHttpMessageConverter.class, FormHttpMessageConverter.class })
public interface YourAppApiClient {
#Post("/items/addItem.php")
void getCustomerInformation(MultiValueMap formfields);
}
-Totaly Agree with above answers but for use of mappinjacksonhttpmessageconverter you have to add another library so if you dnt want to use it you can use below example
Or you can consider it as another example also :)
#Rest(rootUrl = CommonUtils.BASE_URL, converters = { ByteArrayHttpMessageConverter.class,
FormHttpMessageConverter.class, StringHttpMessageConverter.class })
public interface CustomRest extends RestClientErrorHandling{
#Post(CommonUtils.pUrlLogin)
String _Login(MultiValueMap<String, Object> multiValueMap);
#Post(CommonUtils.pUrlSignUp)
String _SignUp(MultiValueMap<String, Object> multiValueMap);
}

JSONObject as class attribute storage/retrieval

In android, I'm using model classes with methods to handle the data manipulation. My data is brought in from webservices as json. I'm contemplating the possibility of using JSONObjects to store the values of class level attributes. But, I don't know of a way to use the JSONObj as the "holder" variable and create access methods. I don't want to predetermine these methods, as jsonRepository should hold the values, not always known at design time
For example, I'd like to have:
public class User {
private JSONObject jsonAttributes;
public User(String json) {
this.jsonAttributes= new JSONObject(json);
}
[IMPLICIT attribute access methods]
public string Prop1() returns jsonAttributes.getString("prop1");
public string Prop1(String newProp1) returns jsonAttributes.putString("prop1",newProp1);
public string Prop2() returns jsonRepository.getString("id");
public string Prop2(String newProp2) returns jsonAttributes.putString("prop2",newProp2);
....
from outside this class then, I would access the attributes simply...
User myUser = new User(someValidJson);
String myString = myUser.Prop1
Misguided? If not, how does one manage implicit property setting/getting?
As was mentioned in the comment above, why not create your user class, with all of the relevant memeber variables, and simply parse your JSON data in order to populate the ionformation in your user class.
There are a lot of ways you can do this, but I would consider using the builder pattern, as it is flexible, which could be useful if your JSON data changes in the future.

Categories

Resources