1、空值转换-异常情况:
解决方法,在ObjectMapper配置中增加:
2、转义字符-异常情况:
解决办法,在ObjectMapper配置中增加:
这里先简单的做下jackson的介绍:jackson可以很方便并且高效的将json对象转化成java对象,也可以将java对象转换成json对象和xml文档。Jackson有几个显著的特点:性能高,对于复杂对象和大数据量对象的序列化和反序列化,表现出比同类工具包(如gson,json-lib等)更优的性能;功能强,绑定所有JDK中的通用类以及Java Bean Class,Collection,Map和Enum;无依赖,除了JDK外无任何他依赖;完全开源,并且有丰富的文档和用户群体,便于自学。
在进行http请求的接口测试的过程中,我们需要灵活方便的处理http请求返回数据,使json串反序列化成为java对象,这样我们才能方便地对返回数据进行校验。如何试用jackson进行反序列化,网上内容很多,所以在此补赘述。我想重点说下在接口测试过程中需要注意的点和可能会遇到的问题的解决办法。
【注意点1】: 尽可能使用开发人员使用的数据对象类作为反序列化时的mapper类。
通常情况下,浏览器在发送http请求向服务端应用请求数据的时候,客户端应用都会依赖一个服务端的client包,以便于反序列化json数据后,形成用于vm模板的渲染所需要的java对象。这样就为我们测试http接口提供了便利,我们只需要在我们测试应用中依赖这个client的jar包,就可以方便的运用这些对象去组装我们的mapper。
【注意点2】: 当开发人员提供的数据对象类“不好用”的时候,需要自行创建pojo类,或者使用JDK的原生数据对象。
ObjectMapper初始化配置的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
ObjectMapper objectMapper =
new
ObjectMapper();
//配置为true表示mapper接受只有一个元素的数组的反序列化
objectMapper.configure(Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY,
true
);
//配置为false表示mapper在遇到mapper对象中存在json对象中没有的数据变量时不报错,可以进行反序列化
objectMapper.configure(Feature.FAIL_ON_UNKNOWN_PROPERTIES,
false
);
//新版的jackson设置mapper的方法,功能同上
objectMapper.getDeserializationConfig().without(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES);
//定义针对日期类型的反序列化时的数据格式
objectMapper.getDeserializationConfig().setDateFormat(
new
SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss"
));
|
下面是处理json的工具类代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
public
static
if
(jsonString ==
null
||
""
.equals(jsonString)) {
return
null
;
}
else
{
try
{
return
(T) objectMapper.readValue(jsonString, tr);
}
catch
(Exception e) {
e.printStackTrace();
}
}
return
null
;
}
|
此方法采用了泛型,是为了抽象json返回对象的数据类型,以便后续开发通用的测试验证类
下面是调用类的方法的代码:
1
|
actDO = JsonUtils.getObjectFromJsonString(jsonStr,
new
TypeReference
|
或者
1
|
actDO = JsonUtils.getObjectFromJsonString(jsonStr,
new
TypeReference
|
下面是BaseResponseModel的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
public
class
BaseResponseModel
implements
Serializable{
private
static
final
long
serialVersionUID = 5393610697317077173L;
private
List
private
boolean
isSuccess;
private
String errorMsg;
private
int
errorCode;
private
Integer total;
public
boolean
isSuccess() {
return
isSuccess;
}
public
void
setIsSuccess(
boolean
isSuccess) {
this
.isSuccess = isSuccess;
}
//其余getter/setter省略
}
|
BaseResponseModel封装了http请求返回的通用成员变量,例如:ErrorCode,IsSuccess,Total等
Mapper对象实例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
public
class
InfoAndRateMapper
implements
Serializable{
private
static
final
long serialVersionUID = 1L;
private
List
private
List
public
List
return
info;
}
public
void
setInfo(List
this
.info = info;
}
public
List
return
rate;
}
public
void
setRate(List
this
.rate = rate;
}
}
|
经常碰到的问题及解决办法:
Unrecognized field “INFO” (Class com.tmall.brand.api.test.model.InfoAndRateMapper), not marked as ignorable
【异常解释】:当反序列化的json对象中有“INFO”,但mapper对象中没有该字段时报错。
【解决办法】:在mapper中增加此变量
Unrecognized field “typeString”
【异常解释】:反序列化过程中出现不可识别的成员变量
【解决办法】:增加mapper的属性配置:objectMapper .configure(Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);此参数默认是true,即检查映射关系,当设置为false以后,objectMapper将忽略需解析的json串中“不认识”的字段
例如:mapper对象中有private String name;的对象,当json对象中并没有此变量,那当这个属性值设置为false时,可成功反序列化。
org.codehaus.jackson.map.JsonMappingException : Can not instantiate value of type [collection type; class java.util.ArrayList, contains [simple type, class java.lang.Long]] from JSON String; no single-String constructor/factory method (through reference chain: com.tmall.brand.api.test.model.GetInfoAndRateRespModel["result"]->com.tmall.brand.api.test.model.InfoAndRateMapper["INFO"]->com.tmall.brand.service.domain.ratenews.BrandNewsQuery["typeList"])
【异常解释】:jackson无法实例化json对象中变量类型的值
【解决办法】:@JsonIgnoreProperties({ “typeList”})
在mapper类之前加此标签忽略这个字段的反序列化
Can not deserialize instance of java.util.ArrayList out of START_OBJECT token
【异常解释】:无法反序列化没有START_OBJECT token的ArrayList
【解决办法】:增加mapper的属性配置:
1
|
objectMapper .configure(Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY,
true
);
|
org.codehaus.jackson.map.JsonMappingException : No suitable constructor found for type [simple type, class com.taobao.matrix.snsplugin.common.enumconstants.EnumResultStatus]: can not instantiate from JSON object (need to add/enable type information?)
at [Source: java.io.StringReader@98350a; line: 1, column: 89] (through reference chain: com.tmall.brand.api.test.model.BaseResponseModel["result"]->com.tmall.brand.api.test.model.PublishCommentResultMapper["status"])
【异常解释】:jackson无法实例化json对象,没有找到适合的构造函数。
【解决办法】:jackson在进行反序列号的时候,需要Mapper类是普通的pojo类,并且类中的变量都需要有setXXX的set方法,如果没有set方法或者没有“正确”的set方法,就会报无法实例化JSON对象的异常
例如:
1、json对象的一个变量为
1
|
private
boolean isSuccess;
|
自动生成代码后的set方法为:(根据你自己的eclipse 的autogen来决定自动生成的代码模板)
1
2
3
4
5
|
public
void
setSuccess( boolean isSuccess) {
this
. isSuccess = isSuccess;
}
|
如果是这样,jackson在反序列化的时候就会报此异常,应改为:
1
2
3
4
5
|
public
void
setIsSuccess( boolean isSuccess) {
this
. isSuccess = isSuccess;
}
|
2、当JSON对象为:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
public
class
XXXStatus
extends
XXXResultStatus
private
static
final
long serialVersionUID = 2385584133823877965L;
public
static
final
Map
new
HashMap
public
static
final
XXXStatus SUCCESS =
new
XXXStatus(
0
,
"xxx"
,
"xxx"
);
....
private
XXXStatus(
int
code,
String
msg,
String
frontMsg) {
super
(code, msg, frontMsg);
codeMap.put(code,
this
);
}
public
static
final
XXXStatus getRelationStatus(
int
code) {
XXXStatus satus = codeMap.
get
(code);
if
(satus ==
null
) {
return
SYSTEM_ERROR;
}
return
satus;
}
}
|
同样没有set方法,所以这样的JSON对象都需要重新创建一个自定义的mapper对象,用于jackson反序列化