I am working with Spring 4, together with Spring MVC.
I have the following POJO class
@XmlRootElement(name="person")
@XmlType(propOrder = {"id",...})
public class Person implements Serializable {
…
@Id
@XmlElement
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
…
}
If I want return a list of Person through Spring MVC in XML format, I have the following handler
@RequestMapping(value="/getxmlpersons/generic",
method=RequestMethod.GET,
produces=MediaType.APPLICATION_XML_VALUE)
@ResponseBody
public JaxbGenericList<Person> getXMLPersonsGeneric(){
logger.info("getXMLPersonsGeneric - getxmlpersonsgeneric");
List<Person> persons = new ArrayList<>();
persons.add(...);
…more
JaxbGenericList<Person> jaxbGenericList = new JaxbGenericList<>(persons);
return jaxbGenericList;
}
Where JaxbGenericList is (class declaration based on Generics)
@XmlRootElement(name="list")
public class JaxbGenericList<T> {
private List<T> list;
public JaxbGenericList(){}
public JaxbGenericList(List<T> list){
this.list=list;
}
@XmlElement(name="item")
public List<T> getList(){
return list;
}
}
When I execute the URL, I get the following error stack trace
org.springframework.http.converter.HttpMessageNotWritableException: Could not marshal [com.manuel.jordan.jaxb.support.JaxbGenericList@31f8809e]: null; nested exception is javax.xml.bind.MarshalException
- with linked exception:
[com.sun.istack.internal.SAXException2: class com.manuel.jordan.domain.Person nor any of its super class is known to this context.
javax.xml.bind.JAXBException: class com.manuel.jordan.domain.Person nor any of its super class is known to this context.]
But If I have this (class declaration not based on Generics):
@XmlRootElement(name="list")
public class JaxbPersonList {
private List<Person> list;
public JaxbPersonList(){}
public JaxbPersonList(List<Person> list){
this.list=list;
}
@XmlElement(name="item")
public List<Person> getList(){
return list;
}
}
and other handler method of course, as follows
@RequestMapping(value="/getxmlpersons/specific",
method=RequestMethod.GET,
produces=MediaType.APPLICATION_XML_VALUE)
@ResponseBody
public JaxbPersonList getXMLPersons(){
logger.info("getXMLPersonsSpecific - getxmlpersonsspecific");
List<Person> persons = new ArrayList<>();
persons.add(...);
…more
JaxbPersonList jaxbPersonList = new JaxbPersonList(persons);
return jaxbPersonList;
}
All work fine:
Question, what extra configuration I need to work in peace with only JaxbGenericList
Addition One
I did not configure a marshaller
bean, so I think Spring behind the scenes has provided one. Now according with your reply I have added the following:
@Bean
public Jaxb2Marshaller marshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setClassesToBeBound(JaxbGenericList.class, Person.class);
Map<String, Object> props = new HashMap<>();
props.put(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setMarshallerProperties(props);
return marshaller;
}
Something seems missing because I receive 'again':
org.springframework.http.converter.HttpMessageNotWritableException: Could not marshal [com.manuel.jordan.jaxb.support.JaxbGenericList@6f763e89]: null; nested exception is javax.xml.bind.MarshalException
- with linked exception:
[com.sun.istack.internal.SAXException2: class com.manuel.jordan.domain.Person nor any of its super class is known to this context.
javax.xml.bind.JAXBException: class com.manuel.jordan.domain.Person nor any of its super class is known to this context.]
Have you tried in a Web Environment? Seems I need tell Spring MVC use that marshaller
, I said seems because other URL working with not collections of POJO/XML works fine yet.
I am working with Spring 4.0.5 and Web environment is configured through Java Config
Addition Two
Your latest edition suggestion works
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(marshallingMessageConverter());
}
@Bean
public MarshallingHttpMessageConverter marshallingMessageConverter() {
MarshallingHttpMessageConverter converter = new MarshallingHttpMessageConverter();
converter.setMarshaller(jaxbMarshaller());
converter.setUnmarshaller(jaxbMarshaller());
return converter;
}
But now my XML not generic and JSON code fails.
For my other XML URL
http://localhost:8080/spring-utility/person/getxmlpersons/specific
HTTP Status 406 -
type Status report
message
description The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request "accept" headers.
It has been fixed adding or updating:
from:
marshaller.setClassesToBeBound(JaxbGenericList.class, Person.class);
to:
marshaller.setClassesToBeBound(JaxbGenericList.class, Person.class, JaxbPersonList.class);
But for JSON, other URL http://localhost:8080/spring-utility/person/getjsonperson
again
HTTP Status 406 -
type Status report
message
description The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request "accept" headers.
Seems I need add a converter for JSON (I did not define before), I have used the Spring defaults, could you give me a hand please?