Проблема сериализации 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());

Я открыл вопрос, чтобы предоставить это из коробки в следующем выпуске.

Другие вопросы по тегам