Capturando erros de parser no XmlJavaTypeAdapter

Em uma manutenção em um webservices SOAP identifiquei um comportamento curioso do framework que faz parsing de xml, um comportamento que facilita no desenvolvimento mas pode ocasionar em problemas na consistência dos dados.

Quando utilizamos um conversor através da anotação @XmlJavaTypeAdapter e ocorre algum erro dentro desse conversor esse erro não para todo processo e apenas não retorna o valor da Tag com problema, deixando o valor como nulo.

Fiz os testes no cenário, utilizando webservice SOAP com a implementações do próprio java (javax.xml.ws).

Para conseguir capturar esses erros que ocorrem na fase de parse do xml, é preciso ativar SchemaValidation do webservice, para que ele possa criticar inconsistências(conversões, formatações, estruturas) durante o processo da requisição. Isso ocorre porque na fase de parse, o framework apenas notifica os erros de conversões ou formatações para uma lista de eventos (ValidationEvent).

A solução que encontrei para capturar apenas os erros de conversões e não toda estrutra do wsdl, foi a criação de um Handler que notifica quando o ocorre exception do tipo SAXParseException, que são as exceptions que ocorrem durante o processamento de parse.

public class SchemaValidationErrorHandler extends ValidationErrorHandler {

  public static final String WARNING = "SchemaValidationWarning";
  public static final String ERROR = "SchemaValidationError";
  public static final String FATAL_ERROR = "SchemaValidationFatalError";

  public void warning(SAXParseException exception) {
    packet.invocationProperties.put(WARNING, exception);
  }

  public void error(SAXParseException exception) {
    packet.invocationProperties.put(ERROR, exception);
 }

  public void fatalError(SAXParseException exception) {
    packet.invocationProperties.put(FATAL_ERROR, exception);
  }
}

O Handler simplesmente captura a SAXParseException e adiciona no atributo packet, que é um atributo que armazena informações de mensagens dentro do contexto do webservice.

Após a criação do hadler é preciso ativar a validação na classe do webservice

@WebService(serviceName = "OrdemServico", name = "OrdemServico")
@SchemaValidation(handler = SchemaValidationErrorHandler.class) 
public class Endpoint {
}

Com isso, as exceções durante o parser estarão sendo capturadas, agora é preciso recuperar elas no método do webservice para retornar o erro no WS.

private RespostaOrdemServicoCompleto validarParseException() {
  final MessageContext messageContext = wsContext.getMessageContext();
  final Object erroValidacao = messageContext.get(SchemaValidationErrorHandler.ERROR);
  if(erroValidacao != null) {
    final SAXParseException exceptionValidacao = (SAXParseException) erroValidacao;
    String message = exceptionValidacao.getMessage();
    if(message.startsWith(XML_VALIDATION_ERROR_CVC_TYPE_3_1_3)) {
       return RespostaOrdemServicoCompleto.falha(message.contains("cvc") ? message.substring(message.indexOf(":"), message.length()) : message);
    }
  }
  return null;
}

Método para capturar erros de validação de XML, naturalmente o JAXB faz essa validações, mas não retorna para próxima camada. Durante as validações são geradas SAXParseException, referentes aos erros encontrados no XMLs.

Esse método trata apenas erros de validações do tipo cvc-type-3-1-3, que são erros de conversões de tipo de dados.

Após criado o método que captura os erros de validação, agora é apenas utilizar no método do endPoint:

@WebMethod(operationName = "ordemServico")
public RespostaOrdemServicoCompleto ordemServico(
			@WebParam(name = "dn") String dn,
			@WebParam(name = "token") String token,
			@WebParam(name = "dadosOrdemServico") OrdemServicoCompletoTO dadosOrdemServico) {

  final RespostaOrdemServicoCompleto message = validarParseException();

  if (message != null) {
    return message;
  }
     
   processar(dadosOrdemServico);
   return RespostaOrdemServicoCompleto.sucesso(dadosOrdemServico);
}

Injetando o contexto do webService, é possível pegar o método getMessageContext que contem as exceções que foram lançadas no packet (dentro do ValidationHandler) e direcionar para o retorno do WS.

Achei um pouco trabalhosa essa forma de recuperar os erros durante a fase de parse do framework, mas na minha opinião, isso ocorre porque nos beneficiamos da facilidade de realizar o parse através de uma classe configurada @XmlRootElement, então quando é preciso utilizar algo fora do tradicional do framework é um pouco mais trabalhoso.

Anúncios

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.