【问题标题】:Custom validation error messages using Jaxb2marshaller and spring-ws使用 Jaxb2marshaller 和 spring-ws 自定义验证错误消息
【发布时间】:2012-08-06 19:55:14
【问题描述】:

我有一个正在运行的 spring-ws 项目,它可以使用 Jax2b 解组请求,但是当整数/布尔值的解组失败时,我会收到一条没有详细信息且通常没有无效元素名称的错误消息。例如:

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'.]

这也成为来自我的网络服务的 SOAPFault 响应的内容。

我正在尝试更改消息以包含元素名称。我正在使用 ValidationEventHandler 通过从事件处理程序中抛出 RuntimeException 来更改消息,但它仅在某些情况下有效。

ValidationEventHandler:

@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)

Jaxb2Marshalling 的 Spring 配置:

<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?

谢谢!

【问题讨论】:

  • 我没有找到解决这个问题的好方法。由于它在当前应用程序中是一个非关键问题,并且可以在日志中看到验证失败的元素的名称。我已经决定不再继续下去了……仍然欢迎提出建议!

标签: spring-ws jaxb2 unmarshalling xml-validation


【解决方案1】:

我终于找到了解决这个问题的方法。我没有从 ValidationEventHandler 中抛出一个新的 RuntimeException,而是将其添加为事件链接异常的抑制异常:

event.getLinkedException().addSuppressed(new RuntimeException(errorMessage));

在 Endpoint 中,我将 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();

这不是一个优雅的解决方案,但端点会产生比以前更好的错误消息。

【讨论】:

    【解决方案2】:

    您是否尝试过使用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

    【讨论】:

    • 谢谢。好久没看了,不过我会尽快试试看的。
    • 我的屏幕上可能有一个搜索结果,其中不包含最近的问题。抱歉挖了旧东西;)
    • 我查看了我的“旧东西”,发现我已经尝试使用自定义 PayloadValidatingInterceptor 来验证传入的请求。我不能说这是否是一个死胡同,但我运气不好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-19
    • 1970-01-01
    • 1970-01-01
    • 2016-04-18
    • 2016-12-04
    • 1970-01-01
    相关资源
    最近更新 更多