2

I have a rest service which receives an array of objects, and I need to convert the json info back into the object List; my stack is build on top of Spring 4

I got this service definition:

@RequestMapping(value = "/services/crud/dangers/createDanger", method = RequestMethod.GET)
    public @ResponseBody GenericServiceReturn createDanger(
            @RequestParam(value = "postionId", required = true) Long positionId,
            @RequestParam(value = "dangerName", required = true) String dangerName,
            @RequestParam(value = "type", required = true) Integer type,
            @RequestParam(value = "description", required = true) String description,
            @RequestParam(value = "words", required = true) List<RestWord> words)

As you can see, the parameter words is a List of RestWord, which is defined like this:

public class RestWord {
    private long id = -1;
    private String name;
    private long type = -1;
    

Also I've defined the converter like this:

public class RestWordConverter implements Converter<String, RestWord>{
    private static final Logger log = LoggerFactory
            .getLogger(RestWordConverter.class);
                    
    @Override
    public RestWord convert(String text) {
        // TODO Auto-generated method stub
        log.info(text);
        return new RestWord();
    }

}

not much logic so far as you can see, also got the converter registered in mvc context like this.

<mvc:annotation-driven conversion-service="conversionService" />

<beans:bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean" >
        <beans:property name="converters">
            <beans:list>
                <beans:bean class="co.com.lineascontrol.core.endpoints.converters.RestWordConverter"/>
            </beans:list>
        </beans:property>
    </beans:bean>  

The problem is, that the converter class is called for each little piece of the json message, to illustrate that, a simple example, for an incoming message:

String words = "[{\"id\":0,\"name\":instalar,\"type\":-1},{\"id\":0,\"name\":ventilacion,\"type\":-1},{\"id\":0,\"name\":tunel,\"type\":-1}]";

I'm getting this at the server output:

c.c.l.c.e.c.RestWordConverter - [{"id":0
c.c.l.c.e.c.RestWordConverter - "name":instalar
c.c.l.c.e.c.RestWordConverter - "type":-1}
c.c.l.c.e.c.RestWordConverter - {"id":0
c.c.l.c.e.c.RestWordConverter - "name":ventilacion
c.c.l.c.e.c.RestWordConverter - "type":-1}
c.c.l.c.e.c.RestWordConverter - {"id":0
c.c.l.c.e.c.RestWordConverter - "name":tunel
c.c.l.c.e.c.RestWordConverter - "type":-1}]

Which means the converter function is called one time for every part of the message, and by doing this is impossible to convert the incoming string to the specific object.

I also have the standard Json converters defined like this:

<beans:bean
        class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
        <beans:property name="messageConverters">
            <beans:list>
                <beans:ref bean="jsonMessageConverter" />
            </beans:list>
        </beans:property>
    </beans:bean>

    <!-- Configure bean to convert JSON to POJO and vice versa -->
    <beans:bean id="jsonMessageConverter"
        class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
    </beans:bean>

I believe that the converter should be defined as json converter, and not as a conversion service for mvc, but I haven't managed to find examples or documentation about this.

Solution

Hi, in case someone else is struggling with this I managed to get everything up and running.

First of all, if you are new to Rest, I found this simple article explaining basic, but very important stuff:

http://www.drdobbs.com/web-development/restful-web-services-a-tutorial/240169069?pgno=1

After that, I understood most of my problems, so at the end this is my service interface:

@RequestMapping(value = "/services/crud/dangers/createDanger", method = RequestMethod.POST)
    public @ResponseBody GenericServiceReturn createDanger(
            @RequestBody List<RestWord> words,
            @RequestParam(value = "postionId", required = true) Long positionId,
            @RequestParam(value = "dangerName", required = true) String dangerName,
            @RequestParam(value = "type", required = true) String type,
            @RequestParam(value = "description", required = true) String description) {

And here is the proper way to calle it!

List<RestWord> restWordList = new ArrayList<RestWord>();
            
            //put some values in the list! or whatever object you are using
            
            url = "http://localhost:8080/LineasControllBussinesLayer/rest/services/crud/dangers/createDanger";
            
            //add the uri params
            Map<String, Object> requestParams = new HashMap<String, Object>();
            requestParams.put("postionId", 1l);
            requestParams.put("dangerName", dangerName);
            requestParams.put("type", DANGER_TYPE.ACTIVITIE);
            requestParams.put("description", "actividad repeligrosa");
            
            // Create the request body as a MultiValueMap
            
            System.out.println(restWordList);
            //see how the HttpEntity is created with the first parameter as the object, and the second are the header, in my case I use the headers to aunteticate
            HttpEntity<List<RestWord>> entity2 = new HttpEntity<List<RestWord>>(restWordList, headers);
            
            
            //then just call the service!!!
            System.out.println(restTemplate.postForObject(url, entity2, String.class, requestParams));

Please keep in mind that this is just test code, the actual requests should be wrapped into a request object, and everything should go inside the request body

Community
  • 1
  • 1
Camilo Casadiego
  • 907
  • 3
  • 9
  • 33

1 Answers1

1

I'd recommend to use @Resquestbody to map the json to an object. Be aware to combine it with @RequestParam as it may work or not given a version, and it has to be in certain order (try to avoid the @ResquestParam in this case).

Take a look at: Spring MVC - Why not able to use @RequestBody and @RequestParam together Read until the last comment.

Community
  • 1
  • 1
Luke SpringWalker
  • 1,600
  • 3
  • 19
  • 33
  • I understand that I need to change the StringHttpMessageConverter? there's no a way to just implment a converter? I'm asking because I'll be using several different objects in mys requests. I already just changed the definition of the service adding the @RequestBody part, but still have the same behavior – Camilo Casadiego Feb 26 '15 at 22:29
  • Just in case, my real method has many parameters, not only the array. – Camilo Casadiego Feb 26 '15 at 22:31
  • Why you don't create an object that it's a representation of the data you are recieving and use @RequestBody to map it all (this is equals to one objecto corresponding to all the data)?. This way, you delegate the responsability to Spring, but you should be aware of this, don't pass the object to the core of you app, it only has to live in the controller layer. – Luke SpringWalker Feb 27 '15 at 12:46
  • yup, actually my problem was a misunderstanding of basic concepts but @Luke SpringWalker pointed me in the right direction – Camilo Casadiego Feb 27 '15 at 15:19