Author: [email protected]
Date: Mon Feb 27 08:53:53 2012
New Revision: 2113
Log:
Improvements for bean instantiation
Modified:
sandbox/ivol/amdatu-commons/rest-doclet/pom.xml
sandbox/ivol/amdatu-commons/rest-doclet/src/main/java/org/amdatu/commons/restdoclet/ClassAnalyzer.java
sandbox/ivol/amdatu-commons/rest-doclet/src/main/java/org/amdatu/commons/restdoclet/JaxbBeanHelper.java
sandbox/ivol/amdatu-commons/rest-doclet/src/main/java/org/amdatu/commons/restdoclet/RESTDoclet.java
Modified: sandbox/ivol/amdatu-commons/rest-doclet/pom.xml
==============================================================================
--- sandbox/ivol/amdatu-commons/rest-doclet/pom.xml (original)
+++ sandbox/ivol/amdatu-commons/rest-doclet/pom.xml Mon Feb 27 08:53:53 2012
@@ -24,7 +24,7 @@
</parent>
<artifactId>org.amdatu.commons.restdoclet</artifactId>
<packaging>jar</packaging>
- <version>1.0.3</version>
+ <version>1.0.4-SNAPSHOT</version>
<name>Amdatu Commons - REST Doclet</name>
<description>A doclet to generate REST documentation</description>
@@ -44,7 +44,7 @@
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
- <version>1.4</version>
+ <version>2.1</version>
<scope>compile</scope>
</dependency>
<dependency>
Modified:
sandbox/ivol/amdatu-commons/rest-doclet/src/main/java/org/amdatu/commons/restdoclet/ClassAnalyzer.java
==============================================================================
---
sandbox/ivol/amdatu-commons/rest-doclet/src/main/java/org/amdatu/commons/restdoclet/ClassAnalyzer.java
(original)
+++
sandbox/ivol/amdatu-commons/rest-doclet/src/main/java/org/amdatu/commons/restdoclet/ClassAnalyzer.java
Mon Feb 27 08:53:53 2012
@@ -15,6 +15,12 @@
*/
package org.amdatu.commons.restdoclet;
+import static javax.ws.rs.core.MediaType.APPLICATION_FORM_URLENCODED;
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+import static javax.ws.rs.core.MediaType.APPLICATION_XML;
+import static javax.ws.rs.core.MediaType.TEXT_HTML;
+import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
+
import java.util.ArrayList;
import java.util.List;
@@ -104,30 +110,41 @@
}
// Returns the consumed types
- public String getConsumes(MethodDoc methodDoc) throws Exception {
- String result = "";
+ public StringBuffer getConsumes(MethodDoc methodDoc) throws Exception {
String[] consumes = getAnnotationValues(methodDoc, Consumes.class);
if (consumes != null && consumes.length > 0) {
// Build mimetypes
+ StringBuffer result = new StringBuffer();
String[] mimeTypes = getMimeTypes(consumes[0]);
- result += getMimeTypeTable(methodDoc, mimeTypes, true);
- }
- else {
- result = "-";
+ result.append(getMimeTypeTable(methodDoc, mimeTypes, true));
+ return result;
}
- return result;
+ return null;
}
-
- private String getMimeTypeTable(MethodDoc methodDoc, String[] mimeTypes,
boolean in) throws Exception {
- String result = "<table>";
+
+ private StringBuffer getMimeTypeTable(MethodDoc methodDoc, String[]
mimeTypes, boolean input) throws Exception {
+ StringBuffer result = new StringBuffer();
+ result.append("<table>");
for (String mimeType : mimeTypes) {
- result += "<tr><td>" + mimeType + "</td><td>";
+ result.append("<tr><td>" + mimeType + "</td><td>");
List<String> params;
- if (in) {
- // Get example, find the JAXB annotated bean
- params = getParameters(methodDoc, null);
+ if (input) {
+ // If the mimetype is form encoded, we must try to retrieve
FormParam annotated parameters
+ if (APPLICATION_FORM_URLENCODED.equals(mimeType)) {
+ params = getParameters(methodDoc, FormParam.class);
+ } else {
+ // First try the see tag
+ String seeTagParam = getTypeFromSeeTag(methodDoc);
+ if (seeTagParam != null) {
+ params = new ArrayList<String>();
+ params.add(seeTagParam);
+ } else {
+ // Try to get an example from the JAXB annotated bean
+ params = getParameters(methodDoc, null);
+ }
+ }
}
else {
Type returnType = methodDoc.returnType();
@@ -137,61 +154,73 @@
}
else if
(Response.class.getCanonicalName().equals(returnType.qualifiedTypeName())) {
// Check if there is a @see anotation that indicates the
return type
- SeeTag[] seeTags = methodDoc.seeTags();
- if (seeTags != null && seeTags.length > 0) {
- for (SeeTag seeTag : seeTags) {
- if (seeTag.referencedClass() != null) {
-
params.add(seeTag.referencedClass().qualifiedTypeName());
- }
- }
+ String seeTagParam = getTypeFromSeeTag(methodDoc);
+ if (seeTagParam != null) {
+ params.add(seeTagParam);
}
if (params.size() == 0) {
- if (mimeType.equals("text/plain") ||
mimeType.equals("text/html")) {
+ if (mimeType.equals(TEXT_PLAIN) ||
mimeType.equals(TEXT_HTML)) {
params.add("");
}
else {
- result += Response.class.getCanonicalName();
+ result.append(Response.class.getCanonicalName());
}
}
}
}
for (String param : params) {
- if ("text/plain".equals(mimeType)) {
- result += "Some text";
+ if (TEXT_PLAIN.equals(mimeType)) {
+ result.append("Some text");
}
- else if ("text/html".equals(mimeType)) {
- result += "Some html";
+ else if (TEXT_HTML.equals(mimeType)) {
+ result.append("Some html");
}
- else if ("application/json".equals(mimeType)) {
- Object obj = m_beanHelper.createBean(param);
- result += m_beanHelper.toJSON(obj);
+ else if (APPLICATION_JSON.equals(mimeType)) {
+ Object obj = m_beanHelper.createBean(param, mimeType,
getHTTPMethod(methodDoc));
+ result.append(m_beanHelper.toJSON(obj));
}
- else if ("application/xml".equals(mimeType)) {
- Object obj = m_beanHelper.createBean(param);
- result += m_beanHelper.toXML(obj);
+ else if (APPLICATION_XML.equals(mimeType)) {
+ Object obj = m_beanHelper.createBean(param, mimeType,
getHTTPMethod(methodDoc));
+ result.append(m_beanHelper.toXML(obj));
}
- else if ("application/x-www-form-urlencoded".equals(mimeType))
{
+ else if (APPLICATION_FORM_URLENCODED.equals(mimeType)) {
List<String> formParams = getFormParameters(methodDoc);
- result += "<ul>";
+ result.append("<ul>");
for (String formParam : formParams) {
- result += "<li>" + formParam + "</li>";
+ result.append("<li>" + formParam + "</li>");
}
- result += "</ul>";
+ result.append("</ul>");
}
}
- result += "</td></tr>";
+ result.append("</td></tr>");
}
- result += "</table>";
+ result.append("</table>");
return result;
}
+
+ private String getTypeFromSeeTag(MethodDoc methodDoc) {
+ SeeTag[] seeTags = methodDoc.seeTags();
+ if (seeTags != null && seeTags.length > 0) {
+ for (SeeTag seeTag : seeTags) {
+ if (seeTag.referencedClass() != null) {
+ String name = seeTag.referencedClass().qualifiedTypeName();
+ if (seeTag.referencedMemberName() != null) {
+ name += "#" + seeTag.referencedMemberName();
+ }
+ return name;
+ }
+ }
+ }
+ return null;
+ }
- public String getProduces(MethodDoc methodDoc) throws Exception {
+ public StringBuffer getProduces(MethodDoc methodDoc) throws Exception {
String[] produces = getAnnotationValues(methodDoc, Produces.class);
if (produces != null && produces.length > 0) {
return getMimeTypeTable(methodDoc, getMimeTypes(produces[0]),
false);
}
else
- return "-";
+ return new StringBuffer().append("-");
}
private String[] getMimeTypes(String mimeTypeString) {
@@ -236,7 +265,7 @@
}
private List<String> getParameters(MethodDoc methodDoc, Class<?>
annotationClass) {
- List<String> pathParameters = new ArrayList<String>();
+ List<String> parameters = new ArrayList<String>();
Parameter[] params = methodDoc.parameters();
if (params != null) {
ParamTag[] tags = methodDoc.paramTags();
@@ -260,18 +289,18 @@
if (javadoc != null) {
descr += " : " + javadoc;
}
- pathParameters.add(descr);
+ parameters.add(descr);
}
}
}
}
else if (annotationClass == null) {
// No annotations, this must be a JAXB annotated bean
- pathParameters.add(param.type().toString());
+ parameters.add(param.type().toString());
}
}
}
- return pathParameters;
+ return parameters;
}
private String[] getAnnotationValues(AnnotationDesc[] annotationDescs,
Class<?> annotation) {
Modified:
sandbox/ivol/amdatu-commons/rest-doclet/src/main/java/org/amdatu/commons/restdoclet/JaxbBeanHelper.java
==============================================================================
---
sandbox/ivol/amdatu-commons/rest-doclet/src/main/java/org/amdatu/commons/restdoclet/JaxbBeanHelper.java
(original)
+++
sandbox/ivol/amdatu-commons/rest-doclet/src/main/java/org/amdatu/commons/restdoclet/JaxbBeanHelper.java
Mon Feb 27 08:53:53 2012
@@ -15,6 +15,7 @@
*/
package org.amdatu.commons.restdoclet;
+import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Method;
@@ -23,6 +24,7 @@
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
+import javax.xml.bind.annotation.XmlRootElement;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
@@ -30,7 +32,7 @@
@SuppressWarnings({"restriction", "rawtypes", "unchecked"})
public class JaxbBeanHelper {
private final static Gson GSON = new
GsonBuilder().setPrettyPrinting().create();
-
+
private ClassLoader m_sourceClassLoader;
public JaxbBeanHelper(ClassLoader cl) {
@@ -43,16 +45,58 @@
return true;
}
catch (ClassNotFoundException e) {
- return false;
+ return false;
}
}
-
- public Object createBean(String className) throws Exception {
+
+ public Object createBean(String classMethod, String mimeType, String
httpMethod) throws Exception {
+ String className = classMethod;
+ String methodName = null;
+ if (classMethod.indexOf("#") != -1) {
+ className = classMethod.substring(0, classMethod.indexOf("#"));
+ methodName = classMethod.substring(classMethod.indexOf("#") + 1);
+ }
Class<?> clazz = m_sourceClassLoader.loadClass(className);
- return createBean(clazz, 1);
+ return createBean(clazz, 1, methodName, mimeType, httpMethod);
}
-
- public Object createBean(Class<?> clazz, int index) throws Exception {
+
+ public Object createBean(Class<?> clazz, int index, String methodName,
String mimeType, String httpMethod)
+ throws Exception {
+ // By conventions, the class may contain a static method
getExampleInstance() which returns
+ // an example instance of this bean for the purpose of documentation.
Try to find this method,
+ // otherwise we generate our own instance
+ try {
+ String mName = methodName != null ? methodName :
"getExampleInstance";
+
+ // 1. Try invocation with mimetype and http method
+ try {
+ Method method = clazz.getDeclaredMethod(mName, new Class<?>[]
{String.class, String.class});
+ if (method.getReturnType().isAssignableFrom(clazz)) {
+ return method.invoke(null, mimeType, httpMethod);
+ }
+ }
+ catch (NoSuchMethodException e) {
+ }
+
+ // 2. Try invocation with only mimetype
+ try {
+ Method method = clazz.getDeclaredMethod(mName, new Class<?>[]
{String.class});
+ if (method.getReturnType().isAssignableFrom(clazz)) {
+ return method.invoke(null, mimeType);
+ }
+ }
+ catch (NoSuchMethodException e) {
+ }
+
+ // 3. Try invocation with no parameters
+ Method method = clazz.getDeclaredMethod(mName, new Class<?>[0]);
+ if (method.getReturnType().isAssignableFrom(clazz)) {
+ return method.invoke(null);
+ }
+ }
+ catch (Exception e) {
+ }
+
// Invoke default constructor
Object obj = clazz.newInstance();
@@ -79,17 +123,18 @@
String type =
method.getGenericParameterTypes()[0].toString();
String cls = type.substring(type.indexOf("<") + 1,
type.indexOf(">"));
Class listClass = m_sourceClassLoader.loadClass(cls);
- Object val1 = createBean(listClass, 1);
- Object val2 = createBean(listClass, 2);
+ Object val1 = createBean(listClass, 1, null, mimeType,
httpMethod);
+ Object val2 = createBean(listClass, 2, null, mimeType,
httpMethod);
List values = new ArrayList();
values.add(val1);
values.add(val2);
method.invoke(obj, values);
- } else {
+ }
+ else {
// Another bean type
String type = paramType.getName();
Class listClass = m_sourceClassLoader.loadClass(type);
- Object val = createBean(listClass, 1);
+ Object val = createBean(listClass, 1, null, mimeType,
httpMethod);
method.invoke(obj, val);
}
}
@@ -97,27 +142,34 @@
}
return obj;
}
-
- public String toJSON(Object bean) {
+
+ public String toJSON(Object bean) throws IOException {
+ XmlRootElement rootElement =
bean.getClass().getAnnotation(XmlRootElement.class);
+ String name = null;
+ if (rootElement != null) {
+ name = rootElement.name();
+ }
String json = GSON.toJson(bean);
+
+ json = "{\"" + name + "\": " + json + "}";
json = json.replace(" ", " ").replace("\n", "<br/>");
return json;
}
-
+
public String toXML(Object bean) throws Exception {
JAXBContext context = JAXBContext.newInstance(bean.getClass());
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
-
+
Writer sWriter = new StringWriter();
- marshaller.marshal(bean, sWriter);
-
+ marshaller.marshal(bean, sWriter);
+
String html = sWriter.toString();
html = html.replace("<", "<");
html = html.replace(">", ">");
html = html.replace("\n", "<br/>");
html = html.replace(" ", " ");
-
+
return html;
}
}
Modified:
sandbox/ivol/amdatu-commons/rest-doclet/src/main/java/org/amdatu/commons/restdoclet/RESTDoclet.java
==============================================================================
---
sandbox/ivol/amdatu-commons/rest-doclet/src/main/java/org/amdatu/commons/restdoclet/RESTDoclet.java
(original)
+++
sandbox/ivol/amdatu-commons/rest-doclet/src/main/java/org/amdatu/commons/restdoclet/RESTDoclet.java
Mon Feb 27 08:53:53 2012
@@ -43,19 +43,21 @@
public static void main(String[] args) {
log("Executing RESTDoclet");
- com.sun.tools.javadoc.Main.execute(new String[] { "@options",
"@packages" });
+ System.out.println("!!!!!!!!!!LC: " +
RESTDoclet.class.getClassLoader().toString());
+
+ com.sun.tools.javadoc.Main.execute(new String[] {"@options"});
}
-
+
private static void log(String msg) {
System.out.println("[INFO] " + msg);
}
public static boolean start(RootDoc root) throws Exception {
log("Generating REST dcoumentation");
-
- // Initialize the sourec class loader
+
+ // Initialize the source class loader
m_classAnalyzer.setSourceClassLoader(createSourceClassLoader(root));
-
+
// Ensure /html exists
new File("html").mkdir();
@@ -77,7 +79,7 @@
log("Finished REST documentation");
return true;
}
-
+
private static URLClassLoader createSourceClassLoader(RootDoc root) throws
MalformedURLException {
String classpath = "";
for (String[] option : root.options()) {
@@ -85,17 +87,17 @@
classpath = option[1];
}
}
-
+
// Depending on OS the classpath separator is ; or :
String sep = File.pathSeparator;
String[] classPathEntries = classpath.split(sep);
URL[] urls = new URL[classPathEntries.length];
- for (int i=0; i<classPathEntries.length; i++) {
+ for (int i = 0; i < classPathEntries.length; i++) {
urls[i] = new File(classPathEntries[i]).toURL();
}
-
+
log("classpath=" + classpath);
- return new URLClassLoader(urls);
+ return new URLClassLoader(urls, RESTDoclet.class.getClassLoader());
}
private static void copyFile(String source, String target) throws
IOException {
@@ -106,7 +108,7 @@
if (new File("html/" + target).exists()) {
new File("html/" + target).delete();
}
-
+
InputStream is = null;
FileOutputStream out = null;
try {
@@ -115,7 +117,7 @@
byte[] bytes = new byte[1024];
int len;
- while ((len = is.read(bytes)) != -1) {
+ while ((len = is.read(bytes)) != -1) {
out.write(bytes, 0, len);
}
}
@@ -172,7 +174,7 @@
lines.add("</head>");
lines.add("<body>");
lines.add("<div class='ui-state-highlight ui-corner-all'
align='center'>");
- lines.add("<h3>REST documentation for " +
m_classAnalyzer.getPath(classDoc, null) + "</h3></div>");
+ lines.add("<h3>REST documentation for " +
m_classAnalyzer.getPath(classDoc, null) + "</h3></div>");
lines.add("<div id='accordion'>");
FileUtils.writeLines(m_file, lines, EOL, true);
}
@@ -189,20 +191,36 @@
log(" Generating documentation for HTTP method " +
methodDoc.name());
Collection<String> lines = new ArrayList<String>();
- lines.add("<h3><a href='#'>" +
m_classAnalyzer.getHTTPMethod(methodDoc) + " "
- + m_classAnalyzer.getPath(classDoc, methodDoc) +
"</a></h3>");
+ lines.add("<h3><a href='#'>" +
m_classAnalyzer.getHTTPMethod(methodDoc) + " "
+ + m_classAnalyzer.getPath(classDoc, methodDoc) + "</a></h3>");
lines.add("<div><table>");
-
+
lines.add(getRow("Method", m_classAnalyzer.getHTTPMethod(methodDoc)));
lines.add(getRow("URI", m_classAnalyzer.getPath(classDoc, methodDoc)));
- lines.add(getRow("Path parameters",
toUl(m_classAnalyzer.getPathParameters(methodDoc))));
- lines.add(getRow("Query parameters",
toUl(m_classAnalyzer.getQueryParameters(methodDoc))));
+
+ // Path parameters
+ List<String> pathParameters =
m_classAnalyzer.getPathParameters(methodDoc);
+ if (pathParameters.size() > 0) {
+ lines.add(getRow("Path parameters", toUl(pathParameters)));
+ }
+
+ // Query parameters
+ List<String> queryParameters =
m_classAnalyzer.getQueryParameters(methodDoc);
+ if (queryParameters.size() > 0) {
+ lines.add(getRow("Query parameters", toUl(queryParameters)));
+ }
+ // Description
lines.add(getRow("Description",
m_classAnalyzer.getDescription(methodDoc)));
-
- lines.add(getRow("Consumes", m_classAnalyzer.getConsumes(methodDoc)));
+
+ // Consumes
+ StringBuffer consumes = m_classAnalyzer.getConsumes(methodDoc);
+ if (consumes != null) {
+ lines.add(getRow("Consumes", consumes));
+ }
lines.add(getRow("Produces", m_classAnalyzer.getProduces(methodDoc)));
-
+
+ // Response
lines.add(getRow("Response", m_classAnalyzer.getReturn(methodDoc)));
lines.add("</table></div>");
FileUtils.writeLines(m_file, lines, EOL, true);
@@ -212,6 +230,10 @@
return "<tr><th>" + key + "</th><td>" + value + "</td></tr>";
}
+ private static String getRow(String key, StringBuffer value) {
+ return "<tr><th>" + key + "</th><td>" + value.toString() +
"</td></tr>";
+ }
+
private static String toUl(List<String> values) {
if (values != null && values.size() > 0) {
String ul = "<ul>";
_______________________________________________
Amdatu-commits mailing list
[email protected]
http://lists.amdatu.org/mailman/listinfo/amdatu-commits