背负式风力灭火机使用:用 annotation 辅助 Json-lib 转换 JavaBean
来源:百度文库 编辑:偶看新闻 时间:2024/04/30 15:46:17
如今大量的 Web 站点应用了 AJAX 技术,通过更少的数据通讯,服务器能够更快的反馈用户请求,再通过 Javascript 的控制,让使用者有了更好的用户体验。JSON 是一种轻量级的数据交换语言,它是 Javascript 的一个子集,又有良好的可读性,经常用于客户端和服务器间的数据交换。因此,在服务器端,常常需要将实体对象(JavaBean)转换为 JSON 格式数据。本文介绍了如何使用 Json-lib 转换 JavaBean 为 JSON 格式数据,并给出解决方法,以及利用 annotation 来增强 Json-lib 的两个功能:一是灵活的筛选 JavaBean 属性;二是通过 JsonValueProcessor 来自定义如何转换 JavaBean 属性到 JSON 数据。
回页首
JSON 的数据格式简单易读,它存在于两种基本形式:
名值对(Collection):名称与值用‘:’分开;名值对之间用‘,’分隔;整体用‘ {} '括起来。例如 {name1:value1, name2:value2}
值的有序队列(Array):即数组,每个值之间用‘,’分隔;整体用‘ [] '括起来。例如:[value1, value2]
这两种形式的有机组合,就形成了 JSON 数据。
回页首
Json-lib 是一个 java 工具库,它提供 api 来转换 JavaBean,Map,Collection 等对象为 JSON 数据,或反过来通过 JSON 数据得到 JavaBean。
Json-lib 的使用很容易,只要使用 JSONSerializer 的 toJSON 方法就可以转换任意的 Java Object 为 JSON 对象了,再调用 JSON 对象的 toString 方法可以得到转换后的字符串。不过还有一些进一步的问题需要我们自己来解决。
import net.sf.json.JSONSerializer;List list = new ArrayList(); list.add( "first" );list.add( "second" );JSON json = JSONSerializer.toJSON( list );System.out.println( json.toString() );// prints ["first","second"]class MyBean{ private String name = "json"; private int pojoId = 1; // getters & setters ...}json = JSONSerializer.toJSON( new MyBean() );System.out.println( json.toString() );// prints {"name":"json","pojoId":1}
清单 1 中的例子转换后的 JSON 数据中包含了 JavaBean 中的全部属性,可是我们常常需要有选择的提取 JavaBean 中的特定属性出来。例如:
需要过滤掉循环引用的属性,这一点 json-lib 提供了 CycleDetectionStrategy 来处理,但是直接过滤掉更简单;
不同的情况下只需要 JavaBean 中的部分属性:比如列表界面只需要显示 Bean 的几个重要属性,而详情界面则需要显示更多的 Bean 的属性;
不同的用户权限限制用户只能获得某些属性数据;
对于普通的 Object 类型(如 Long,String 等),json-lib 有缺省的值转换处理方式,但是对于一些特殊的类型,我们希望用自定义的方式来转换该属性的值。例如:
对于 java.util.Date 类型,我们希望直接转换成时间串:2010-04-10,而不希望得到一个类似 {"year":"2010","month":"4","day":"10"} 这样的结果
对于常用到的代码数据(比如:性别),在定义时它也许是个 Integer(男:1;女:2),我们希望在转换后直接得到:{"性别":"男",...},而不是 {"性别":"1",...}
Json-lib 已经预留出一些接口,让用户修改它的缺省行为。下面我们来看看如何利用 annotation 来配合 Json-lib 解决这两个问题。
回页首
JSONSerializer 提供了一个 toJSON 的重载方法,增加一个参数 JsonConfig,可以通过这个参数对 Json-lib 的缺省方式做自定义的配置。
import net.sf.json.JSONSerializer;import net.sf.json.JsonConfig;import net.sf.json.util.PropertyFilter;// 定义属性过滤器PropertyFilter filter = new PropertyFilter( public boolean apply(Object source, String name, Object value) { if ( name.equals( “pojoId” ) ) { return true; // 返回 true, 表示这个属性将被过滤掉 } return false; });// 注册属性过滤器JsonConfig config = new JsonConfig();config.setJsonPropertyFilter( filter );System.out.println( JSONSerializer.toJSON( new MyBean(), config ) );// prints {"name":"json"}
从清单 2 中可以看出来,Json-lib 通过 PropertyFilter 的 apply 方法进行属性过滤,可以象例子中一样,把所有需要过滤的属性名称写进去,但是这样做太烦琐,也不好维护,对不同的 Bean 要做不同的处理。下面让我们看看怎么利用 annotation 来更方便的处理。
首先,需要定义一个 annotation,并给 MyBean 的 get 方法加上标注。
import java.lang.annotation.Target;import java.lang.annotation.Documented;import java.lang.annotation.Retention;import java.lang.annotation.ElementType;import java.lang.annotation.RetentionPolicy;@Documented@Target({ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)public @interface Invisible { public String[] value();}// 为myBean中需要过滤的属性get方法(或者is方法)加上Invisible标注public class MyBean{ private String name = "json"; private int pojoId = 1; // getters & setters public String getName() { return name; } @Invisible(“LIST”) // 在 “LIST” 情况下不要这个属性 public int getPojoId() { return pojoId; }}
然后,我们需要一些能处理 annotation 的 PropertyFilter 类。
import java.util.Map;import java.lang.reflect.Method;import net.sf.json.util.PropertyFilter;// 先实现一个abstract类,将读取Bean属性的Method找到并传递给子类处理public abstract class AbstractMethodFilter implements PropertyFilter { // 这个方法留给子类实现,以便适应不同的过滤需求 public abstract boolean apply(final Method method); public boolean apply(final Object source, final String name, final Object value) { if (source instanceof Map) { return false; } String propName = name.substring(0, 1).toUpperCase() + name.substring(1); Class clz = source.getClass(); String methodName = "get" + propName; Method method = null; try { method = clz.getMethod(methodName, (Class[]) null); // 寻找属性的get方法 } catch (NoSuchMethodException nsme) { String methodName2 = "is" + propName; // 也许是个is方法 try { method = clz.getMethod(methodName2, (Class[]) null); } catch (NoSuchMethodException ne) { // 没有找到属性的get或者is方法,打印错误,返回true System.err.println(“No such methods: ” + methodName + “ or “ + methodName2); return true; } } return apply(method); }} // END: AbstractMethodFilterpublic class InvisibleFilter extends AbstractMethodFilter { // 过滤条件,标注中有符合这个条件的property将被过滤掉 private String _sGUIID; public InvisibleFilter(final String guiid) { _sGUIID = guiid; } public boolean apply(final Method method) { if (_sGUIID == null || _sGUIID.equals(“”)) { return false; // 表示不做限制 } if (method.isAnnotationPresent(Invisible.class)) { Invisible anno = method.getAnnotation(Invisible.class); String[] value = anno.value(); for (int i = 0; i < value.length; i++) { if (_sGUIID.equals(value[i])) { return true; } } } return false; }}
现在只要把这个 filter 注册到 JsonConfig 中,就实现了属性的过滤,请看清单 5。
JsonConfig config = new JsonConfig();config.setJsonPropertyFilter( new InvisibleFilter(“LIST”)); //标注了LIST的属性将被过滤掉System.out.println( JSONSerializer.toJSON( new MyBean(), config ) );// prints {"name":"json"}
增加其他的 annotation 及 Filter 就可以实现不同的属性过滤方式了。
回页首
Json-lib 通过 JsonConfig 提供了自定义属性转换方式的接口。
JsonConfig config = new JsonConfig();config.registerJsonValueProcessor(java.util.Date.class, new JsDateJsonValueProcessor());
注册后 Json-lib 在遇到 java.uitl.Date 类型的属性时,会应用 JsDateJsonValueProcessor 的处理方法。
所以,只要实现自己的 JsonValueProcessor 就可以自定义各种 Object 的转换方式了。
根据上一节的讨论,Json-lib 在转换 Bean 属性之前,会将属性数据传递给 PropertyFilter 来判断是否需要过滤掉。因此,我们可以通过一个 Filter 对象获得 Bean 的属性的标注数据,并将它传递给特定的 Processor,Processor 根据得到的标注值知道应该怎么处理这个属性。下面以整型代码为例,说明处理的方法。
一般情况下,一个项目中会涉及许多种不同的代码,我们会为每一种代码定义一个主代码号(代码往往都是整型的),为它的子项定义几个子代码号。例如,我们定义性别的主代码号为 100,并定义男:1,女:2。
首先,需要一个代码标注(IntegerCode)及一个处理这种标注的 PropertyFilter。
@Documented@Target({ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)public @interface IntegerCode { public int value();}public class IntegerCodeFilter extends AbstractMethodFilter { // 代码处理器 private IntegerCodeProcessor _processor; public IntegerCodeFilter(final IntegerCodeProcessor processor) { _processor = processor; } // 不过滤属性,但当发现IntegerCode标注时,将数据传递给Processor public boolean apply(final Method method) { if (_processor == null) { return false; // 表示没有特别的处理 } if (method.isAnnotationPresent(IntegerCode.class)) { IntegerCode anno = method.getAnnotation(IntegerCode.class); int code = anno.value(); _processor.setMainCode(code); // 将code设置为主代码 } return false; }}
现在,我们需要一个 JsonValueProcessor 来处理 IntegerCode 数据。
public class IntegerCodeProcessor implements JsonValueProcessor { private int _iMainCode; public void setMainCode(final int mainCode) { _iMainCode = mainCode; } public IntegerCodeProcessor() { super(); } // END: IntegerCodeProcessor private void reset() { _iMainCode = -1; } public Object processArrayValue(Object value, JsonConfig jsonConfig) { return process(value, jsonConfig); } // END: processArrayValue public Object processObjectValue( String key, Object value, JsonConfig jsonConfig ) { return process( value, jsonConfig ); } // END: processObjectValue private Object process(Object value, JsonConfig jsonConfig) { if (value == null) { return null; } String ret = null; if (value instanceof Integer && _iMainCode >= 0) { int code = value.intValue(); switch (_iMainCode) { case 100: // 这里使用简单的case 处理不同的代码 if (code == 1) { // 好一点的方式是从资源文件中读取对应值 ret = "man"; } else if (code == 2) { ret = "woman"; } else { ret = value.toString(); } break; default: ret = value.toString(); break; } } else { ret = value.toString(); } reset(); // 处理后重置,以免影响其他 Integer 属性 return ret; } // END: process}
现在,我们创建一个 JavaBean:Student 来测试这个 Processor。
public class Student { private String name = "camry"; private int gender = 1; // getters & setters public String getName() { return name; } @IntegerCode(100) // 性别主代码为 100 public int getGender() { return gender; }}}...IntegerCodeProcessor processor = new IntegerCodeProcessor();IntegerCodeFilter filter = new IntegerCodeFilter(processor);JsonConfig config = new JsonConfig();config.setJsonPropertyFilter( filter );config.registerJsonValueProcessor(Integer.class, processor);System.out.println( JSONSerializer.toJSON( new Student(), config ) );// prints {“gender”:”man”, "name":"camry"}
回页首
Json-lib 可以很方便的进行 JavaBean 到 JSON 数据的转换,再结合 annotation 为 JavaBean 的属性定义元数据,可以减少代码,提高效率。
学习
“JSON 入门指南”(developerWorks,2008 年 8 月):本文将快速讲解 JSON 格式,并通过代码示例演示如何分别在客户端和服务器端进行 JSON 格式数据的处理。
“掌握 Ajax,第 10 部分: 使用 JSON 进行数据传输”(developerWorks,2007 年 4 月):讨论另一种有用的数据格式 JSON,以及如何使用它更轻松地在应用程序中移动数据和对象。
参考 JSON 主页,了解 JSON 数据格式的详细说明。
参考“Json-lib 主页”,了解 Json-lib 的实现与使用。
参考“Java 站点”,了解更多关于 annotation 的知识。
技术书店:浏览关于这些和其他技术主题的图书。
developerWorks Java 技术专区:数百篇关于 Java 编程各个方面的文章。
讨论
加入 My developerWorks 中文社区。
查看 developerWorks 博客 的最新信息。
吴浩,Fortinet 的高级软件工程师,有 10 年的 Java 编程经验。
回页首
JSON 的数据格式简单易读,它存在于两种基本形式:
名值对(Collection):名称与值用‘:’分开;名值对之间用‘,’分隔;整体用‘ {} '括起来。例如 {name1:value1, name2:value2}
值的有序队列(Array):即数组,每个值之间用‘,’分隔;整体用‘ [] '括起来。例如:[value1, value2]
这两种形式的有机组合,就形成了 JSON 数据。
回页首
Json-lib 是一个 java 工具库,它提供 api 来转换 JavaBean,Map,Collection 等对象为 JSON 数据,或反过来通过 JSON 数据得到 JavaBean。
Json-lib 的使用很容易,只要使用 JSONSerializer 的 toJSON 方法就可以转换任意的 Java Object 为 JSON 对象了,再调用 JSON 对象的 toString 方法可以得到转换后的字符串。不过还有一些进一步的问题需要我们自己来解决。
import net.sf.json.JSONSerializer;List list = new ArrayList(); list.add( "first" );list.add( "second" );JSON json = JSONSerializer.toJSON( list );System.out.println( json.toString() );// prints ["first","second"]class MyBean{ private String name = "json"; private int pojoId = 1; // getters & setters ...}json = JSONSerializer.toJSON( new MyBean() );System.out.println( json.toString() );// prints {"name":"json","pojoId":1}
清单 1 中的例子转换后的 JSON 数据中包含了 JavaBean 中的全部属性,可是我们常常需要有选择的提取 JavaBean 中的特定属性出来。例如:
需要过滤掉循环引用的属性,这一点 json-lib 提供了 CycleDetectionStrategy 来处理,但是直接过滤掉更简单;
不同的情况下只需要 JavaBean 中的部分属性:比如列表界面只需要显示 Bean 的几个重要属性,而详情界面则需要显示更多的 Bean 的属性;
不同的用户权限限制用户只能获得某些属性数据;
对于普通的 Object 类型(如 Long,String 等),json-lib 有缺省的值转换处理方式,但是对于一些特殊的类型,我们希望用自定义的方式来转换该属性的值。例如:
对于 java.util.Date 类型,我们希望直接转换成时间串:2010-04-10,而不希望得到一个类似 {"year":"2010","month":"4","day":"10"} 这样的结果
对于常用到的代码数据(比如:性别),在定义时它也许是个 Integer(男:1;女:2),我们希望在转换后直接得到:{"性别":"男",...},而不是 {"性别":"1",...}
Json-lib 已经预留出一些接口,让用户修改它的缺省行为。下面我们来看看如何利用 annotation 来配合 Json-lib 解决这两个问题。
回页首
JSONSerializer 提供了一个 toJSON 的重载方法,增加一个参数 JsonConfig,可以通过这个参数对 Json-lib 的缺省方式做自定义的配置。
import net.sf.json.JSONSerializer;import net.sf.json.JsonConfig;import net.sf.json.util.PropertyFilter;// 定义属性过滤器PropertyFilter filter = new PropertyFilter( public boolean apply(Object source, String name, Object value) { if ( name.equals( “pojoId” ) ) { return true; // 返回 true, 表示这个属性将被过滤掉 } return false; });// 注册属性过滤器JsonConfig config = new JsonConfig();config.setJsonPropertyFilter( filter );System.out.println( JSONSerializer.toJSON( new MyBean(), config ) );// prints {"name":"json"}
从清单 2 中可以看出来,Json-lib 通过 PropertyFilter 的 apply 方法进行属性过滤,可以象例子中一样,把所有需要过滤的属性名称写进去,但是这样做太烦琐,也不好维护,对不同的 Bean 要做不同的处理。下面让我们看看怎么利用 annotation 来更方便的处理。
首先,需要定义一个 annotation,并给 MyBean 的 get 方法加上标注。
import java.lang.annotation.Target;import java.lang.annotation.Documented;import java.lang.annotation.Retention;import java.lang.annotation.ElementType;import java.lang.annotation.RetentionPolicy;@Documented@Target({ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)public @interface Invisible { public String[] value();}// 为myBean中需要过滤的属性get方法(或者is方法)加上Invisible标注public class MyBean{ private String name = "json"; private int pojoId = 1; // getters & setters public String getName() { return name; } @Invisible(“LIST”) // 在 “LIST” 情况下不要这个属性 public int getPojoId() { return pojoId; }}
然后,我们需要一些能处理 annotation 的 PropertyFilter 类。
import java.util.Map;import java.lang.reflect.Method;import net.sf.json.util.PropertyFilter;// 先实现一个abstract类,将读取Bean属性的Method找到并传递给子类处理public abstract class AbstractMethodFilter implements PropertyFilter { // 这个方法留给子类实现,以便适应不同的过滤需求 public abstract boolean apply(final Method method); public boolean apply(final Object source, final String name, final Object value) { if (source instanceof Map) { return false; } String propName = name.substring(0, 1).toUpperCase() + name.substring(1); Class clz = source.getClass(); String methodName = "get" + propName; Method method = null; try { method = clz.getMethod(methodName, (Class[]) null); // 寻找属性的get方法 } catch (NoSuchMethodException nsme) { String methodName2 = "is" + propName; // 也许是个is方法 try { method = clz.getMethod(methodName2, (Class[]) null); } catch (NoSuchMethodException ne) { // 没有找到属性的get或者is方法,打印错误,返回true System.err.println(“No such methods: ” + methodName + “ or “ + methodName2); return true; } } return apply(method); }} // END: AbstractMethodFilterpublic class InvisibleFilter extends AbstractMethodFilter { // 过滤条件,标注中有符合这个条件的property将被过滤掉 private String _sGUIID; public InvisibleFilter(final String guiid) { _sGUIID = guiid; } public boolean apply(final Method method) { if (_sGUIID == null || _sGUIID.equals(“”)) { return false; // 表示不做限制 } if (method.isAnnotationPresent(Invisible.class)) { Invisible anno = method.getAnnotation(Invisible.class); String[] value = anno.value(); for (int i = 0; i < value.length; i++) { if (_sGUIID.equals(value[i])) { return true; } } } return false; }}
现在只要把这个 filter 注册到 JsonConfig 中,就实现了属性的过滤,请看清单 5。
JsonConfig config = new JsonConfig();config.setJsonPropertyFilter( new InvisibleFilter(“LIST”)); //标注了LIST的属性将被过滤掉System.out.println( JSONSerializer.toJSON( new MyBean(), config ) );// prints {"name":"json"}
增加其他的 annotation 及 Filter 就可以实现不同的属性过滤方式了。
回页首
Json-lib 通过 JsonConfig 提供了自定义属性转换方式的接口。
JsonConfig config = new JsonConfig();config.registerJsonValueProcessor(java.util.Date.class, new JsDateJsonValueProcessor());
注册后 Json-lib 在遇到 java.uitl.Date 类型的属性时,会应用 JsDateJsonValueProcessor 的处理方法。
所以,只要实现自己的 JsonValueProcessor 就可以自定义各种 Object 的转换方式了。
根据上一节的讨论,Json-lib 在转换 Bean 属性之前,会将属性数据传递给 PropertyFilter 来判断是否需要过滤掉。因此,我们可以通过一个 Filter 对象获得 Bean 的属性的标注数据,并将它传递给特定的 Processor,Processor 根据得到的标注值知道应该怎么处理这个属性。下面以整型代码为例,说明处理的方法。
一般情况下,一个项目中会涉及许多种不同的代码,我们会为每一种代码定义一个主代码号(代码往往都是整型的),为它的子项定义几个子代码号。例如,我们定义性别的主代码号为 100,并定义男:1,女:2。
首先,需要一个代码标注(IntegerCode)及一个处理这种标注的 PropertyFilter。
@Documented@Target({ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)public @interface IntegerCode { public int value();}public class IntegerCodeFilter extends AbstractMethodFilter { // 代码处理器 private IntegerCodeProcessor _processor; public IntegerCodeFilter(final IntegerCodeProcessor processor) { _processor = processor; } // 不过滤属性,但当发现IntegerCode标注时,将数据传递给Processor public boolean apply(final Method method) { if (_processor == null) { return false; // 表示没有特别的处理 } if (method.isAnnotationPresent(IntegerCode.class)) { IntegerCode anno = method.getAnnotation(IntegerCode.class); int code = anno.value(); _processor.setMainCode(code); // 将code设置为主代码 } return false; }}
现在,我们需要一个 JsonValueProcessor 来处理 IntegerCode 数据。
public class IntegerCodeProcessor implements JsonValueProcessor { private int _iMainCode; public void setMainCode(final int mainCode) { _iMainCode = mainCode; } public IntegerCodeProcessor() { super(); } // END: IntegerCodeProcessor private void reset() { _iMainCode = -1; } public Object processArrayValue(Object value, JsonConfig jsonConfig) { return process(value, jsonConfig); } // END: processArrayValue public Object processObjectValue( String key, Object value, JsonConfig jsonConfig ) { return process( value, jsonConfig ); } // END: processObjectValue private Object process(Object value, JsonConfig jsonConfig) { if (value == null) { return null; } String ret = null; if (value instanceof Integer && _iMainCode >= 0) { int code = value.intValue(); switch (_iMainCode) { case 100: // 这里使用简单的case 处理不同的代码 if (code == 1) { // 好一点的方式是从资源文件中读取对应值 ret = "man"; } else if (code == 2) { ret = "woman"; } else { ret = value.toString(); } break; default: ret = value.toString(); break; } } else { ret = value.toString(); } reset(); // 处理后重置,以免影响其他 Integer 属性 return ret; } // END: process}
现在,我们创建一个 JavaBean:Student 来测试这个 Processor。
public class Student { private String name = "camry"; private int gender = 1; // getters & setters public String getName() { return name; } @IntegerCode(100) // 性别主代码为 100 public int getGender() { return gender; }}}...IntegerCodeProcessor processor = new IntegerCodeProcessor();IntegerCodeFilter filter = new IntegerCodeFilter(processor);JsonConfig config = new JsonConfig();config.setJsonPropertyFilter( filter );config.registerJsonValueProcessor(Integer.class, processor);System.out.println( JSONSerializer.toJSON( new Student(), config ) );// prints {“gender”:”man”, "name":"camry"}
回页首
Json-lib 可以很方便的进行 JavaBean 到 JSON 数据的转换,再结合 annotation 为 JavaBean 的属性定义元数据,可以减少代码,提高效率。
学习
“JSON 入门指南”(developerWorks,2008 年 8 月):本文将快速讲解 JSON 格式,并通过代码示例演示如何分别在客户端和服务器端进行 JSON 格式数据的处理。
“掌握 Ajax,第 10 部分: 使用 JSON 进行数据传输”(developerWorks,2007 年 4 月):讨论另一种有用的数据格式 JSON,以及如何使用它更轻松地在应用程序中移动数据和对象。
参考 JSON 主页,了解 JSON 数据格式的详细说明。
参考“Json-lib 主页”,了解 Json-lib 的实现与使用。
参考“Java 站点”,了解更多关于 annotation 的知识。
技术书店:浏览关于这些和其他技术主题的图书。
developerWorks Java 技术专区:数百篇关于 Java 编程各个方面的文章。
讨论
加入 My developerWorks 中文社区。
查看 developerWorks 博客 的最新信息。
吴浩,Fortinet 的高级软件工程师,有 10 年的 Java 编程经验。
JSON的中文问题
签证页的annotation重要吗?
丝路智力辅助怎么用.?
我不小心用了辅助,结果.....
请证明青蛙用皮肤辅助呼吸
封神榜的辅助魔法要怎么用?
学托福用什么辅助教材好?
辅助查询的软件?复习用的??‘
鱼用什么呼吸,靠什么辅助?
宠物技能伐木辅助干什么用
适合大学生用的英语辅助教材?
change the style annotation character elegant appearance怎么翻译
不用任何辅助软件,如何知道其他人用的操作系统?
是不是一定要用辅助器材才能学好英语?
请问考大学英语4级用什么辅助资料好?
求希望OL辅助外挂哪有啊!要可以用的。。。
QQ幻想术士的辅助技能集中有什么用?
怎么自从我用了辅助器就回不去了
我的键盘辅助区用不了,为怎么呢?
热血江湖医生辅助技能都有什么用?
企业一般都有哪几种辅助帐簿,具体有什么用?
用MD录音需要配备些什么辅助设备
谁知道用辅助药物增长肌肉的方法
用一根烟怎么把烟盒弄断,火机做辅助作用!