用string adapter来解决系统接口对接中发现的空值验证问题

分享到:

客户用的是很旧版本的ERP系统,在与客户系统做接口对接的时候发现了一个问题。假设接口请求需要的body是xml格式的,共有三个字段:name, mobile, email。由于客户ERP系统比较老,如果某个字段没有值,传的是空字符串,而不是将该字段在请求消息体中隐藏。客户发的请求类似下面的例子:

1<xml>
2    <name>John</name>
3    <mobile>13800138000</mobile>
4    <email></email>
5</xml>

由于历史遗留问题,我方系统里在字段上面加了 javax.validation.constraints.Pattern 注解使用正则表达式来对传入的请求值做验证。当传入值为空字符串的时候,正则表达式验证就无法通过。

与客户做过沟通,对于空值的字段,他们也没有办法在请求中隐藏字段,只能传空字符串。那就只能在我方系统这边看看是否可以通过修改代码来解决。一种方案是修改正则表达式,来兼容空字符串,但是由于这些都是传统代码,不确定把空字符串设置在这个字段上面会对后面的处理会有什么影响。如果有更合适的、代价更小的方案,那么就最好不选择这种。

 1@XmlType
 2@XmlAccessorType(XmlAccessType.FIELD)
 3public class TestRequest implements Serializable {
 4    @XmlElement(required = true)
 5    private String name;
 6
 7    @XmlElement(required = false)
 8    @Pattern(regexp = Constants.regexpMobile, message = "invalidMobile")
 9    private String mobile;
10
11    @XmlElement(required = false)
12    @Pattern(regexp = Constants.regexpEmail, message = "invalidEmail")
13    private String email;
14
15    // getter / setter
16    ...
17}

通过查阅相关资料,发现 javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter 注解可以达到目的。这个注解可以指定一个类,用于转换与处理xml请求中的字段值。这样,我们只需要自定义一个类,将传入空字符串值转换成null

首先,先定义一个XmlAdapter类

 1public class MyXmlStringAdapter extends XmlAdapter<String, String> {
 2
 3    @Override
 4    public String marshal(String value) throws Exception {
 5        if ("".equals(value)) {
 6            return null;
 7        }
 8
 9        return value;
10    }
11
12    @Override
13    public String unmarshal(String value) throws Exception {
14        if ("".equals(value)) {
15            return null;
16        }
17
18        return value;
19    }
20
21}

然后,在相应的字段上面,使用前面定义好的XmlAdapter类。这样,xml解析器在转换请求的时候,会将空字符串转换成null,这样就认为该字段没有传值,不使用正则表达式做验证。

 1@XmlType
 2@XmlAccessorType(XmlAccessType.FIELD)
 3public class TestRequest implements Serializable {
 4    @XmlElement(required = true)
 5    private String name;
 6
 7    @XmlElement(required = false)
 8    @Pattern(regexp = Constants.regexpMobile, message = "invalidMobile")
 9    @XmlJavaTypeAdapter(value = MyXmlStringAdapter.class, type = String.class)  // Use MyXmlStringAdapter
10    private String mobile;
11
12    @XmlElement(required = false)
13    @Pattern(regexp = Constants.regexpEmail, message = "invalidEmail")
14    @XmlJavaTypeAdapter(value = MyXmlStringAdapter.class, type = String.class)  // Use MyXmlStringAdapter
15    private String email;
16
17    // getter / setter
18    ...
19}