I consume a rest service and i get a json object , and i map json object to my java object with Gson library.
But Date Json with following format not deserialized :
"/Date(1466606168687+0430)/"
I also checked following gson object ,but json date is not deserialized yet:
Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ").create();
Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ssz").create();
Update:
My problem is time zon for deserializing json date with timezon.
finally i use this code for date deserialization :
public class JsonDateDeserializer implements com.google.gson.JsonDeserializer<Date>{
public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
String s = json.getAsJsonPrimitive().getAsString();
String s1 = s.substring(6, s.length() - 2);
String[] saa = s1.split("\\+");
long l = Long.parseLong(saa[0]);
Date d = new Date(l);
return d;
}
}
Related
I'm trying to have a custom date format in Gson output, but .setDateFormat(DateFormat.FULL) doesn't seem to work and it the same with .registerTypeAdapter(Date.class, new DateSerializer()).
It's like Gson doesn't care about the object "Date" and print it in its way.
How can I change that?
Thanks
EDIT:
#Entity
public class AdviceSheet {
public Date lastModif;
[...]
}
public void method {
Gson gson = new GsonBuilder().setDateFormat(DateFormat.LONG).create();
System.out.println(gson.toJson(adviceSheet);
}
I always use java.util.Date; setDateFormat() doesn't work :(
It seems that you need to define formats for both date and time part or use String-based formatting. For example:
Gson gson = new GsonBuilder()
.setDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz").create();
or using java.text.DateFormat
Gson gson = new GsonBuilder()
.setDateFormat(DateFormat.FULL, DateFormat.FULL).create();
or do it with serializers:
I believe that formatters cannot produce timestamps, but this serializer/deserializer-pair seems to work
JsonSerializer<Date> ser = new JsonSerializer<Date>() {
#Override
public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext
context) {
return src == null ? null : new JsonPrimitive(src.getTime());
}
};
JsonDeserializer<Date> deser = new JsonDeserializer<Date>() {
#Override
public Date deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context) throws JsonParseException {
return json == null ? null : new Date(json.getAsLong());
}
};
Gson gson = new GsonBuilder()
.registerTypeAdapter(Date.class, ser)
.registerTypeAdapter(Date.class, deser).create();
If using Java 8 or above you should use the above serializers/deserializers like so:
JsonSerializer<Date> ser = (src, typeOfSrc, context) -> src == null ? null
: new JsonPrimitive(src.getTime());
JsonDeserializer<Date> deser = (jSon, typeOfT, context) -> jSon == null ? null : new Date(jSon.getAsLong());
Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ").create();
Above format seems better to me as it has precision up to millis.
As M.L. pointed out, JsonSerializer works here. However, if you are formatting database entities, use java.sql.Date to register you serializer. Deserializer is not needed.
Gson gson = new GsonBuilder()
.registerTypeAdapter(java.sql.Date.class, ser).create();
This bug report might be related: http://code.google.com/p/google-gson/issues/detail?id=230. I use version 1.7.2 though.
In case if you hate Inner classes, by taking the advantage of functional interface you can write less code in Java 8 with a lambda expression.
JsonDeserializer<Date> dateJsonDeserializer =
(json, typeOfT, context) -> json == null ? null : new Date(json.getAsLong());
Gson gson = new GsonBuilder().registerTypeAdapter(Date.class,dateJsonDeserializer).create();
You can specify you format Gson gson = builder.setDateFormat("yyyy-MM-dd").create(); in this method instead of yyyy-MM-dd you can use anyother formats
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(Date.class, new JsonDeserializer<Date>() {
public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
return new Date(json.getAsJsonPrimitive().getAsLong());
}
});
Gson gson = builder.setDateFormat("yyyy-MM-dd").create();
This is a bug. Currently you either have to set a timeStyle as well or use one of the alternatives described in the other answers.
I'm on Gson 2.8.6 and discovered this bug today.
My approach allows all our existing clients (mobile/web/etc) to continue functioning as they were, but adds some handling for those using 24h formats and allows millis too, for good measure.
Gson rawGson = new Gson();
SimpleDateFormat fmt = new SimpleDateFormat("MMM d, yyyy HH:mm:ss")
private class DateDeserializer implements JsonDeserializer<Date> {
#Override
public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
try {
return new rawGson.fromJson(json, Date.class);
} catch (JsonSyntaxException e) {}
String timeString = json.getAsString();
log.warning("Standard date deserialization didn't work:" + timeString);
try {
return fmt.parse(timeString);
} catch (ParseException e) {}
log.warning("Parsing as json 24 didn't work:" + timeString);
return new Date(json.getAsLong());
}
}
Gson gson = new GsonBuilder()
.registerTypeAdapter(Date.class, new DateDeserializer())
.create();
I kept serialization the same as all clients understand the standard json date format.
Ordinarily, I don't think it's good practice to use try/catch blocks to govern flow control, but this should be a fairly rare case.
This won't really work at all. There is no date type in JSON. I would recommend to serialize to ISO 8601 back and forth (for format agnostics and JS compat). Consider that you have to know which fields contain dates.
Is it any way to save ArrayList to sharedpreferences? Thank you
ArrayList<Class> activityList = new ArrayList<>();
activityList.add(Level1Activity.class);
activityList.add(Level2Activity.class);
activityList.add(Level3Activity.class);
activityList.add(Level4Activity.class);
activityList.add(Level5Activity.class);
I already answered this to your other question but just in case, I'll re-write it here and explain it more a bit.
You can use Gson to convert your list into a Json String so that you can save it in SharedPreferences.
You will need to add implementation 'com.google.code.gson:gson:2.8.6' inside your app gradle dependencies to be able to use Gson.
But, you cannot simply parse the list using Gson to Json or viceversa when you use the Class class. In order to do so, you will need to create your own serializer and deserializer for it. Or you'll face this exception:
java.lang.UnsupportedOperationException: Attempted to serialize java.lang.Class: com.etc.etc.Level1Activity. Forgot to register a type adapter?
So let's create a custom adapter that implements JsonSerializer and JsonDeserializer. Don't forget to put inside the angle brackets the type we're working with, which is Class.
ClassAdapter class
public class ClassAdapter implements JsonSerializer<Class>, JsonDeserializer<Class> {
#Override
public JsonElement serialize(Class src, Type typeOfSrc, JsonSerializationContext context) {
// Get our class 'src' name
return new JsonPrimitive(src.getName());
}
#Override
public Class deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
try {
// Get class
return Class.forName(json.getAsString());
} catch (ClassNotFoundException e) {
// If class could not be found or did not exists, handle error here...
e.printStackTrace();
}
return null;
}
}
To convert our list to Json String and save it inside SharedPreferences:
// Create new GsonBuilder and register our adapter for Class objects
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Class.class, new ClassAdapter());
// Initialize our list of levels (ie. classes)
List<Class> classes = new ArrayList<>();
classes.add(Level1Activity.class);
classes.add(Level2Activity.class);
classes.add(Level3Activity.class);
classes.add(Level4Activity.class);
classes.add(Level5Activity.class);
// Create Gson from GsonBuilder and convert list to json
Gson gson = gsonBuilder.create();
String json = gson.toJson(classes);
// Save json to SharedPreferences
SharedPreferences sharedPreferences = getSharedPreferences("app_name", MODE_PRIVATE);
sharedPreferences.edit().putString("levels", json).apply();
And to retrieve the list back:
// Retrieve json from SharedPreferences
SharedPreferences sharedPreferences = getSharedPreferences("app_name", MODE_PRIVATE);
String json = sharedPreferences.getString("levels", null);
// Handle here if json doesn't exist yet
if (json == null) {
// ...
}
// Create new GsonBuilder and register our adapter for Class objects
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Class.class, new ClassAdapter());
// Create Gson from GsonBuilder and specify type of list
Gson gson = gsonBuilder.create();
Type type = new TypeToken<ArrayList<Class>>(){}.getType();
// Convert json to list
List<Class> classes = gson.fromJson(json, type);
Hope this helps, happy coding!
I need to get data from a badly designed web API which returns the list of objects in the form of JSON object:
{
"29593": { ..object to parse },
"29594": { ..object to parse },
"29600": { ..object to parse }
}
I need to create POJO for this response, but the issue is that these integers are changing, they are like object IDs. I don't know how to extract these integers from the JSON keys and then use the inner JSON objects further in another POJO class (I know basic Gson mapping when the key has a fixed value).
Is it even possible?
The solution is to use a custom JsonDeserializer from gson library, here is a example:
public class MyAwesomeDeserializer implements JsonDeserializer<MyModel> {
public MyModel deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonObject eJson = json.getAsJsonObject();
Set<String> keys = eJson.keySet();
MyModel myModel = new MyModel();
for (String key: keys) {
JsonObject asJsonObject = eJson.get(key).getAsJsonObject();
ItemOfMyModel itemOfMyModel = context.deserialize(asJsonObject, ItemOfMyModel.class);
myModel.addItemOfMyModel(itemOfMyModel);
}
return myModel;
}
}
and dont forget to add your custom deserializer as a type adapter to gson builder:
Gson gson = new GsonBuilder()
.registerTypeAdapter(MyModel.class, new MyAwesomeDeserializer())
.create()
I am trying to use Gson to deserialize a json array, but am currently getting a JsonSyntaxException. The json string was created by a .NET MVC3 web service using JsonResult (meaning, I am not manually creating the json, it is being created by a library which I know to work on several other platforms).
This is the json:
[{"PostID":1,"StudentID":39,"StudentName":"Joe Blow",
"Text":"Test message.","CreateDate":"\/Date(1350178408267)\/",
"ModDate":"\/Date(1350178408267)\/","CommentCount":0}]
This is the code:
public class Post {
public int PostID;
public int StudentID;
public String StudentName;
public String Text;
public Date CreateDate;
public Date ModDate;
public Post() { }
}
Type listOfPosts = new TypeToken<ArrayList<Post>>(){}.getType();
ArrayList<Post> posts = new Gson().fromJson(json, listOfPosts);
The exception says that the date format is invalid:
com.google.gson.JsonSyntaxException: /Date(1350178408267)/
Anyone know what is going on?
I found an answer here but I found it strange that there isn't an easier way. Several other json libraries I've used support the .NET json format natively. I was surprised when Gson didn't handle it. There must be a better way. If anyone knows of one, please post it here. All the same, this was my solution:
I created a custom JsonDeserializer and registered it for the Date type. By doing so, Gson will use my deserializer for the Date type instead of its default. The same can be done for any other type if you want to serialize/deserialize it in a custom way.
public class JsonDateDeserializer implements JsonDeserializer<Date> {
public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
String s = json.getAsJsonPrimitive().getAsString();
long l = Long.parseLong(s.substring(6, s.length() - 2));
Date d = new Date(l);
return d;
}
}
Then, when I am creating my Gson object:
Gson gson = new GsonBuilder().registerTypeAdapter(Date.class, new JsonDateDeserializer()).create();
Now my gson object will be capable of parsing the .NET date format (millis since 1970).
Another solution is to use ISO 8601 format. This has to be configured on both Gson side as:
Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").create();
as well as on the server side, e.g. for ASP.NET MVC in Global.asax.cs file, as follows:
JsonSerializerSettings serializerSettings = new JsonSerializerSettings();
serializerSettings.Converters.Add(new IsoDateTimeConverter());
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings = serializerSettings;
The advantage of the code above is that it handles both serialization and deserialization and thus allows two way transmission of dates/times.
Note: IsoDateTimeConverter class is part of the JSON.NET library.
Serialize and Deserialize methoda. Register this as a Adapter for GSON
JsonSerializer<Date> ser = new JsonSerializer<Date>() {
#Override
public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext
context) {
return src == null ? null : new JsonPrimitive(src.getTime());
}
};
JsonDeserializer<Date> deser = new JsonDeserializer<Date>() {
#Override
public Date deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context) throws JsonParseException {
return json == null ? null : new Date(json.getAsLong());
}
};
Gson gson = new GsonBuilder()
.registerTypeAdapter(Date.class, ser)
.registerTypeAdapter(Date.class, deser).create();
This solution works for me by using SqlDateTypeAdapter:
SqlDateTypeAdapter sqlAdapter = new SqlDateTypeAdapter();
Gson gson = new GsonBuilder()
.registerTypeAdapter(java.sql.Date.class, sqlAdapter)
.setDateFormat("yyyy-MM-dd")
.create();
Ref: https://stackoverflow.com/a/30398307/7308789
I'm trying to have a custom date format in Gson output, but .setDateFormat(DateFormat.FULL) doesn't seem to work and it the same with .registerTypeAdapter(Date.class, new DateSerializer()).
It's like Gson doesn't care about the object "Date" and print it in its way.
How can I change that?
Thanks
EDIT:
#Entity
public class AdviceSheet {
public Date lastModif;
[...]
}
public void method {
Gson gson = new GsonBuilder().setDateFormat(DateFormat.LONG).create();
System.out.println(gson.toJson(adviceSheet);
}
I always use java.util.Date; setDateFormat() doesn't work :(
It seems that you need to define formats for both date and time part or use String-based formatting. For example:
Gson gson = new GsonBuilder()
.setDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz").create();
or using java.text.DateFormat
Gson gson = new GsonBuilder()
.setDateFormat(DateFormat.FULL, DateFormat.FULL).create();
or do it with serializers:
I believe that formatters cannot produce timestamps, but this serializer/deserializer-pair seems to work
JsonSerializer<Date> ser = new JsonSerializer<Date>() {
#Override
public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext
context) {
return src == null ? null : new JsonPrimitive(src.getTime());
}
};
JsonDeserializer<Date> deser = new JsonDeserializer<Date>() {
#Override
public Date deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context) throws JsonParseException {
return json == null ? null : new Date(json.getAsLong());
}
};
Gson gson = new GsonBuilder()
.registerTypeAdapter(Date.class, ser)
.registerTypeAdapter(Date.class, deser).create();
If using Java 8 or above you should use the above serializers/deserializers like so:
JsonSerializer<Date> ser = (src, typeOfSrc, context) -> src == null ? null
: new JsonPrimitive(src.getTime());
JsonDeserializer<Date> deser = (jSon, typeOfT, context) -> jSon == null ? null : new Date(jSon.getAsLong());
Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ").create();
Above format seems better to me as it has precision up to millis.
As M.L. pointed out, JsonSerializer works here. However, if you are formatting database entities, use java.sql.Date to register you serializer. Deserializer is not needed.
Gson gson = new GsonBuilder()
.registerTypeAdapter(java.sql.Date.class, ser).create();
This bug report might be related: http://code.google.com/p/google-gson/issues/detail?id=230. I use version 1.7.2 though.
In case if you hate Inner classes, by taking the advantage of functional interface you can write less code in Java 8 with a lambda expression.
JsonDeserializer<Date> dateJsonDeserializer =
(json, typeOfT, context) -> json == null ? null : new Date(json.getAsLong());
Gson gson = new GsonBuilder().registerTypeAdapter(Date.class,dateJsonDeserializer).create();
You can specify you format Gson gson = builder.setDateFormat("yyyy-MM-dd").create(); in this method instead of yyyy-MM-dd you can use anyother formats
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(Date.class, new JsonDeserializer<Date>() {
public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
return new Date(json.getAsJsonPrimitive().getAsLong());
}
});
Gson gson = builder.setDateFormat("yyyy-MM-dd").create();
This is a bug. Currently you either have to set a timeStyle as well or use one of the alternatives described in the other answers.
I'm on Gson 2.8.6 and discovered this bug today.
My approach allows all our existing clients (mobile/web/etc) to continue functioning as they were, but adds some handling for those using 24h formats and allows millis too, for good measure.
Gson rawGson = new Gson();
SimpleDateFormat fmt = new SimpleDateFormat("MMM d, yyyy HH:mm:ss")
private class DateDeserializer implements JsonDeserializer<Date> {
#Override
public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
try {
return new rawGson.fromJson(json, Date.class);
} catch (JsonSyntaxException e) {}
String timeString = json.getAsString();
log.warning("Standard date deserialization didn't work:" + timeString);
try {
return fmt.parse(timeString);
} catch (ParseException e) {}
log.warning("Parsing as json 24 didn't work:" + timeString);
return new Date(json.getAsLong());
}
}
Gson gson = new GsonBuilder()
.registerTypeAdapter(Date.class, new DateDeserializer())
.create();
I kept serialization the same as all clients understand the standard json date format.
Ordinarily, I don't think it's good practice to use try/catch blocks to govern flow control, but this should be a fairly rare case.
This won't really work at all. There is no date type in JSON. I would recommend to serialize to ISO 8601 back and forth (for format agnostics and JS compat). Consider that you have to know which fields contain dates.