/*******************************************************************************
* 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.jaxrs;
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.ArrayList;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import static org.calrissian.restdoclet.util.AnnotationUtils.getAnnotationName;
import static org.calrissian.restdoclet.util.AnnotationUtils.getElementValue;
import static org.calrissian.restdoclet.util.CommonUtils.isEmpty;
import static org.calrissian.restdoclet.util.TagUtils.*;
public class JaxRSCollector extends AbstractCollector {
protected static final String ANNOTATION_PACKAGE = "javax.ws.rs.";
protected static final String PATH_ANNOTATION = ANNOTATION_PACKAGE + "Path";
protected static final String GET_ANNOTATION = ANNOTATION_PACKAGE + "GET";
protected static final String POST_ANNOTATION = ANNOTATION_PACKAGE + "POST";
protected static final String PUT_ANNOTATION = ANNOTATION_PACKAGE + "PUT";
protected static final String DELETE_ANNOTATION = ANNOTATION_PACKAGE + "DELETE";
protected static final String HEAD_ANNOTATION = ANNOTATION_PACKAGE + "HEAD";
protected static final String CONSUMES_ANNOTATION = ANNOTATION_PACKAGE + "Consumes";
protected static final String PRODUCES_ANNOTATION = ANNOTATION_PACKAGE + "Produces";
protected static final String PATHVAR_ANNOTATION = ANNOTATION_PACKAGE + "PathParam";
protected static final String PARAM_ANNOTATION = ANNOTATION_PACKAGE + "QueryParam";
@Override
protected boolean shouldIgnoreClass(ClassDoc classDoc) {
//Look for any JAXRS annotations in the class or the methods. If found then don't ignore this class.
for (AnnotationDesc classAnnotation : classDoc.annotations()) {
String annotationName = getAnnotationName(classAnnotation);
if (annotationName != null && annotationName.startsWith(ANNOTATION_PACKAGE))
return false;
}
for (MethodDoc methodDoc : classDoc.methods(true)) {
if (!shouldIgnoreMethod(methodDoc))
return false;
}
return true;
}
@Override
protected boolean shouldIgnoreMethod(MethodDoc methodDoc) {
//Jax RS methods need a method annotation inorder to be used, so simply look for them.
for (AnnotationDesc methodAnnotation : methodDoc.annotations()) {
String annotationName = getAnnotationName(methodAnnotation);
if (GET_ANNOTATION.equals(annotationName) ||
POST_ANNOTATION.equals(annotationName) ||
PUT_ANNOTATION.equals(annotationName) ||
DELETE_ANNOTATION.equals(annotationName) ||
HEAD_ANNOTATION.equals(annotationName)) {
return false;
}
}
return true;
}
@Override
protected EndpointMapping getEndpointMapping(ProgramElementDoc doc) {
Collection<String> paths = new LinkedHashSet<String>();
Collection<String> httpMethods = new LinkedHashSet<String>();
Collection<String> consumes = new LinkedHashSet<String>();
Collection<String> produces = new LinkedHashSet<String>();
//Look for a request mapping annotation
for (AnnotationDesc annotation : doc.annotations()) {
String annotationName = getAnnotationName(annotation);
if (GET_ANNOTATION.equals(annotationName) ||
POST_ANNOTATION.equals(annotationName) ||
PUT_ANNOTATION.equals(annotationName) ||
DELETE_ANNOTATION.equals(annotationName) ||
HEAD_ANNOTATION.equals(annotationName)) {
httpMethods.add(annotationName.replace(ANNOTATION_PACKAGE, ""));
} else if (PATH_ANNOTATION.equals(annotationName)) {
paths.addAll(getElementValue(annotation, "value"));
} else if (CONSUMES_ANNOTATION.equals(annotationName)) {
consumes.addAll(getElementValue(annotation, "value"));
} else if (PRODUCES_ANNOTATION.equals(annotationName)) {
produces.addAll(getElementValue(annotation, "value"));
}
}
return new EndpointMapping(
paths,
httpMethods,
consumes,
produces
);
}
@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();
List<String> values = getElementValue(annotation, "value");
if (!values.isEmpty())
name = values.get(0);
//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);
//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, false, 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()) {
//TODO, need to double check this logic more.
//ignore anything in annotations and that starts with javax. Then just accept the first one.
if (isEmpty(parameter.annotations()) && !parameter.typeName().startsWith("javax.")) {
//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) {
//Only methods should have http methods.
return methodMapping.getHttpMethods();
}
}