22.5 注解的应用:定制序列化
在上一章,我们演示了一个简单的通用序列化类SimpleMapper,在将对象转换为字符串时,格式是固定的,本节演示如何对输出格式进行定制化。我们实现一个简单的类SimpleFormatter,它有一个方法:
1
| public static String format(Object obj)
|
我们定义两个注解:@Label
和@Format
。@Label
用于定制输出字段的名称,@Format
用于定义日期类型的输出格式,它们的定义如下:
1 2 3 4 5 6 7 8 9 10 11
| @Retention(RUNTIME) @Target(FIELD) public @interface Label { String value() default ""; } @Retention(RUNTIME) @Target(FIELD) public @interface Format { String pattern() default "yyyy-MM-dd HH:mm:ss"; String timezone() default "GMT+8"; }
|
可以用这两个注解来修饰要序列化的类字段,比如:
1 2 3 4 5 6 7 8 9
| static class Student { @Label("姓名") String name; @Label("出生日期") @Format(pattern="yyyy/MM/dd") Date born; @Label("分数") double score;
|
我们可以这样来使用SimpleFormatter:
1 2 3
| SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); Student zhangsan = new Student("张三", sdf.parse("1990-12-12"), 80.9d); System.out.println(SimpleFormatter.format(zhangsan));
|
输出为:
1 2 3
| 姓名:张三 出生日期:1990/12/12 分数:80.9
|
可以看出,输出使用了自定义的字段名称和日期格式,SimpleFormatter.format()是怎么利用这些注解的呢?我们看代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public static String format(Object obj) { try { Class<? > cls = obj.getClass(); StringBuilder sb = new StringBuilder(); for(Field f : cls.getDeclaredFields()) { if(! f.isAccessible()) { f.setAccessible(true); } Label label = f.getAnnotation(Label.class); String name = label ! = null ? label.value() : f.getName(); Object value = f.get(obj); if(value ! = null && f.getType() == Date.class) { value = formatDate(f, value); } sb.append(name + ":" + value + "\n"); } return sb.toString(); } catch (IllegalAccessException e) { throw new RuntimeException(e); } }
|
对于日期类型的字段,调用了formatDate,其代码为:
1 2 3 4 5 6 7 8 9
| private static Object formatDate(Field f, Object value) { Format format = f.getAnnotation(Format.class); if(format ! = null) { SimpleDateFormat sdf = new SimpleDateFormat(format.pattern()); sdf.setTimeZone(TimeZone.getTimeZone(format.timezone())); return sdf.format(value); } return value; }
|
这些代码都比较简单,我们就不解释了。