2017-09-13 3 views
3

Je suis confronté à des problèmes auxquels je ne trouve pas non plus de solution (ou je m'attaque au mauvais sens). Lorsque certaines exceptions sont générées à partir de mon service, il semble que la sérialisation échoue. Il en résulte une exception encapsulée qui est pénible car les clients appelant reçoivent une erreur médiocre et j'imagine que je perds des informations utiles de l'exception originale. Dans l'exemple ci-dessous, il s'agit d'un problème d'accès au compartiment S3, mais j'ai rencontré des problèmes similaires avec certaines exceptions SQL.Échec de la sérialisation de l'exception Jax-ws

Il serait utile que je puisse garder mes services pour intervenir directement. L'idéal serait d'ajouter un code de sérialisation d'exception personnalisé.

> com.amazonaws.services.simpleworkflow.flow.DataConverterException: 
> Failure serializing 
> "com.sun.xml.internal.ws.fault.ServerSOAPFaultException: Client 
> received SOAP Fault from server: Access Denied (Service: Amazon S3; 
> Status Code: 403; Error Code: AccessDenied; Request ID: AAAAAAAAAAAA) 
> Please see the server log to find more detail regarding exact cause of 
> the failure." of type "class 
> com.sun.xml.internal.ws.fault.ServerSOAPFaultException" when mapping 
> key "null" at 
> com.amazonaws.services.simpleworkflow.flow.JsonDataConverter.throwDataConverterException(JsonDataConverter.java:90) 
> at 
> com.amazonaws.services.simpleworkflow.flow.JsonDataConverter.toData(JsonDataConverter.java:78) 
> at 
> com.amazonaws.services.simpleworkflow.flow.pojo.POJOActivityImplementation.throwActivityFailureException(POJOActivityImplementation.java:102) 
> at 
> com.amazonaws.services.simpleworkflow.flow.pojo.POJOActivityImplementation.execute(POJOActivityImplementation.java:67) 
> at 
> com.amazonaws.services.simpleworkflow.flow.generic.ActivityImplementationBase.execute(ActivityImplementationBase.java:46) 
> at 
> com.amazonaws.services.simpleworkflow.flow.worker.SynchronousActivityTaskPoller.execute(SynchronousActivityTaskPoller.java:196) 
> at 
> com.amazonaws.services.simpleworkflow.flow.worker.ActivityTaskPoller$2.run(ActivityTaskPoller.java:92) 
> at 
> java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) 
> at 
> java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) 
> at java.lang.Thread.run(Thread.java:748) Caused by: 
> com.fasterxml.jackson.databind.JsonMappingException: Type id handling 
> not implemented for type org.w3c.dom.Node (by serializer of type 
> com.fasterxml.jackson.databind.ext.DOMSerializer) (through reference 
> chain: 
> com.sun.xml.internal.ws.fault.ServerSOAPFaultException["fault"]) at 
> com.fasterxml.jackson.databind.SerializerProvider.mappingException(SerializerProvider.java:1084) 
> at 
> com.fasterxml.jackson.databind.JsonSerializer.serializeWithType(JsonSerializer.java:159) 
> at 
> com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:695) 
> at 
> com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:675) 
> at 
> com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeWithType(BeanSerializerBase.java:566) 
> at 
> com.fasterxml.jackson.databind.ser.impl.TypeWrappedSerializer.serialize(TypeWrappedSerializer.java:32) 
> at 
> com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:130) 
> at 
> com.fasterxml.jackson.databind.ObjectMapper._configAndWriteValue(ObjectMapper.java:3559) 
> at 
> com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:2927) 
> at 
> com.amazonaws.services.simpleworkflow.flow.JsonDataConverter.toData(JsonDataConverter.java:72) 
> ... 8 more 

Merci pour toutes suggestions

+0

Un grand merci @Kayaman –

+0

403 sur un service SOAP? Avec JSON? Quelque chose manque à votre question. Est-ce que vous mappez SOAP à JSON? – Namphibian

Répondre

1

Jackson tente de sérialiser une instance de com.sun.xml.internal.ws.fault.ServerSOAPFaultException. Cette exception est une sous-classe de javax.xml.ws.soap.SOAPFaultException, dont happens to have a getter for retrieving the SOAPFault. En tant que SOAPFault est un DOM Node, Jackson décide d'utiliser un DOMSerializer et aussi de coder les informations de type afin que, au moment de la désérialisation, il puisse trouver le type concret fault qui était une instance de. Le problème est que DOMSerializer ne prend pas en charge ce type d'information de type, de sorte que vous obtenez com.fasterxml.jackson.databind.JsonMappingException.

Je pense que la meilleure façon de contourner ce problème serait d'enregistrer une paire sérialiseur/désérialiseur personnalisée pour SOAPFault. Vous pouvez ensuite sérialiser à String s et désérialiser la création de nouvelles instances via l'un des SOAPFactory.createFault(...) methods. N'oubliez pas d'implémenter également JsonSerializer.serializeWithType(...) afin que Jackson puisse correctement gérer le type.

A (très approximative) projet serait

public class SOAPFaultSerializer extends StdSerializer<SOAPFault> { 

    public SOAPFaultSerializer() { 
     this(null); 
    } 

    public SOAPFaultSerializer(Class<SOAPFault> t) { 
     super(t); 
    } 

    @Override 
    public void serialize(SOAPFault fault, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException { 

     jgen.writeStartObject(); 
     // serialize "interesting" SOAPFault information 
     jgen.writeStringField("faultActor", fault.getFaultActor()); 
     jgen.writeStringField("faultCode", fault.getFaultCode()); 
     ... 
     jgen.writeEndObject(); 
    } 

    @Override 
    public void serializeWithType(JsonGenerator jgen, SerializerProvider provider, TypeSerializer typeSer) throws IOException, JsonGenerationException { 
     typeSer.writeTypePrefixForObject(this, jgen, SOAPFault.class); 
     serialize(value, jgen, provider); 
     typeSer.writeTypeSuffixForObject(this, jgen); 
    } 
} 

public class SOAPFaultDeserializer extends StdDeserializer<SOAPFault> { 

    public SOAPFaultDeserializer() { 
     this(null); 
    } 

    public SOAPFaultDeserializer(Class<?> vc) { 
     super(vc); 
    } 

    @Override 
    public SOAPFault deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { 
     JsonNode node = jp.getCodec().readTree(jp); 
     // deserialize "interesting" SOAPFault information 
     String faultActor = node.get("faultActor").asText(); 
     String faultCode = node.get("faultCode").asText(); 
     ... 
     SOAPFactory factory = SOAPFactory.newInstance(); 
     SOAPFault fault = factory.createFault(); 
     // fill in SOAPFault with deserialized fields 
     fault.setFaultActor(faultActor); 
     fault.setFaultCode(faultCode); 
     ... 
     return fault; 
    } 
} 
+0

Brillant, merci beaucoup de me mettre sur la bonne voie! –

+0

Vous êtes les bienvenus :) – gpeche

+0

Gardez à l'esprit que 'SOAPFactory.newInstance()' est susceptible d'être relativement coûteux, donc si vous avez besoin d'être performant, vous devriez essayer d'appeler cette méthode une seule fois et réutiliser l'instance de l'usine. – gpeche