`

用 annotation 辅助 Json-lib 转换 JavaBean

阅读更多

 概述

如今大量的 Web  站点应用了  AJAX  技术,通过更少的数据通讯,服务器能够更快的反馈用户请求,再通过  Javascript  的控制,让使用者有了更好的用户体验。 JSON  是一种轻量级的数据交换语言,它是  Javascript  的一个子集,又有良好的可读性,经常用于客户端和服务器间的数据交换。因此,在服务器端,常常需要将实体对象( JavaBean )转换为  JSON  格式数据。本文介绍了如何使用  Json-lib  转换  JavaBean  为  JSON  格式数据,并给出解决方法,以及利用  annotation  来增强  Json-lib  的两个功能:一是灵活的筛选  JavaBean  属性;二是通过  JsonValueProcessor  来自定义如何转换  JavaBean  属性到  JSON  数据。

 JSON 数据格式

JSON 的数据格式简单易读,它存在于两种基本形式:

·  名值对(Collection ):名称与值用 分开;名值对之间用 分隔;整体用 ‘ {}  '括起来。例如  {name1:value1, name2:value2}

·  值的有序队列(Array ):即数组,每个值之间用 分隔;整体用 ‘ []  '括起来。例如: [value1, value2]

这两种形式的有机组合,就形成了 JSON  数据。

使用 Json-lib  转换  JavaBean  为  JSON  数据

Json-lib 是一个  java  工具库,它提供  api  来转换  JavaBean Map Collection  等对象为  JSON  数据,或反过来通过  JSON  数据得到  JavaBean

Json-lib 的使用很容易,只要使用  JSONSerializer  的  toJSON  方法就可以转换任意的  Java Object  为  JSON  对象了,再调用  JSON  对象的  toString  方法可以得到转换后的字符串。不过还有一些进一步的问题需要我们自己来解决。


清单 1.  使用  JSONSerializer

              

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:  需要有选择的提取  JavaBean  中的属性

清单  中的例子转换后的  JSON  数据中包含了  JavaBean  中的全部属性,可是我们常常需要有选择的提取  JavaBean  中的特定属性出来。例如:

·  需要过滤掉循环引用的属性,这一点 json-lib  提供了  CycleDetectionStrategy  来处理,但是直接过滤掉更简单;

·  不同的情况下只需要 JavaBean  中的部分属性:比如列表界面只需要显示  Bean  的几个重要属性,而详情界面则需要显示更多的  Bean  的属性;

·  不同的用户权限限制用户只能获得某些属性数据;

问题 2:  需要自定义某些属性的转换方式

对于普通的 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  解决这两个问题。

 

 使用 annotation  筛选  JavaBean  属性

JSONSerializer 提供了一个  toJSON  的重载方法,增加一个参数  JsonConfig ,可以通过这个参数对  Json-lib  的缺省方式做自定义的配置。


 
清单 2.  自定义  JSONSerializer  的属性过滤器

              

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"}

 


 

从清单  中可以看出来, Json-lib  通过  PropertyFilter  的  apply  方法进行属性过滤,可以象例子中一样,把所有需要过滤的属性名称写进去,但是这样做太烦琐,也不好维护,对不同的  Bean  要做不同的处理。下面让我们看看怎么利用  annotation  来更方便的处理。

首先,需要定义一个 annotation ,并给  MyBean  的  get  方法加上标注。


 
清单 3.  定义一个  annotation: Invisible

              

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  类。


清单 4.  处理  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: AbstractMethodFilter

 

public 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


清单 5.  使用  InvisibleFilter  来过滤不需要的属性

              

JsonConfig config = new JsonConfig();

config.setJsonPropertyFilter( new InvisibleFilter(“LIST”)); //标注了 LIST 的属性将被过滤掉

 

System.out.println( JSONSerializer.toJSON( new MyBean(), config ) );

// prints {"name":"json"}

 


 

增加其他的 annotation  及  Filter  就可以实现不同的属性过滤方式了。

 

 使用 annotation  自定义  Bean  属性的转换方式

Json-lib 通过  JsonConfig  提供了自定义属性转换方式的接口。


清单 6.  注册  JsonValueProcessor


 

注册后 Json-lib  在遇到  java.uitl.Date  类型的属性时,会应用  JsDateJsonValueProcessor  的处理方法。

所以,只要实现自己的 JsonValueProcessor  就可以自定义各种  Object  的转换方式了。

根据上一节的讨论,Json-lib  在转换  Bean  属性之前,会将属性数据传递给  PropertyFilter  来判断是否需要过滤掉。因此,我们可以通过一个  Filter  对象获得  Bean  的属性的标注数据,并将它传递给特定的  Processor Processor  根据得到的标注值知道应该怎么处理这个属性。下面以整型代码为例,说明处理的方法。

一般情况下,一个项目中会涉及许多种不同的代码,我们会为每一种代码定义一个主代码号(代码往往都是整型的),为它的子项定义几个子代码号。 例如,我们定义性别的主代码号为 100 ,并定义男: 1 ,女: 2

首先,需要一个代码标注(IntegerCode )及一个处理这种标注的  PropertyFilter


 
清单 7. IntegerCode  及  IntegerCodeFilter

              

JsonConfig config = new JsonConfig();

config.registerJsonValueProcessor(java.util.Date.class, new JsDateJsonValueProcessor());

 

              

@Documented

@Target({ElementType.METHOD})

@Retention(RetentionPolicy.RUNTIME)

public @interface IntegerCode {

 

分享到:
评论
1 楼 mojunbin 2011-07-25  
为什么帖子显示不全啊

相关推荐

    json-lib-support-spring-源码.rar

    2. **配置和扩展**:在 Spring 的配置文件中,可以定义自定义的 `HttpMessageConverter` 实现,以便在处理请求和响应时使用 JSON-lib 进行数据转换。这可以通过在 `&lt;mvc:annotation-driven&gt;` 或 `&lt;bean&gt;` 元素中配置...

    springmvc-json-lib.rar

    在SpringMVC中,我们可以使用Jackson的`@ResponseBody`注解,将控制器方法的返回值自动转换为JSON格式。同时,通过`@RequestBody`注解,我们可以将HTTP请求体中的JSON数据自动映射到方法参数中。 配置Jackson库需要...

    javax.annotation-api-1.2-API文档-中文版.zip

    赠送jar包:javax.annotation-api-1.2.jar; 赠送原API文档:javax.annotation-api-1.2-javadoc.jar; 赠送源代码:javax.annotation-api-1.2-sources.jar; 赠送Maven依赖信息文件:javax.annotation-api-1.2.pom;...

    jakarta.annotation-api-1.3.5-API文档-中文版.zip

    赠送jar包:jakarta.annotation-api-1.3.5.jar; 赠送原API文档:jakarta.annotation-api-1.3.5-javadoc.jar; 赠送源代码:jakarta.annotation-api-1.3.5-sources.jar; 赠送Maven依赖信息文件:jakarta.annotation...

    jakarta.annotation-api-1.3.5-API文档-中英对照版.zip

    赠送jar包:jakarta.annotation-api-1.3.5.jar; 赠送原API文档:jakarta.annotation-api-1.3.5-javadoc.jar; 赠送源代码:jakarta.annotation-api-1.3.5-sources.jar; 赠送Maven依赖信息文件:jakarta.annotation...

    javax.annotation-api-1.3.2-API文档-中文版.zip

    赠送jar包:javax.annotation-api-1.3.2.jar; 赠送原API文档:javax.annotation-api-1.3.2-javadoc.jar; 赠送源代码:javax.annotation-api-1.3.2-sources.jar; 赠送Maven依赖信息文件:javax.annotation-api-...

    javax.annotation-api-1.3.2 jar包.rar

    在Java编程语言中,...通过深入理解和正确使用`javax.annotation-api-1.3.2.jar` 中提供的注解,开发者可以编写出更加简洁、可维护且易于扩展的代码,特别是在企业级Java应用开发中,注解的运用是不可或缺的一部分。

    javax.annotation-api-1.3.2-API文档-中英对照版.zip

    赠送jar包:javax.annotation-api-1.3.2.jar; 赠送原API文档:javax.annotation-api-1.3.2-javadoc.jar; 赠送源代码:javax.annotation-api-1.3.2-sources.jar; 包含翻译后的API文档:javax.annotation-api-...

    javax.annotation-api-1.3.2

    JDK9及以上版本没有javax.annotation-api-***.jar包 ,无法使用注解:@Resource JDK新特性,高版本JDK没有自带的javax...下载javax.annotation.jar包,导入到lib文件夹下,然后Add as library,就可以使用@Resource

    javax.annotation-api-1.2-API文档-中英对照版.zip

    赠送jar包:javax.annotation-api-1.2.jar; 赠送原API文档:javax.annotation-api-1.2-javadoc.jar; 赠送源代码:javax.annotation-api-1.2-sources.jar; 赠送Maven依赖信息文件:javax.annotation-api-1.2.pom;...

    javax.annotation-api-1.2.jar

    javax.annotation-api-1.2.jar包,注解,声明,@Resource是做bean的注入使用。

    mybatis-plus-annotation-3.2.0-API文档-中英对照版.zip

    赠送jar包:mybatis-plus-annotation-3.2.0.jar; 赠送原API文档:mybatis-plus-annotation-3.2.0-javadoc.jar; 赠送源代码:mybatis-plus-annotation-3.2.0-sources.jar; 赠送Maven依赖信息文件:mybatis-plus-...

    javax.annotation-api-1.3.jar

    @Resource注解所在的jar包 与@Autowired不同的是此注解是ByName进行依赖注入的

    mybatis-plus-annotation-3.5.1-API文档-中文版.zip

    赠送jar包:mybatis-plus-annotation-3.5.1.jar; 赠送原API文档:mybatis-plus-annotation-3.5.1-javadoc.jar; 赠送源代码:mybatis-plus-annotation-3.5.1-sources.jar; 赠送Maven依赖信息文件:mybatis-plus-...

    mybatis-plus-annotation-3.1.0-API文档-中文版.zip

    赠送jar包:mybatis-plus-annotation-3.1.0.jar; 赠送原API文档:mybatis-plus-annotation-3.1.0-javadoc.jar; 赠送源代码:mybatis-plus-annotation-3.1.0-sources.jar; 赠送Maven依赖信息文件:mybatis-plus-...

    mybatis-plus-annotation-3.5.1-API文档-中英对照版.zip

    赠送jar包:mybatis-plus-annotation-3.5.1.jar; 赠送原API文档:mybatis-plus-annotation-3.5.1-javadoc.jar; 赠送源代码:mybatis-plus-annotation-3.5.1-sources.jar; 赠送Maven依赖信息文件:mybatis-plus-...

    annotation-file-utilities.jar.zip

    在实际使用中,`annotation-file-utilities.jar`可能需要与其他构建工具(如Maven或Gradle)配合,通过指定依赖关系将其引入项目。开发者可以利用这个库提供的功能,编写更加高效和可维护的代码,同时减少手动配置和...

    mybatis-plus-annotation-3.1.0-API文档-中英对照版.zip

    赠送jar包:mybatis-plus-annotation-3.1.0.jar; 赠送原API文档:mybatis-plus-annotation-3.1.0-javadoc.jar; 赠送源代码:mybatis-plus-annotation-3.1.0-sources.jar; 赠送Maven依赖信息文件:mybatis-plus-...

    mybatis-generator-core-chinese-annotation-1.3.5-master.zip

    在描述中提到的"mybatis-generator-core-chinese-annotation-1.3.5-master.zip"是一个包含MBG中文注解版1.3.5版本的压缩包,旨在帮助开发者更方便地理解和使用这个工具。 MBG的核心功能在于根据数据库表自动生成...

    sentinel-annotation-aspectj-1.4.0.jar

    sentinel-annotation-aspectj-1.4.0.jar

Global site tag (gtag.js) - Google Analytics