Its loader is not in trouble, apparently the problem is in the dependency of Jackson, which is the standard JSON converter registered by Spring. By default Spring MVC registers these converters:
How Jackson’s Standard Converter Needs a Version 2.*
, You must upgrade to a newer version of Jackson, which the registered standard converter makes use of. To this end, amend the dependency statement jackson-mapper-asl
in his pom.xml
by one of the version 2
, something like that:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.6.1</version>
</dependency>
Realize that both the groupId
as to the artifactId
are different from the version you are using.
There are other ways to do this, but more laborious if it is mandatory to use an older version of Jackson in your project. One is to configure a view resolve that resolves by content (ContentNegotiatingViewResolver
) and another is to register a converter that using the mapper of Jackson’s version 1.*
. I don’t know how your entire application is, maybe this is not the best alternative, but if this is your case, let me know that I update the response with configuration for these scenarios.
Considerations about serialization in Spring MVC
Suggested this scenario according to what you said in your question, some other points can be checked in your application in search of the solution of your problem.
Something to note is that it is not mandatory to explicitly inform on @RequestMapping
that the end-point will produce JSON, or XML, or HTML, as suggested in the other response, this somewhat limits the flexibility that Spring MVC gives you, as in cases where you need to change the type of media returned. Reviewing all mapping is not a very cool service...
Good practice is to set up several messages converters and leave it up to the customer to choose what type of media he wants, ie it is the customer who will tell what type of return he wants through a header. If it is something that our application does not return, then we will return an error or we can still consider one by default.
As stated above Spring already configures several converters, so what we need to do is just ensure the types of media that our application will handle, as well as configure a standard. In XML we can do this way:
<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager" />
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="defaultContentType" value="application/json" />
<property name="mediaTypes">
<value>
json=application/json
xml=application/xml
</value>
</property>
</bean>
And the equivalent in Java is this:
@Override
public void configureContentNegotiation(final ContentNegotiationConfigurer configurer) {
configurer.parameterName("mediaType")
.defaultContentType(MediaType.APPLICATION_JSON)
.mediaType("xml", MediaType.APPLICATION_XML)
.mediaType("json", MediaType.APPLICATION_JSON);
}
In both XML and Java we did the same thing, we said that the default content type will be JSON (defaultContentType
) and limit the types of media our application will work with (mediaTypes
).
Once this is done, we can test. In Postman a request can be made to http://localhost:8080/<seu_context>/test/candidatos
, with or without the header Accept
, but we can also use something like curl
. This:
curl http://localhost:8080/<seu_context>/test/candidatos
Or this:
curl --header "Accept:application/json" http://localhost:8080/<seu_context>/test/candidatos
You will return this in my example:
[
{
"id": 1,
"nome": "Pedro da Silva"
},
{
"id": 2,
"nome": "Paula Pereira"
},
{
"id": 3,
"nome": "<anonimo>"
}
]
If we inform as value application/xml
for the header Accept
, we will have this:
<List xmlns="">
<item>
<id>1</id>
<nome>Pedro da Silva</nome>
</item>
<item>
<id>2</id>
<nome>Paula Pereira</nome>
</item>
<item>
<id>3</id>
<nome><anonimo></nome>
</item>
</List>
Using curl
, it would be something like that:
curl --header "Accept:application/xml" http://localhost:8080/<seu_context>/test/candidatos
Note: on return in XML the name of the property, namespace, etc., can be changed by you.
Finally, some remarks, other good practices:
- it is not necessary to return a Responseentity, it is usually used when we inform a status HTTP different than the container would return, when we are using
RestTemplate
or when we do not explicitly inform @ResponseBody
. In the latter case, @ResponseBody
is already inherited when we use @RestController
;
- it is not necessary to convert anything to a
JSONObject
, as suggests also the other response, this is work and unnecessary. When we speak through the @ResponseBody
that the return will be serialized, which will be the payload response, Spring will choose the most appropriate converter according to the header provided by the client (HTTP header Accept
) or set as default. That said, you can simply return a list of candidates (List<Candidato>
);
So considering also these remarks, your CandidatosWS
might look like this:
@RestController
@RequestMapping(value = "/test")
public class CandidatosWS {
@Autowired
private CandidatoService candidatoService;
@RequestMapping(value = "/candidatos", method = RequestMethod.GET)
public List<Candidato> allCandidatos() {
return candidatoService.listarCandidatos();
}
}
A full working example can be seen in this gist, if you want to see how you can make your controllers simpler, leaving it to Spring to serialize.
No need to convert anything to
JSONObject
, spring already has converters for that, just set up. Ever imagined having to implementtoJson();
in all entities, or even call explicitly in the controller to be serialized? It’s a lot of work that spring already does for us ;)– Bruno César
@Brunocésar, thank you for your comments. It was just an example the code above, it would not need to implement in all entities, depends on the need for it. I didn’t know Spring had converters, I always saw code using Jackson and Gson explicitly converting objects to JSON. Anyway, I see no reason to deny an answer that, as far as I know, is not incorrect.
– Dherik
@Dherik I think the only problem with the answer is the word accurate. The user does not need to mount JSON manually. On the other hand, it is an excellent alternative, since an object does not always give us the desired mapping or even we want to create a class to represent a simple value. In addition to that the performance of assembling a JSON manually is far superior to that which uses reflection. So it is always good to keep in mind an alternative.
– utluiz