Мне нужно сделать Rest POST для службы, которая возвращает либо <job/>
, либо <exception/>
и всегда код состояния 200
. (хромой сторонний продукт!).
У меня есть код вроде:
Job job = getRestTemplate().postForObject(url, postData, Job.class);
И мой applicationContext.xml выглядит так:
<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>
Когда я пытаюсь сделать этот вызов и служба терпит неудачу, я получаю:
Failed to convert value of type 'domain.fullspec.Exception' to required type 'domain.fullspec.Job'
В вызове postForObject() я запрашиваю Job.class и не получаю его, и он расстраивается.
Я думаю, что мне нужно что-то сделать в соответствии с:
Object o = getRestTemplate().postForObject(url, postData, Object.class);
if (o instanceof Job.class) {
...
else if (o instanceof Exception.class) {
}
Но это не работает, потому что тогда JAXB жалуется, что он не знает, как маршалировать Object.class - не удивительно.
Я попытался создать подкласс MarshallingHttpMessageConverter и переопределить readFromSource()
защищенный объект readFromSource (класс clazz, заголовки HttpHeaders, источник источника) {
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;
}
К сожалению, это не работает, потому что основной входной поток внутри источника был закрыт к моменту его повторного запуска.
Любые предложения, полученные с благодарностью,
Tom
ОБНОВЛЕНИЕ: у меня есть это для работы, взяв копию 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 берется из http://www.velocityreviews.com/forums/t143479-how-to-make-a-copy-of-inputstream-object.html, я вставляю его здесь.
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());
}
}