我正在为一家公司进行项目改造,他们希望在前端/客户端和后端/服务器之间拆分系统(更像是前端和数据库服务器之间的中间人),我应该使用JAX-WS RPC并维护当前的功能。
通过维护功能,它们意味着一些方法应该返回null,这是WS-I所禁止的。
在寻找可能的解决方案时,我偶然发现了这篇文章:http://victor-ichim.blogspot.com.br/2011/03/rpcliteral-and-null-object-pattern.html它通过使用EJB拦截器来拦截空结果并用空对象替换空结果,基本上解决了类似的问题。
围绕这个概念,我想像这样截取结果,用字符串模板之类的东西替换null,在客户端上再次截取它,然后用null替换回该模板。
我的问题是:
- 它们默认不使用EJB,因此本身没有拦截器。是否有一些实现可以同时适用于Tomcat和JBoss?
- 即使我能够在服务器端拦截返回,我怎么能在客户端完成呢
- 如果我可以使用SOAPHandlers,我如何避免由于试图返回null而引发SOAP Fault
由于我也遇到了JAXB不处理接口的问题,所以我最终使用@XmlJavaTypeAdapter
注释来启用(有选择地,因为实际上可能为null的每个返回和参数都需要注释)将值从null转换回null,这有点像黑客作业。我为Serializable
对象创建了一个通用的ish适配器,并对其他类型的Object
对象采用了相同的方法:
public class SerializableAdapter extends XmlAdapter<String, Serializable>>{
private static final String NULL = "'NULL'"; // Will hopefully never collide
@Override
public Serializable unmarshal(String e) throws Exception {
if (e == NULL) {
return null;
}
byte [] eB = e.getBytes("ISO-8859-1");
InputStream iS = new ByteArrayInputStream(Base64.getDecoder().decode(eB));
ObjectInputStream oIS = new ObjectInputStream(iS);
return (Serializable) oIS.readObject();
}
@Override
public String marshal(Serializable o) throws Exception {
if (o == null) {
return NULL;
}
ByteArrayOutputStream bAOS = new ByteArrayOutputStream();
ObjectOutputStream oOS = new ObjectOutputStream(bAOS);
oOS.writeObject(o);
return Base64.getEncoder().encodeToString(bAOS.toByteArray());
}
}
然后用@XmlJavaTypeAdapter(SerializableAdapter.class)
对每个Serializable
实例进行注释,因为使用包级别的@XmlJavaTypeAdapters
由于某些原因而不起作用,等等。JAXB在调用适配器时似乎急切地将编码的类型转换为和转换为,因此即使要编组的对象不是预期类/接口的实例,它也会编译得很好,并且只在运行时抛出异常。
我不建议这样做,因为它需要注释每一个方法/参数或包,并且会在第一个没有注释但收到null的方法/参数包处中断这个适配器仍然适用于我需要使用接口的情况,并且实现类也实现了Serializable,尽管有些情况仍然需要特定的适配器,但这通常是经过深思熟虑的代码。
部分原因是这很麻烦,加上注释所有内容的麻烦,我设法说服公司放弃SOAP RPC绑定,所以我可以在没有这一点的情况下使用null参数和返回。