Проблема сериализации Genson с полями байтов и даты
Привет, я использую Genson для ser/de для моих классов POJO. Но есть проблема при сериализации POJO с байтовым полем. Я не пробовал десериализацию одного и того же объекта. Так что я не знаю, работает ли это тоже. Также есть проблема в поле даты.
Вот мой POJO
public class User implements Serializable{
private String userId;
private String emailId;
private Date lastLogin;
private Byte attempts;
//geters and setters, toString methods.
}
Я получил объект со значениями, и когда я печатаю, я получил следующее.
User [userId=sss, emailId=ssss@gmail.com, lastLogin=2014-12-21 23:24:46.0, attempts=9]
Я попробовал следующий код для сериализации с Genson (иногда мне нужно сериализовать, удалив некоторые поля, поэтому я использую следующий код).
public String serialize(Object object, Class cls,
String[] ignoreList) {
GensonBuilder builder = new Genson.Builder();
if (null != ignoreList) {
for (String field : ignoreList) {
builder.exclude(field, cls);
}
}
Genson genson = builder.create();
return genson.serialize(object);
}
Но я получаю следующую строку JSON, значение поля байта отличается. Значение поля даты без отметки времени.
{"emailId":"sss@gmail.com","lastLogin":"21 Dec, 2014","attempts":"CQ==","userId":"sss"}
Я вижу, проблема с байтами уже исправлена с помощью этой проблемы в Github. Но как мне получить обновленный код в моем проекте? Я использую Maven и использую последнюю версию Genson-1.2.
Должен ли я попробовать builder.useByteAsInt(true);
в моем коде?
Также для поля даты. Я вижу два варианта
builder.useDateAsTimestamp(true);
builder.useDateFormat(dateFormat);
Я не хочу устанавливать эти вещи. Потому что иногда поле может приходить с меткой времени, а иногда без метки времени, и форматы даты могут отличаться для разных объектов. Я ищу решение, которое будет сериализовать поле даты и преобразовать в строку как есть.
Каков наилучший способ получить правильную строку JSON? Я ищу решение, которое может сериализовать десериализацию любого класса POJO.
ОБНОВЛЕНИЕ 1
Я создал ByteConverter и Date Converter.
Это мои конвертеры ByteConverter.java
@HandleClassMetadata
@HandleBeanView
public final class ByteConverter implements Converter<Byte> {
public final static ByteConverter instance = new ByteConverter();
private ByteConverter() {
}
public void serialize(Byte obj, ObjectWriter writer, Context ctx) {
writer.writeValue(obj.byteValue());
}
public Byte deserialize(ObjectReader reader, Context ctx) {
return (byte) reader.valueAsInt();
}
}
DateConverter.java
@HandleClassMetadata
@HandleBeanView
public class DateConverter implements Converter<Date> {
private DateFormat dateFormat;
private final boolean asTimeInMillis;
public DateConverter() {
this(SimpleDateFormat.getDateInstance(), false);
}
public DateConverter(DateFormat dateFormat, boolean asTimeInMillis) {
if (dateFormat == null)
dateFormat = SimpleDateFormat.getDateInstance();
this.dateFormat = dateFormat;
this.asTimeInMillis = asTimeInMillis;
}
public void serialize(Date obj, ObjectWriter writer, Context ctx) {
if (asTimeInMillis)
writer.writeValue(obj.getTime());
else
writer.writeUnsafeValue(format(obj));
}
protected synchronized String format(Date date) {
return dateFormat.format(date);
}
public Date deserialize(ObjectReader reader, Context ctx) {
try {
if (asTimeInMillis)
return new Date(reader.valueAsLong());
else
return read(reader.valueAsString());
} catch (ParseException e) {
throw new JsonBindingException("Could not parse date "
+ reader.valueAsString(), e);
}
}
protected synchronized Date read(String dateString) throws ParseException {
return dateFormat.parse(dateString);
}
}
В моем методе я попробовал следующий код
public void serialize(User user) {
Converter<Byte> byteConverter = ByteConverter.instance;
Converter<Date> dateConverter = new DateConverter();
Converter[] converters = { byteConverter, dateConverter };
GensonBuilder builder = new GensonBuilder();
builder.withConverters(converters);
Genson genson = builder.create();
String str = genson.serialize(user);
System.out.println(str);
}
Я получаю следующую строку JSON
{"emailId":"sss@gmail.com","lastLogin":"21 Dec, 2014","attempts":"9","userId":"sss"}
Байт проблема решена. Но проблема с датой все еще существует. Я попробовал следующий метод derialize класса DateConverter. Но это также не сработало.
public Date deserialize(ObjectReader reader, Context ctx) {
try {
if (reader.getValueType() == ValueType.INTEGER)
return new Date(reader.valueAsLong());
else
return dateFormat.parse(reader.valueAsString());
} catch (ParseException e) {
throw new JsonBindingException("Could not parse date "
+ reader.valueAsString(), e);
}
}
ОБНОВЛЕНИЕ 2
Мой обновленный DateConverter.java. DateUtils из общего достояния Apache. Я не тестировал десериализацию. Но Сериализация работает. Я хотел формат с Timezone также. Так я и сделал по-своему.
@HandleClassMetadata
@HandleBeanView
public class DateConverter implements Converter<Date> {
private static final String YYYY_MM_DD_HH_MM_SS_Z = "yyyy-MM-dd HH:mm:ss z";
private static final String YYYY_MM_DD_SLASH = "yyyy/MM/dd";
private static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
private static final String YYYY_MM_DD_HH_MM_SS_ZZZ = "yyyy-MM-dd HH:mm:ss zzz";
private static final String DD_MMM_YY_HH_MM_SS_SSSSSS_AAA = "dd-MMM-yy hh.mm.ss.SSSSSS aaa";
private static final String YYYY_MM_DD_HH_MM_SS_SSS = "yyyy-MM-dd HH:mm:ss.SSS";
private static final String YYYY_MM_DD = "yyyy-MM-dd";
private static final String YYYY_MM_DD_HH_MM_SS_0 = "yyyy-MM-dd HH:mm:ss.'0'";
private static final String EEE_MMM_DD_HH_MM_SS_ZZZ_YYYY = "EEE MMM dd HH:mm:ss zzz yyyy";
String[] dateFormats = { EEE_MMM_DD_HH_MM_SS_ZZZ_YYYY,
YYYY_MM_DD_HH_MM_SS_0, YYYY_MM_DD, YYYY_MM_DD_HH_MM_SS_SSS,
DD_MMM_YY_HH_MM_SS_SSSSSS_AAA, YYYY_MM_DD_HH_MM_SS_ZZZ,
YYYY_MM_DD_HH_MM_SS, YYYY_MM_DD_SLASH };
private DateFormat dateFormat;
private final boolean asTimeInMillis;
public DateConverter() {
this(SimpleDateFormat.getDateInstance(), false);
}
public DateConverter(DateFormat dateFormat, boolean asTimeInMillis) {
if (dateFormat == null)
dateFormat = SimpleDateFormat.getDateInstance();
this.dateFormat = dateFormat;
this.asTimeInMillis = asTimeInMillis;
}
public void serialize(Date obj, ObjectWriter writer, Context ctx) {
if (asTimeInMillis)
writer.writeValue(obj.getTime());
else
writer.writeUnsafeValue(format(obj));
}
protected synchronized String format(Date date) {
return getDateTime(YYYY_MM_DD_HH_MM_SS_Z, date);
// return dateFormat.format(date);
}
public Date deserialize(ObjectReader reader, Context ctx) {
try {
if (asTimeInMillis)
return new Date(reader.valueAsLong());
else
return read(reader.valueAsString());
} catch (ParseException e) {
throw new JsonBindingException("Could not parse date "
+ reader.valueAsString(), e);
}
}
protected synchronized Date read(String dateString) throws ParseException {
return DateUtils.parseDate(dateString, dateFormats);
// return dateFormat.parse(dateString);
}
public String getDateTime(String aMask, Date aDate) {
SimpleDateFormat df = null;
String returnValue = "";
if (aDate != null) {
df = new SimpleDateFormat(aMask);
returnValue = df.format(aDate);
}
return returnValue;
}
}
1 ответ
Обновление Это было выпущено в Genson 1.3.
Однобайтовая проблема
Исправление проблемы, о которой вы упомянули, было перенесено в ветку devlopment, но еще не выпущено. Это должно прибыть скоро с другими улучшениями и исправлениями ошибок. Если вам это нужно сейчас, вы можете определить собственный конвертер и зарегистрировать его в GensonBuilder.
Обратите внимание, что вы хотите добавить аннотацию @HandleClassMetadata, только если вы включили функцию метаданных класса (эта аннотация гарантирует, что Genson не будет записывать информацию о классе для вывода этого конвертера).
Формат даты
Если форматы входящей даты (строковые или временные метки) не изменяются для каждого поля, вы можете определить глобальную политику и затем переопределить аннотацию @JsonDateFormat на своем получателе и установщике (если вы используете конфигурацию по умолчанию) или полях (если вы не используете getter/setter и настроенная видимость приватных полей).
Если входящие данные изменяются даже для одного и того же поля (или вы не хотите использовать аннотацию), вам, вероятно, придется предоставить специальный конвертер дат, аналогичный этому. Основным отличием будет то, что в методе десериализации у вас будет что-то вроде этого:
if (reader.getValueType() == ValueType.INTEGER)
return new Date(reader.valueAsLong());
else if (reader.getValueType() == ValueType.STRING)
return dateFormat.parse(reader.valueAsString());
Я открыл вопрос, чтобы предоставить это из коробки в следующем выпуске.