WADL generator for Spring REST

Spring REST does not come with out of the box WADL generator like JERSEY However it should be pretty easy to get it done.
The following code will work with Spring REST 4x and its based on the suggested code by tuxgalaxy provided on below https://jira.spring.io/browse/SPR-8705

http://tuxgalaxy.blogspot.in/2012/03/spring3-et-wadl-generation.html

The code has been updated to work with latest versions of Spring and wadl library
Add Dependency for wadl library, There are two versions of this class, use the second one with Spring4 which filter out controllers which are not marked with @RestContoller annotation

<dependency>
  <groupId>org.jvnet.ws.wadl</groupId>
  <artifactId>wadl-core</artifactId>
  <version>1.1.6</version>
</dependency>	
<dependency>
	<groupId>org.jvnet.ws.wadl</groupId>
	<artifactId>wadl-client-plugin</artifactId>
	<version>1.1.6</version>
</dependency>

 

Add a controller class which will generate WADL, You can copy paste below code, it has been tested and should work fine. Call this controller from browser like http://loclahost:8080/site//v2/application.wadl

For Spring 4
The below is a version of WADL generator which add param types as well as filter out which are not marked with @RestController annotation which is new annotation in Spring 4.

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

import javax.servlet.http.HttpServletRequest;
import javax.xml.namespace.QName;

import org.jvnet.ws.wadl.Application;
import org.jvnet.ws.wadl.Doc;
import org.jvnet.ws.wadl.Param;
import org.jvnet.ws.wadl.ParamStyle;
import org.jvnet.ws.wadl.Representation;
import org.jvnet.ws.wadl.Request;
import org.jvnet.ws.wadl.Resource;
import org.jvnet.ws.wadl.Resources;
import org.jvnet.ws.wadl.Response;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
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.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.WebApplicationContext;
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("/v2/application.wadl")
public class WADLControllerV2 {
    String xs_namespace="http://www.w3.org/2001/XMLSchema" ;
    @Autowired
    private RequestMappingHandlerMapping handlerMapping;
    @Autowired
    private WebApplicationContext webApplicationContext;

    @RequestMapping(method=RequestMethod.GET, produces={"application/xml"} ) 
    public @ResponseBody Application generateWadl(HttpServletRequest request) {
        Application result = new Application();
        Doc doc = new Doc();
        doc.setTitle("Spring REST Service WADL");
        result.getDoc().add(doc);
        Resources wadResources = new Resources();
        wadResources.setBase(getBaseUrl(request));
         
        Map<RequestMappingInfo, HandlerMethod> handletMethods = handlerMapping.getHandlerMethods();
        for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : handletMethods.entrySet()) {
            
             
            HandlerMethod handlerMethod = entry.getValue();
            
            Object object = handlerMethod.getBean();
            Object bean = webApplicationContext.getBean(object.toString());
            
            boolean isRestContoller = bean.getClass().isAnnotationPresent(RestController.class);
            if(!isRestContoller) {
            	continue;
            }
            RequestMappingInfo mappingInfo = entry.getKey();
             
            Set<String> pattern =  mappingInfo.getPatternsCondition().getPatterns();
            Set<RequestMethod> httpMethods =  mappingInfo.getMethodsCondition().getMethods();
            ProducesRequestCondition producesRequestCondition = mappingInfo.getProducesCondition();
            Set<MediaType> mediaTypes = producesRequestCondition.getProducibleMediaTypes();
            Resource wadlResource = null; 
            for (RequestMethod httpMethod : httpMethods) {
                org.jvnet.ws.wadl.Method wadlMethod = new org.jvnet.ws.wadl.Method();
     
                for (String uri : pattern) {
                	wadlResource = createOrFind( uri,  wadResources); 
                    wadlResource.setPath(uri);      
                }
                 
                wadlMethod.setName(httpMethod.name());
                Method javaMethod = handlerMethod.getMethod();
                wadlMethod.setId(javaMethod.getName());
                Doc wadlDocMethod = new Doc();
                wadlDocMethod.setTitle(javaMethod.getDeclaringClass().getSimpleName()+"."+javaMethod.getName());
                wadlMethod.getDoc().add(wadlDocMethod);
                 
                // Request
                Request wadlRequest = new Request();
                 
                Annotation[][] annotations = javaMethod.getParameterAnnotations();
                Class<?>[] paramTypes = javaMethod.getParameterTypes();
                int i = 0;
                for (Annotation[] annotation : annotations) {
                	Class<?> paramType =paramTypes[i];
                	i++;
                    for (Annotation annotation2 : annotation) {
                    
                        if (annotation2 instanceof RequestParam ) {
                            RequestParam param2 = (RequestParam)annotation2;
                            Param waldParam = new Param();
                            QName nm = convertJavaToXMLType(paramType);
                            waldParam.setName(param2.value());
                            waldParam.setStyle(ParamStyle.QUERY);
                            waldParam.setRequired(param2.required());
                            String defaultValue = cleanDefault(param2.defaultValue());
                            if ( !defaultValue.equals("") ) {
                                waldParam.setDefault(defaultValue);
                            }
                            waldParam.setType(nm);
                            wadlRequest.getParam().add(waldParam);
                        } else if ( annotation2 instanceof PathVariable ) {
                            PathVariable param2 = (PathVariable)annotation2;
                            QName nm = convertJavaToXMLType(paramType);
                            Param waldParam = new Param();
                            waldParam.setName(param2.value());
                            waldParam.setStyle(ParamStyle.TEMPLATE);
                            waldParam.setRequired(true);
                            wadlRequest.getParam().add(waldParam);
                            waldParam.setType(nm);
                        }
                    }
                }
                if ( ! wadlRequest.getParam().isEmpty() ) {
                    wadlMethod.setRequest(wadlRequest);
                }
                 
                // Response
                if ( !mediaTypes.isEmpty() ) {
                    Response wadlResponse = new Response();
                    Class methodReturn = handlerMethod.getReturnType().getClass();
                    ResponseStatus status = handlerMethod.getMethodAnnotation(ResponseStatus.class);
                    if(status==null) {
                    	wadlResponse.getStatus().add((long)(HttpStatus.OK.value()));
                    }else {
                        HttpStatus httpcode = status.value();
                        wadlResponse.getStatus().add((long)httpcode.value());
                    }

                    for (MediaType mediaType : mediaTypes) {
                        Representation wadlRepresentation = new Representation();
                        wadlRepresentation.setMediaType(mediaType.toString());
                        wadlResponse.getRepresentation().add(wadlRepresentation);
                    }
                    wadlMethod.getResponse().add(wadlResponse);
                }
                 
                wadlResource.getMethodOrResource().add(wadlMethod);
                 
            }
             
    
             
        }
        result.getResources().add(wadResources);
         
        return result;
    }
    private QName convertJavaToXMLType(Class<?> type) {
    	QName nm = new QName("");
    	String classname=type.toString();
    	if (classname.indexOf("String")>=0) {
	         nm = new QName(xs_namespace,"string","xs");
	        
        }else if(classname.indexOf("Integer")>=0) {
        	 nm = new QName(xs_namespace,"int","xs");
        }
    	return nm;
    }
    private Resource createOrFind(String uri, Resources wadResources) {
    	  List<Resource> current = wadResources.getResource();
    	  for(Resource resource:current) {
    		  if(resource.getPath().equalsIgnoreCase(uri)){
    			  return resource;
    		  }
    	  }
    	  Resource wadlResource = new  Resource();
    	  current.add(wadlResource);
    	  return wadlResource;
    }
    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", "");
        return value;
    }
}
Posted in Spring REST
2 comments on “WADL generator for Spring REST
  1. Radek says:

    good post but the code doesn’t work

Leave a comment