JAX-RS response for XML or JSON not working

I have the following GenericRest class that I use to extend leisure classes that are based on Entity classes annotated with @XmlRootElement.

public class GenericRest<T extends BaseEntity> { @Inject @Service GenericService<T> service; public GenericService<T> getService() { return service; } @GET @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Response getAll() { // This works for JSON but does not work for XML Requests. List<T> list = getService().findAll(); // This just gives the attributes for the BaseEntity. //GenericEntity<List<T>> list = new GenericEntity<List<T>>(getService().findAll()) {}; return Response.ok(list).build(); } } 

APPLICATION_JSON works fine in the current situation without commenting, but APPLICATION_XML gives an error:

Could not find MessageBodyWriter for response object of type: java.util.ArrayList of media type: application / xml

The marked situation is great for both types of MediaTypes, but it only returns BaseEntity attributes, not added attributes for extended classes. How can I get attributes for extended classes and work with MediaTypes?

The full repository can be found here (in progress): https://github.com/martijnburger/multitenant

=== Update 1 ===

I changed the @XmlSeeAlso annotation to Entities. It was on specific objects, but should have been on BaseEntity . Next, I used the implementation of GenericList above. This gives the correct XML responses. However, it still only returns BaseEntity attributes in JSON replicas. I have two questions:

  • How to return a JSON response, including attributes for a given object?
  • I would prefer that when adding or removing certain Entity classes you don't need to touch BaseEntity . Since the @XmlSeeAlso annotation every time I add a new Entity class, I need to update the annotation. Is there any other way to implement this where I don't need to touch BaseEntity ?

The repository with changes can be found here: https://github.com/martijnburger/multitenant/tree/so_36291250

=== Update 2 ===

I had a good hope that Jackson's @JsonSubTypes annotation would solve my problem 1. However, this did not happen. I updated the repository with Jackson annotations, but I don't see any changes as a result.

=== Update 3 ===

Please ignore my update 2. It fully works when using Jackson 2 instead of Jackson 1. Beginner error. :( Which leaves me with the question: is it possible to get this work without touching BaseEntity every time you add an entity.

+5
source share
3 answers

Instead of using JAXB for XML, you can use Jackson, which has an XML module. For JAX-RS you must use this artifact 1

 <dependency> <groupId>com.fasterxml.jackson.jaxrs</groupId> <artifactId>jackson-jaxrs-xml-provider</artifactId> <version>${jackson2.version}</version> <!-- you'll probably want to use the same version as the jackson being used on your wildfly --> </dependency> 

If you use this, XML will be processed by Jackson, which does not have some of the same quirks as JAXB. And all your Jackson JSON annotations will work with this too, so you only need one set of annotations for XML and JSON. At a lower level, Jackson's XML provider uses jackson-dataformat-xml if you want more information about this.

From what I tested, just adding an artifact to your project is enough to make it work, although I did not test Wildfly, I just tested it with RESTeasy. But I suppose that should still work.

If this does not work, I can only assume that the JAXB provider has priority over this. You may need to exclude resteasy-jaxb-provider in the jboss-structure.xml file. But, as I said, I do not think it will be required. I would check with Wildfly, but I really didn't want to download it :-)

Extra

The OP uses Class 2 scanning to select resources and providers of auto-register, but if you manually register your resources and suppliers in your Application subclass, you will also need to manually register JacksonXMLProvider.class (or JacksonJaxbXMLProvider.class if you want JAXB annotation support).


1 - The linked project is displayed as obsolete, but it refers to a non-obsolete later version. I am related to outdated since there is documentation in README, although this is very small. The newer project is missing documentation.

2 - An empty Application subclass annotated with @ApplicationPath is enough to start scanning the classpath. After you override either getClasses() or getSingletons() and return a nonempty set, getSingletons() scanning is disabled.

+1
source

All variables must be private in the definition of the entity. If someone is public, he returns a json response but does not return an xml response.

+1
source

Good. In the end, I came up with a separate solution for XML and JSON. In this solution, I do not need annotations for the Generic classes (Like @XmlSeeAlso and @JsonSubTypes ). The only drawback of this solution is that you cannot return the Response object to the Rest class for the XML request.

 @GET @Produces(MediaType.APPLICATION_JSON) public Response getAllJSON() { return Response.ok(getService().findAll()).build(); } @GET @Produces(MediaType.APPLICATION_XML) public List<T> getAllXML() { return getService().findAll(); } 

If someone knows a better implementation, I will remove this answer.

0
source

Source: https://habr.com/ru/post/1246007/


All Articles