the problem is in the Postegres timestamp serialization using GSON,
private static final GsonBuilder GSON_BASE = Converters
.registerAll(new GsonBuilder().disableHtmlEscaping())
.registerTypeAdapter(InfoTransfer.class, new InfoTransfer.Adapter())
.setDateFormat(DateFormat.FULL, DateFormat.FULL) //Line added but it seems work for MySQL DB Timestamp
.setPrettyPrinting()
.create();
.
//inner class in InfoTransfer
public static class Adapter implements JsonSerializer<InfoTransfer>{
#Override
public JsonElement serialize(InfoTransfer src, Type typeOfSrc, JsonSerializationContext context) {
Gson gson= new Gson();
JsonObject jsonObject= (JsonObject) gson.toJsonTree(src);
return new JsonPrimitive(jsonObject.getAsString());
}
}
.
.
.
Log.d("Result",GSON_BASE.toJson(data));
expected result :
"created_at": "2016-10-13 18:18:51.64208+01"
result :
\"created_at\": \"\\u0000\\u0001\\ufffdM\\u0015q\\ufffd}\"
so any suggestion ?
The date format can be set as follows:-
setDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSSX")
Example:-
public static void main(String[] args) {
String jsonString = "{\"customorId\":\"506\",\"joiningDate\":\"2016-10-26 19:49:17.290671+01\"}";
Gson gson = new GsonBuilder()
.setDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSSX")
.setPrettyPrinting()
.create();
//Deserialize
Customer customer = gson.fromJson(jsonString, Customer.class);
System.out.println(customer.toString());
//Serialize
Customer customerSerialize = new Customer();
customerSerialize.setCustomorId("123");
customerSerialize.setJoiningDate(new Date());
System.out.println(gson.toJson(customerSerialize));
}
Customer class:-
public class Customer implements Serializable {
private static final long serialVersionUID = 1100012615187080642L;
private String customorId;
private Date joiningDate;
}
Sample output:-
Customer [customorId=506, joiningDate=Wed Oct 26 19:54:07 BST 2016]
{
"customorId": "123",
"joiningDate": "2016-10-26 20:23:37.000811+01"
}
Related
I need to create json of this format:
{
"array": [
1482922777223,
0.014221191,
0.014221191,
0.014221191
]
}
Data.class
public class Data {
#SerializedName("array")
#Expose
private List<Float> array = null;
}
to convert object to JSON string i use gson library.
List<Float> list = new ArrayList<>();
list.add((float)1482922777223);
list.add(0.014221191);
list.add(0.014221191);
list.add(0.014221191);
Data data = new Data(list);
Gson gson = new Gson();
String json = gson.toJson(data);
Result string:
{
"array": [
1.4829219E12, <--- HOW TO GET HERE 1482922777223?
0.014221191,
0.014221191,
0.014221191
]
}
Please help!
You need to register TypeAdapter for Float values.
E.g:
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Float.class, new JsonSerializer<Float>() {
#Override
public JsonElement serialize(final Float src, final Type typeOfSrc, final JsonSerializationContext context) {
BigDecimal value = BigDecimal.valueOf(src);
return new JsonPrimitive(value);
}
});
Gson gson = gsonBuilder.create();
String json = gson.toJson(data);
Output :
{
"array": [
1482922777223,
0.014221191,
0.014221191,
0.014221191
]
}
Am retrieving information from my SQLite database to display on CardView
My SQLite database structure is SQLite DB
My class is
public class ServiceRequest{
public String reqid;
public String name;
public String branch;
public Date date;
public Date time;
public String services;
//Getter and setter
.............
.............
}
I can convert this to JSON format using
List<ServiceRequest> reqs = getAllReqs();
List<ServiceRequest> jobservList = new ArrayList<>();
for (ServiceRequest access : reqs) {
ServiceRequest ob = new ServiceRequest();
ob.setId(access.getId());
ob.setBranch(access.getBranch());
ob.setName(access.getName());
ob.setDate(access.getDate());
ob.setTime(access.getTime());
ob.setServices(access.getServices());
jobservList.add(ob);
}
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String json2 = gson.toJson(jobservList);
return json2;
but my desired JSONObject format is
{
"100": {
"name": "Rahul Suresh",
"branch": "Koramangala",
"phNumber":"123456",
"date": "2016-08-06",
"time": "16:00",
"reqServices": "Loans"
},
"200": {
"name": "Sidh",
"branch": "Jayanagar",
"phNumber":"182694",
"date": "2016-08-12",
"time": "11:00",
"reqServices": "OpenAcc,SafeDeposit"
}
}
so that I will get one whole JSON object with a single call
JSONObject jb = (JSONObject) jsonObject.get(Integer.toString(id));
100,200 are 'reqid' s
It's possible to achieve this using string builder. But is there any other ways to implement this like using an object mapper along with a class or something..?
If you would like to form the JSON you have shown, you could "pull out" the ID into a HashMap key, then set the value to be your object.
I can't remember how Gson handles the conversion of the object values in the map, but this is the general idea
List<ServiceRequest> reqs = getAllReqs();
HashMap<Integer, ServiceRequest> map = new HashMap<Integer, ServiceRequest>();
for (ServiceRequest access : reqs) {
map.put(access.getId(), access);
}
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String json2 = gson.toJson(map); // TODO: Not sure if this will work
return json2;
I am using the Retrofit library for my REST calls. Most of what I have done has been smooth as butter but for some reason I am having issues converting JSON timestamp strings into java.util.Date objects. The JSON that is coming in looks like this.
{
"date": "2013-07-16",
"created_at": "2013-07-16T22:52:36Z",
}
How can I tell Retrofit or Gson to convert these strings into java.util.Date objects?
Gson gson = new GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ss")
.create();
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(API_BASE_URL)
.setConverter(new GsonConverter.create(gson))
.build();
Or the Kotlin equivalent:
val gson = GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss").create()
RestAdapter restAdapter = Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
.create(T::class.java)
You can set your customized Gson parser to retrofit. More here: Retrofit Website
Look at Ondreju's response to see how to implement this in retrofit 2.
#gderaco's answer updated to retrofit 2.0:
Gson gson = new GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ss")
.create();
Retrofit retrofitAdapter = new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
Here is how I did it:
Create DateTime class extending Date and then write a custom deserializer:
public class DateTime extends java.util.Date {
public DateTime(long readLong) {
super(readLong);
}
public DateTime(Date date) {
super(date.getTime());
}
}
Now for the deserializer part where we register both Date and DateTime converters:
public static Gson gsonWithDate(){
final GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(Date.class, new JsonDeserializer<Date>() {
final DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
#Override
public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
try {
return df.parse(json.getAsString());
} catch (final java.text.ParseException e) {
e.printStackTrace();
return null;
}
}
});
builder.registerTypeAdapter(DateTime.class, new JsonDeserializer<DateTime>() {
final DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
#Override
public DateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
try {
return new DateTime(df.parse(json.getAsString()));
} catch (final java.text.ParseException e) {
e.printStackTrace();
return null;
}
}
});
return builder.create();
}
And when you create your RestAdapter, do the following:
new RestAdapter.Builder().setConverter(gsonWithDate());
Your Foo should look like this:
class Foo {
Date date;
DateTime created_at;
}
Gson can handle only one datetime format (those specified in builder) plus the iso8601 if parsing with custom format is not possible. So, a solution could be to write your custom deserializer. To solve your problem I defined:
package stackoverflow.questions.q18473011;
import java.util.Date;
public class Foo {
Date date;
Date created_at;
public Foo(Date date, Date created_at){
this.date = date;
this.created_at = created_at;
}
#Override
public String toString() {
return "Foo [date=" + date + ", created_at=" + created_at + "]";
}
}
with this deserializer:
package stackoverflow.questions.q18473011;
import java.lang.reflect.Type;
import java.text.*;
import java.util.Date;
import com.google.gson.*;
public class FooDeserializer implements JsonDeserializer<Foo> {
public Foo deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
String a = json.getAsJsonObject().get("date").getAsString();
String b = json.getAsJsonObject().get("created_at").getAsString();
SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat sdfDateWithTime = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
Date date, created;
try {
date = sdfDate.parse(a);
created = sdfDateWithTime.parse(b);
} catch (ParseException e) {
throw new RuntimeException(e);
}
return new Foo(date, created);
}
}
Final step is to create a Gson instance with right adapter:
package stackoverflow.questions.q18473011;
import com.google.gson.*;
public class Question {
/**
* #param args
*/
public static void main(String[] args) {
String s = "{ \"date\": \"2013-07-16\", \"created_at\": \"2013-07-16T22:52:36Z\"}";
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(Foo.class, new FooDeserializer());
Gson gson = builder.create();
Foo myObject = gson.fromJson(s, Foo.class);
System.out.println("Result: "+myObject);
}
}
My result:
Result: Foo [date=Tue Jul 16 00:00:00 CEST 2013, created_at=Tue Jul 16 22:52:36 CEST 2013]
Quite literally if you already have an Date object with the name "created_at" in the class you are creating then it is this easy:
Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").create();
YourObject parsedObject1 = gson.fromJson(JsonStringYouGotSomehow, YourObject.class);
And you're done. no complicated overriding needed.
You can define two new classes like this:
import java.util.Date;
public class MyDate extends Date {
}
and
import java.util.Date;
public class CreatedAtDate extends Date {
}
Your POJO will be like this:
import MyDate;
import CreatedAtDate;
public class Foo {
MyDate date;
CreatedAtDate created_at;
}
Finally set your custom deserializer:
public class MyDateDeserializer implements JsonDeserializer<Date> {
public static final SimpleDateFormat sServerDateDateFormat = new SimpleDateFormat("yyyy-MM-dd");
#Override
public MyDate deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
if (json != null) {
final String jsonString = json.getAsString();
try {
return (MyDate) sServerDateDateFormat.parse(jsonString);
} catch (ParseException e) {
e.printStackTrace();
}
}
return null;
}
}
and
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(MyDate.class, new MyDateDeserializer());
This doesn't answer directly the question asked, but is in my opinion the "state of the art" if the coder has the full freedom of choice on how to solve the problem.
First of all, it's not best solution to use java.util.Date. Reason is that those classes had no ideal behaviour in some corner cases so where superseeded by the Java Instant class etc. check the answer of Basil Bourque in this S.O. question: Creating Date objects in Kotlin for API level less than or equal to 16
So I used the Instant class of ThreeTenABP, and
using Kotlin, on Android:
val gson = GsonBuilder().registerTypeAdapter(Instant::class.java,
JsonDeserializer<Instant> { json: JsonElement, _: Type?, _: JsonDeserializationContext? ->
ZonedDateTime.parse(
json.asJsonPrimitive.asString
).toInstant()
}
).create()
val retrofit = Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
I'm using GSON on my Java EE server to provide some json to views.
In some object, I have long text, that can contains anything (like 'What a "great" news!').
I'm supprised that by default GSON doesn't escape the double quote, so it doesn't generate a valid JSON.
Is there a good way of doing this ?
Maybe I'm not understanding your question, but I was able to get GSON to handle Strings with quotes without any settings or changes.
import com.google.gson.Gson;
public class GSONTest {
public String value;
public static void main(String[] args) {
Gson g = new Gson();
GSONTest gt = new GSONTest();
gt.value = "This is a \"test\" of quoted strings";
System.out.println("String: " + gt.value);
System.out.println("JSON: " + g.toJson(gt));
}
}
Output:
String: This is a "test" of quoted strings
JSON: {"value":"This is a \"test\" of quoted strings"}
Maybe I don't understand what you're asking?
Try using setPrettyPrinting with DisableHtml escaping.
import com.google.gson.Gson;
Gson gson = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();
JsonParser jp = new JsonParser();
JsonElement je = jp.parse(jsonArray.toString());
System.out.println( gson.toJson(je));
Here's some sample GSON code:
final JsonObject obj = new JsonObject();
obj.addProperty("foo", "b\"a\"r");
System.out.println(obj.toString());
The Output is:
{"foo":"b\"a\"r"}
(as it should be)
So either you are doing something wrong, or you are using an ancient version of GSON. Perhaps you should show some of your code?
That is what I did to solve that
private final Gson mGson;
{
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(String.class, new EscapeStringSerializer());
mGson = builder.create();
}
private static class EscapeStringSerializer implements JsonSerializer<String> {
#Override
public JsonElement serialize(String s, Type type, JsonSerializationContext jsonSerializationContext) {
return new JsonPrimitive(escapeJS(s));
}
public static String escapeJS(String string) {
String escapes[][] = new String[][]{
{"\\", "\\\\"},
{"\"", "\\\""},
{"\n", "\\n"},
{"\r", "\\r"},
{"\b", "\\b"},
{"\f", "\\f"},
{"\t", "\\t"}
};
for (String[] esc : escapes) {
string = string.replace(esc[0], esc[1]);
}
return string;
}
}
I have a Java class, User:
public class User
{
int id;
String name;
Timestamp updateDate;
}
And I receive a JSON list containing user objects from a webservice:
[{"id":1,"name":"Jonas","update_date":"1300962900226"},
{"id":5,"name":"Test","date_date":"1304782298024"}]
I have tried to write a custom deserializer:
#Override
public User deserialize(JsonElement json, Type type,
JsonDeserializationContext context) throws JsonParseException {
return new User(
json.getAsJsonPrimitive().getAsInt(),
json.getAsString(),
json.getAsInt(),
(Timestamp)context.deserialize(json.getAsJsonPrimitive(),
Timestamp.class));
}
But my deserializer doesn't work. How can I write a custom JSON deserializer for Gson?
I'd take a slightly different approach as follows, so as to minimize "manual" parsing in my code, as unnecessarily doing otherwise somewhat defeats the purpose of why I'd use an API like Gson in the first place.
// output:
// [User: id=1, name=Jonas, updateDate=2011-03-24 03:35:00.226]
// [User: id=5, name=Test, updateDate=2011-05-07 08:31:38.024]
// using java.sql.Timestamp
public class Foo
{
static String jsonInput =
"[" +
"{\"id\":1,\"name\":\"Jonas\",\"update_date\":\"1300962900226\"}," +
"{\"id\":5,\"name\":\"Test\",\"update_date\":\"1304782298024\"}" +
"]";
public static void main(String[] args)
{
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
gsonBuilder.registerTypeAdapter(Timestamp.class, new TimestampDeserializer());
Gson gson = gsonBuilder.create();
User[] users = gson.fromJson(jsonInput, User[].class);
for (User user : users)
{
System.out.println(user);
}
}
}
class User
{
int id;
String name;
Timestamp updateDate;
#Override
public String toString()
{
return String.format(
"[User: id=%1$d, name=%2$s, updateDate=%3$s]",
id, name, updateDate);
}
}
class TimestampDeserializer implements JsonDeserializer<Timestamp>
{
#Override
public Timestamp deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException
{
long time = Long.parseLong(json.getAsString());
return new Timestamp(time);
}
}
(This assumes that "date_date" should be "update_date", in the original question.)
#Override
public User deserialize(JsonElement json, Type type,
JsonDeserializationContext context) throws JsonParseException {
JsonObject jobject = json.getAsJsonObject();
return new User(
jobject.get("id").getAsInt(),
jobject.get("name").getAsString(),
new Timestamp(jobject.get("update_date").getAsLong()));
}
I'm assuming User class has the appropriate constructor.
Today I was looking for this thing as my class had java.time.Instant and the default gson could not deserialize it. My POJOs look like this:
open class RewardResult(
#SerializedName("id")
var id: Int,
#SerializedName("title")
var title: String?,
#SerializedName("details")
var details: String?,
#SerializedName("image")
var image: String?,
#SerializedName("start_time")
var startTimeUtcZulu: Instant?, // Unit: Utc / Zulu. Unit is very important
#SerializedName("end_time")
var endTimeUtcZulu: Instant?,
#SerializedName("unlock_expiry")
var unlockExpiryTimeUtcZulu: Instant?,
#SerializedName("target")
var target: Int,
#SerializedName("reward")
var rewardItem: RewardItem
);
data class RewardItem(
#SerializedName("type")
var type: String?,
#SerializedName("item_id")
var itemId: Int,
#SerializedName("amount")
var amount: Int
)
Then for Instant variables, I parse the json's time variables and convert string to Instant. For integer , string, etc I use jsonObject.get("id").asInt etc. For other pojo, I use the default deserializer like this:
val rewardItem: RewardItem = context!!.deserialize(rewardJsonElement,
RewardItem::class.java);
So the corresponding custom deserializer looks like this:
val customDeserializer: JsonDeserializer<RewardResult> = object : JsonDeserializer<RewardResult> {
override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?): RewardResult {
val jsonObject: JsonObject = json!!.asJsonObject;
val startTimeString: String? = jsonObject.get("start_time")?.asString;
var startTimeUtcZulu: Instant? = createTimeInstant(startTimeString);
val endTimeString: String? = jsonObject.get("end_time")?.asString;
var endTimeUtcZulu: Instant? = createTimeInstant(endTimeString);
val unlockExpiryStr: String? = jsonObject.get("unlock_expiry")?.asString;
var unlockExpiryUtcZulu: Instant? = createTimeInstant(unlockExpiryStr);
val rewardJsonElement: JsonElement = jsonObject.get("reward");
val rewardItem: ridmik.one.modal.reward.RewardItem = context!!.deserialize(rewardJsonElement,
ridmik.one.modal.reward.RewardItem::class.java); // I suppose this line means use the default jsonDeserializer
var output: ridmik.one.modal.reward.RewardResult = ridmik.one.modal.reward.RewardResult(
id = jsonObject.get("id").asInt,
title = jsonObject.get("title")?.asString,
details = jsonObject.get("details")?.asString,
image = jsonObject.get("image")?.asString,
startTimeUtcZulu = startTimeUtcZulu,
endTimeUtcZulu = endTimeUtcZulu,
unlockExpiryTimeUtcZulu = unlockExpiryUtcZulu,
target = jsonObject.get("target").asInt,
rewardItem = rewardItem
);
Timber.tag(TAG).e("output = "+output);
return output;
}
}
Finally, I create my custom gson like this:
val gsonBuilder = GsonBuilder();
gsonBuilder.registerTypeAdapter(RewardResult::class.javaObjectType,
this.customJsonDeserializer);
val customGson: Gson = gsonBuilder.create();