我有一个运行的spring-ws项目,它可以使用Jax2b解组请求,但是当整数/布尔值的解组失败时,我得到一条错误消息,其中包含很少的细节,通常没有无效元素的名称。 E.g:
org.springframework.oxm.UnmarshallingFailureException: JAXB unmarshalling exception; nested exception is javax.xml.bind.UnmarshalException
- with linked exception:
[org.xml.sax.SAXParseException; cvc-datatype-valid.1.2.1: '' is not a valid value for 'integer'.]
这也成为我的webservice的SOAPFault响应的内容。
我正在尝试更改消息以包含元素名称。我正在使用ValidationEventHandler通过从事件处理程序抛出RuntimeException来更改消息,但它仅在某些情况下有效。
@Component
public class ValidationEventHandlerImpl implements ValidationEventHandler {
@Override
public boolean handleEvent(ValidationEvent event) {
String message = event.getMessage();
String linkedMessage = "";
if(event.getLinkedException() != null)
linkedMessage = event.getLinkedException().toString();
boolean ignoreValidationEvent = true;
if(message.contains("NumberFormatException") ||
message.contains("is not a valid value") ||
linkedMessage.contains("NumberFormatException") ||
linkedMessage.contains("is not a valid value")){
ignoreValidationEvent = false;
}
if(ignoreValidationEvent){
return true;
}else{
String nodeName = "";
if(event.getLocator() != null && event.getLocator().getNode() != null)
nodeName = event.getLocator().getNode().getNodeName();
//This is the important line
throw new RuntimeException("Error parsing '" + nodeName + "': " + event.getMessage());
}
}
}
JAXB unmarshalling exception; nested exception is javax.xml.bind.UnmarshalException: Not a number: 32g321
- with linked exception:
[java.lang.NumberFormatException: Not a number: 32g321]
to: RuntimeException消息:“ java.lang.RuntimeException:解析'MyNodeName'时出错:不是数字:32g321 ”
(事件严重性:错误)
JAXB unmarshalling exception; nested exception is javax.xml.bind.UnmarshalException
- with linked exception:
[org.xml.sax.SAXParseException; cvc-datatype-valid.1.2.1: '' is not a valid value for 'integer'.]
to: RuntimeException消息:“ java.lang.RuntimeException:解析'MyNodeName'时出错:''不是'integer'的有效值”。
忽略RuntimeException并抛出SAXParseException并将其添加到SOAPFault响应中。
(事件严重性:FATAL_ERROR)
<bean id="jaxb2MarshallerContact" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>com.model.oxm.ContactRequest</value>
<value>com.model.oxm.ContactResponse</value>
</list>
</property>
<property name="marshallerProperties">
<map>
<entry>
<key>
<util:constant static-field="javax.xml.bind.Marshaller.JAXB_FORMATTED_OUTPUT" />
</key>
<value type="boolean">true</value>
</entry>
<entry>
<key>
<util:constant static-field="javax.xml.bind.Marshaller.JAXB_FRAGMENT" />
</key>
<value type="boolean">true</value>
</entry>
</map>
</property>
<property name="schema" ref="ContactServiceSchema" />
<property name="validationEventHandler" ref="validationEventHandlerImpl" />
</bean>
<bean id="ContactServiceSchema" class="org.springframework.core.io.ClassPathResource">
<constructor-arg value="WEB-INF/schemas/ContactService.xsd" />
</bean>
@Endpoint
public class ContactEndpoint {
private Logger logger = Logger.getLogger(ContactEndpoint.class);
@Autowired
private ContactService contactService;
private static final String NAMESPACE_URI = "http://mydomain/schemas";
@PayloadRoot(namespace = NAMESPACE_URI, localPart = "ContactRequest")
@ResponsePayload
public ContactResponse handleContactRequest(@RequestPayload ContactRequest contactRequest) throws Exception {
...
如何返回自定义消息而不是SAXParseException消息?
有没有更好的方法来实现这一点,例如使用ValidationErrorHandler?
谢谢!
答案 0 :(得分:2)
我终于找到了解决这个问题的方法。我没有从ValidationEventHandler中抛出一个新的RuntimeException,而是将它作为一个被抑制的异常添加到事件链接异常上:
event.getLinkedException().addSuppressed(new RuntimeException(errorMessage));
在端点我改变了RequestPayload的soapenvelope。 marshallingService包装了jax2bmarshaller:
@PayloadRoot(namespace = NAMESPACE_URI, localPart = "ContactRequest")
@ResponsePayload
public ContactResponse handleContactRequest(@RequestPayload SoapEnvelope soapEnvelope) throws Exception {
ContactRequest contactRequest = marshallingService.unmarshalContact(soapEnvelope.getBody().getPayloadSource());
marshallingService捕获异常,提取我的被抑制的异常消息并抛出它:
((UnmarshalException) xmlMappingException.getCause()).getLinkedException().getSuppressed()[0].getLocalizedMessage();
这不是一个优雅的解决方案,但端点产生的错误消息比以前好得多。
答案 1 :(得分:1)
您是否尝试过使用PayloadValidatingInterceptor
?据我所知,这将在解组之前验证消息。也许这会让你更深入地了解出了什么问题。
您只需在应用程序配置中进行设置:
private ClassPathResource yourXsdFile = new ClassPathResource("xsd.xsd");
@Bean
public PayloadValidatingInterceptor validatingInterceptor() {
PayloadValidatingInterceptor interceptor = new PayloadValidatingInterceptor();
interceptor.setSchema(yourXsdFile);
interceptor.setAddValidationErrorDetail(true);
return interceptor;
}
@Bean
public PayloadRootAnnotationMethodEndpointMapping endpointMapping() {
PayloadRootAnnotationMethodEndpointMapping mapping = new PayloadRootAnnotationMethodEndpointMapping();
mapping.setInterceptors(new EndpointInterceptor[]{
validatingInterceptor()
});
return mapping;
}
有关详细信息,请查看api docs。