/*******************************************************************************
* Copyright (C) 2014 The Calrissian Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package org.calrissian.restdoclet.collector.spring;
import com.sun.javadoc.*;
import org.calrissian.restdoclet.collector.AbstractCollector;
import org.calrissian.restdoclet.collector.EndpointMapping;
import org.calrissian.restdoclet.model.PathVar;
import org.calrissian.restdoclet.model.QueryParam;
import org.calrissian.restdoclet.model.RequestBody;
import java.util.*;
import static java.lang.Boolean.FALSE;
import static java.lang.Boolean.TRUE;
import static java.util.Arrays.asList;
import static org.calrissian.restdoclet.util.AnnotationUtils.getAnnotationName;
import static org.calrissian.restdoclet.util.AnnotationUtils.getElementValue;
import static org.calrissian.restdoclet.util.CommonUtils.firstNonEmpty;
import static org.calrissian.restdoclet.util.CommonUtils.isEmpty;
import static org.calrissian.restdoclet.util.TagUtils.*;
public class SpringCollector extends AbstractCollector {
protected static final List<String> CONTROLLER_ANNOTATION = Arrays.asList("org.springframework.stereotype.Controller",
"org.springframework.web.bind.annotation.RestController");
protected static final String MAPPING_ANNOTATION = "org.springframework.web.bind.annotation.RequestMapping";
protected static final String PATHVAR_ANNOTATION = "org.springframework.web.bind.annotation.PathVariable";
protected static final String PARAM_ANNOTATION = "org.springframework.web.bind.annotation.RequestParam";
protected static final String REQUESTBODY_ANNOTATION = "org.springframework.web.bind.annotation.RequestBody";
@Override
protected boolean shouldIgnoreClass(ClassDoc classDoc) {
//If found a controller annotation then don't ignore this class.
for (AnnotationDesc classAnnotation : classDoc.annotations())
if (CONTROLLER_ANNOTATION.contains(getAnnotationName(classAnnotation)))
return false;
//If not found then ignore this class.
return true;
}
@Override
protected boolean shouldIgnoreMethod(MethodDoc methodDoc) {
//If found a mapping annotation then don't ignore this class.
for (AnnotationDesc classAnnotation : methodDoc.annotations())
if (MAPPING_ANNOTATION.equals(getAnnotationName(classAnnotation)))
return false;
//If not found then ignore this class.
return true;
}
@Override
protected EndpointMapping getEndpointMapping(ProgramElementDoc doc) {
//Look for a request mapping annotation
for (AnnotationDesc annotation : doc.annotations()) {
//If found then extract the value (paths) and the methods.
if (MAPPING_ANNOTATION.equals(getAnnotationName(annotation))) {
//Get http methods from annotation
Collection<String> httpMethods = new LinkedHashSet<String>();
for (String value : getElementValue(annotation, "method"))
httpMethods.add(value.substring(value.lastIndexOf(".") + 1));
return new EndpointMapping(
new LinkedHashSet<String>(getElementValue(annotation, "value")),
httpMethods,
new LinkedHashSet<String>(getElementValue(annotation, "consumes")),
new LinkedHashSet<String>(getElementValue(annotation, "produces"))
);
}
}
//Simply return an empty grouping if no request mapping was found.
return new EndpointMapping(
Collections.<String>emptySet(),
Collections.<String>emptySet(),
Collections.<String>emptySet(),
Collections.<String>emptySet()
);
}
@Override
protected Collection<PathVar> generatePathVars(MethodDoc methodDoc) {
Collection<PathVar> retVal = new ArrayList<PathVar>();
Tag[] tags = methodDoc.tags(PATHVAR_TAG);
ParamTag[] paramTags = methodDoc.paramTags();
for (Parameter parameter : methodDoc.parameters()) {
for (AnnotationDesc annotation : parameter.annotations()) {
if (getAnnotationName(annotation).equals(PATHVAR_ANNOTATION)) {
String name = parameter.name();
Collection<String> values = getElementValue(annotation, "value");
if (!values.isEmpty())
name = values.iterator().next();
//first check for special tag, then check regular param tag, finally default to empty string
String text = findParamText(tags, name);
if (text == null)
text = findParamText(paramTags, parameter.name());
if (text == null)
text = "";
retVal.add(new PathVar(name, text, parameter.type()));
}
}
}
return retVal;
}
@Override
protected Collection<QueryParam> generateQueryParams(MethodDoc methodDoc) {
Collection<QueryParam> retVal = new ArrayList<QueryParam> ();
Tag[] tags = methodDoc.tags(QUERYPARAM_TAG);
ParamTag[] paramTags = methodDoc.paramTags();
for (Parameter parameter : methodDoc.parameters()) {
for (AnnotationDesc annotation : parameter.annotations()) {
if (getAnnotationName(annotation).equals(PARAM_ANNOTATION)) {
String name = parameter.name();
List<String> values = getElementValue(annotation, "value");
if (!values.isEmpty())
name = values.get(0);
List<String> requiredVals = getElementValue(annotation, "required");
//With spring query params are required by default
boolean required = TRUE;
if(!requiredVals.isEmpty())
required = Boolean.parseBoolean(requiredVals.get(0));
//With spring, if defaultValue is provided then "required" is set to false automatically
List<String> defaultVals = getElementValue(annotation, "defaultValue");
if (!defaultVals.isEmpty())
required = FALSE;
//first check for special tag, then check regular param tag, finally default to empty string
String text = findParamText(tags, name);
if (text == null)
text = findParamText(paramTags, parameter.name());
if (text == null)
text = "";
retVal.add(new QueryParam(name, required, text, parameter.type()));
}
}
}
return retVal;
}
@Override
protected RequestBody generateRequestBody(MethodDoc methodDoc) {
Tag[] tags = methodDoc.tags(REQUESTBODY_TAG);
ParamTag[] paramTags = methodDoc.paramTags();
for (Parameter parameter : methodDoc.parameters()) {
for (AnnotationDesc annotation : parameter.annotations()) {
if (getAnnotationName(annotation).equals(REQUESTBODY_ANNOTATION)) {
//first check for special tag, then check regular param tag, finally default to empty string
String text = (isEmpty(tags) ? null : tags[0].text());
if (text == null)
text = findParamText(paramTags, parameter.name());
if (text == null)
text = "";
return new RequestBody(parameter.name(), text, parameter.type());
}
}
}
return null;
}
@Override
protected Collection<String> resolveHttpMethods(EndpointMapping classMapping, EndpointMapping methodMapping) {
//If there are no http methods defined simply use GET
return firstNonEmpty(super.resolveHttpMethods(classMapping, methodMapping), asList("GET"));
}
}