Camilo Casadiego
Camilo Casadiego

Reputation: 920

Array of objects as parameter in Rest service

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

Upvotes: 2

Views: 14356

Answers (1)

Luke SpringWalker
Luke SpringWalker

Reputation: 1592

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.

Upvotes: 1

Related Questions