Genson序列化带有字节和日期字段的问题

时间:2015-01-23 06:31:52

标签: java serialization json-deserialization jsonserializer genson

嗨我正在使用Genson为我的POJO课程提供ser / de。但是在序列化具有字节字段的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"}

我看到已经使用this Issue in 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"}

解决了字节问题。但是日期问题仍然存在。我尝试了DateConverter类的derialize方法。但它也没有用。

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 commons。我没有测试反序列化。但是Serialize正在发挥作用。我也想要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 个答案:

答案 0 :(得分:1)

<强>更新 这已在Genson 1.3中发布。

单字节问题

您提到的问题的修复程序已被推送到devlopment分支但尚未发布。它应该很快就会有其他增强功能和错误修复。 如果您现在需要,那么您可以define a custom Converter并将其注册到GensonBuilder。

请注意,只有在启用了类元数据功能时才要添加@HandleClassMetadata注释(此注释确保Genson不会为此Converter的输出编写类信息)。

日期格式

如果传入的日期格式(字符串或时间戳)不是每个字段更改,那么您可以定义全局策略,然后使用@JsonDateFormat注释覆盖getter和setter(如果使用默认配置)或字段(如果你不喜欢)使用getter / setter并配置私有字段的可见性。

如果传入的数据即使是相同的字段也会发生变化(或者您不想使用注释),您可能需要提供类似于this one的自定义日期转换器。 主要的区别在于,在反序列化方法中你会得到类似这样的东西:

if (reader.getValueType() == ValueType.INTEGER) 
  return new Date(reader.valueAsLong());
else if (reader.getValueType() == ValueType.STRING) 
  return dateFormat.parse(reader.valueAsString());

我已打开an issue以便在下一个版本中提供此功能。