samedi 3 mars 2012

Spring3 et WADL generation

Il n'existe pas à ce jour de génération de wadl pour Spring.
Spring MVC de part sa structure supporte l'architecture de type REST. Il n'utilise cependant pas le standard JSR-311. Il existe plusieurs implémentations de ce standard comme Jersey, Restlet, Apache CXF, et la plupart fournissent une génération automatique de wadl.

Je me suis donc motivé pour générer cette wadl avec un simple Controller spring.
Pour cela, je me suis fortement basé sur l'article suivant :
http://nurkiewicz.blogspot.com/2012/02/automatically-generating-wadl-in-spring.html

Source du controlleur :


package org.dyndns.tuxgalaxy.springrestwadl.controllers;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;

import net.java.dev.wadl._2009._02.WadlApplication;
import net.java.dev.wadl._2009._02.WadlDoc;
import net.java.dev.wadl._2009._02.WadlMethod;
import net.java.dev.wadl._2009._02.WadlParam;
import net.java.dev.wadl._2009._02.WadlParamStyle;
import net.java.dev.wadl._2009._02.WadlRepresentation;
import net.java.dev.wadl._2009._02.WadlRequest;
import net.java.dev.wadl._2009._02.WadlResource;
import net.java.dev.wadl._2009._02.WadlResources;
import net.java.dev.wadl._2009._02.WadlResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.condition.ProducesRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

@Controller
@RequestMapping("/application.wadl")
public class WadlController {
 
 @Autowired
 private RequestMappingHandlerMapping handlerMapping;
 
    @RequestMapping(method=RequestMethod.GET, produces={"application/xml"} ) 
    public @ResponseBody WadlApplication generateWadl(HttpServletRequest request) {
     WadlApplication result = new WadlApplication();
     WadlDoc doc = new WadlDoc();
     doc.setTitle("REST Service WADL");
     result.getDoc().add(doc);
     WadlResources wadResources = new WadlResources();
  wadResources.setBase(getBaseUrl(request));
  
     Map handletMethods = handlerMapping.getHandlerMethods();
     for (Map.Entry entry : handletMethods.entrySet()) {
      WadlResource wadlResource = new WadlResource();
      
      HandlerMethod handlerMethod = entry.getValue();
      RequestMappingInfo mappingInfo = entry.getKey();
      
      Set pattern =  mappingInfo.getPatternsCondition().getPatterns();
      Set httpMethods =  mappingInfo.getMethodsCondition().getMethods();
      ProducesRequestCondition producesRequestCondition = mappingInfo.getProducesCondition();
      Set mediaTypes = producesRequestCondition.getProducibleMediaTypes();
      
      for (RequestMethod httpMethod : httpMethods) {
       WadlMethod wadlMethod = new WadlMethod();
       
       for (String uri : pattern) {
        wadlResource.setPath(uri);  
    }
       
       wadlMethod.setName(httpMethod.name());
       Method javaMethod = handlerMethod.getMethod();
       wadlMethod.setId(javaMethod.getName());
       WadlDoc wadlDocMethod = new WadlDoc();
       wadlDocMethod.setTitle(javaMethod.getDeclaringClass().getName()+"."+javaMethod.getName());
       wadlMethod.getDoc().add(wadlDocMethod);
       
       // Request
       WadlRequest wadlRequest = new WadlRequest();
       
       Annotation[][] annotations = javaMethod.getParameterAnnotations();
       for (Annotation[] annotation : annotations) {
        for (Annotation annotation2 : annotation) {
         if (annotation2 instanceof RequestParam ) {
          RequestParam param2 = (RequestParam)annotation2;
          WadlParam waldParam = new WadlParam();
                waldParam.setName(param2.value());
                waldParam.setStyle(WadlParamStyle.QUERY);
                waldParam.setRequired(param2.required());
                String defaultValue = cleanDefault(param2.defaultValue());
                if ( !defaultValue.equals("") ) {
                 waldParam.setDefault(defaultValue);
                }
                wadlRequest.getParam().add(waldParam);
         } else if ( annotation2 instanceof PathVariable ) {
          PathVariable param2 = (PathVariable)annotation2;
          WadlParam waldParam = new WadlParam();
                waldParam.setName(param2.value());
                waldParam.setStyle(WadlParamStyle.TEMPLATE);
                waldParam.setRequired(true);
                wadlRequest.getParam().add(waldParam);
         }
     }
    }
       if ( ! wadlRequest.getParam().isEmpty() ) {
        wadlMethod.setRequest(wadlRequest);
       }
       
       // Response
       if ( !mediaTypes.isEmpty() ) {
        WadlResponse wadlResponse = new WadlResponse();
     wadlResponse.getStatus().add(200l);
        for (MediaType mediaType : mediaTypes) {
         WadlRepresentation wadlRepresentation = new WadlRepresentation();
         wadlRepresentation.setMediaType(mediaType.toString());
         wadlResponse.getRepresentation().add(wadlRepresentation);
     }
        wadlMethod.getResponse().add(wadlResponse);
       }
       
       wadlResource.getMethodOrResource().add(wadlMethod);
       
   }
      
      wadResources.getResource().add(wadlResource);
      
  }
     result.getResources().add(wadResources);
     
     return result;
    }
    
    
    private String getBaseUrl (HttpServletRequest request) {
     String requestUri = request.getRequestURI();
  return request.getScheme()+"://"+ request.getServerName()+":"+ request.getServerPort() + requestUri;
 }
    
    private String cleanDefault(String value) {
     value = value.replaceAll("\t", "");
     value = value.replaceAll("\n", "");
     value = value.replaceAll("", "");
     value = value.replaceAll("", "");
     value = value.replaceAll("", "");
     return value;
    }
 
}


Example de wadl généré





 
 
  
   
    
    
     
    
   
  
  
   
    
    
     
    
     
     
    
   
  
  
   
    
    
     
   
  
 



Example


Un example de code se trouve sur google code ( projet : SpringRestWadl )


Importer le projet dans eclipse puis accéder à l'url :

http://localhost:8080/SpringRestWadl/rest/application.wadl