Comment utiliser Spring RestTemplate et JAXB marshalling sur une URL qui renvoie plusieurs types de XML

J'ai besoin de faire un Repos POST pour un service qui renvoie une <job/> ou un <exception/> et toujours le code d'état 200. (lame de la 3e partie du produit!).

J'ai un code comme:

Job job = getRestTemplate().postForObject(url, postData, Job.class);

Et mon applicationContext.xml ressemble:

<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
    <constructor-arg ref="httpClientFactory"/>

    <property name="messageConverters">
        <list>
            <bean class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
                <property name="marshaller" ref="jaxbMarshaller"/>
                <property name="unmarshaller" ref="jaxbMarshaller"/>
            </bean>
            <bean class="org.springframework.http.converter.FormHttpMessageConverter"/>
            <bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
        </list>
    </property>
</bean>

<bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
    <property name="classesToBeBound">
        <list>
            <value>domain.fullspec.Job</value>
            <value>domain.fullspec.Exception</value>
        </list>
    </property>
</bean>

Lorsque je tente de faire cet appel et le service échoue, j'obtiens:

 Failed to convert value of type 'domain.fullspec.Exception' to required type 'domain.fullspec.Job'

Dans le postForObject (), je demande un Job.class et de ne pas en obtenir un, et c'est de s'énerver.

Je pense j'ai besoin d'être en mesure de faire quelque chose le long des lignes de:

Object o = getRestTemplate().postForObject(url, postData, Object.class);
if (o instanceof Job.class) {
   ...
else if (o instanceof Exception.class) {
}

Mais cela ne marche pas, car alors JAXB se plaint qu'il ne sait pas comment le maréchal de Object.class - il n'est pas surprenant.

J'ai tenté de créer la sous-classe de MarshallingHttpMessageConverter et remplacer readFromSource()

Objet protégé readFromSource(Classe clazz, HttpHeaders en-têtes, Source de source) {

    Object o = null;
    try {
        o = super.readFromSource(clazz, headers, source);
    } catch (Exception e) {
        try {
            o = super.readFromSource(MyCustomException.class, headers, source);
        } catch (IOException e1) {
            log.info("Failed readFromSource "+e);
        }
    }

    return o;
}

Malheureusement, cela ne marche pas parce que le sous-jacent inputstream à l'intérieur de la source a été fermé le temps que j'ai réessayer il.

Toutes les suggestions reçues avec gratitude,

Tom

Mise à JOUR: j'ai eu que cela fonctionne en prenant une copie de l'inputStream

protected Object readFromSource(Class<?> clazz, HttpHeaders headers, Source source) {
    InputStream is = ((StreamSource) source).getInputStream();

    //Take a copy of the input stream so we can use it for initial JAXB conversion
    //and if that fails, we can try to convert to Exception
    CopyInputStream copyInputStream = new CopyInputStream(is);

    //input stream in source is empty now, so reset using copy
    ((StreamSource) source).setInputStream(copyInputStream.getCopy());

    Object o = null;
    try {
        o = super.readFromSource(clazz, headers, source);
      //we have failed to unmarshal to 'clazz' - assume it is <exception> and unmarshal to MyCustomException

    } catch (Exception e) {
        try {

            //reset input stream using copy
            ((StreamSource) source).setInputStream(copyInputStream.getCopy());
            o = super.readFromSource(MyCustomException.class, headers, source);

        } catch (IOException e1) {
            e1.printStackTrace();  
        }
        e.printStackTrace();
    }
    return o;

}

CopyInputStream est pris de http://www.velocityreviews.com/forums/t143479-how-to-make-a-copy-of-inputstream-object.htmlje vais la coller ici.

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

public class CopyInputStream
{
private InputStream _is;
private ByteArrayOutputStream _copy = new ByteArrayOutputStream();

/**
 * 
 */
public CopyInputStream(InputStream is)
{
    _is = is;

    try
    {
        copy();
    }
    catch(IOException ex)
    {
        //do nothing
    }
}

private int copy() throws IOException
{
    int read = 0;
    int chunk = 0;
    byte[] data = new byte[256];

    while(-1 != (chunk = _is.read(data)))
    {
        read += data.length;
        _copy.write(data, 0, chunk);
    }

    return read;
}

public InputStream getCopy()
{
    return (InputStream)new ByteArrayInputStream(_copy.toByteArray());
}
}

source d'informationauteur Tom