You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by dh...@apache.org on 2014/07/23 21:42:44 UTC
git commit: CAMEL-7613 Updated camel-api-component-maven-plugin to
support parsing Java8 Javadoc HTML
Repository: camel
Updated Branches:
refs/heads/master 966846055 -> 7eef2d129
CAMEL-7613 Updated camel-api-component-maven-plugin to support parsing Java8 Javadoc HTML
Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/7eef2d12
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/7eef2d12
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/7eef2d12
Branch: refs/heads/master
Commit: 7eef2d12930c53cbbe97c8528ed6fa6e13a1e1dc
Parents: 9668460
Author: Dhiraj Bokde <dh...@yahoo.com>
Authored: Wed Jul 23 12:42:21 2014 -0700
Committer: Dhiraj Bokde <dh...@yahoo.com>
Committed: Wed Jul 23 12:42:38 2014 -0700
----------------------------------------------------------------------
.../maven/JavadocApiMethodGeneratorMojo.java | 161 +--------------
.../org/apache/camel/maven/JavadocParser.java | 197 +++++++++++++++++++
.../apache/camel/maven/JavadocParserTest.java | 55 ++++++
3 files changed, 253 insertions(+), 160 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/camel/blob/7eef2d12/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/JavadocApiMethodGeneratorMojo.java
----------------------------------------------------------------------
diff --git a/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/JavadocApiMethodGeneratorMojo.java b/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/JavadocApiMethodGeneratorMojo.java
index 572fbf9..dd76a02 100644
--- a/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/JavadocApiMethodGeneratorMojo.java
+++ b/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/JavadocApiMethodGeneratorMojo.java
@@ -19,25 +19,17 @@ package org.apache.camel.maven;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
-import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
-import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import javax.swing.text.ChangedCharSetException;
-import javax.swing.text.SimpleAttributeSet;
-import javax.swing.text.html.HTML;
import javax.swing.text.html.parser.DTD;
-import javax.swing.text.html.parser.Parser;
-import javax.swing.text.html.parser.TagElement;
import org.apache.camel.util.component.ApiMethodParser;
-import org.apache.commons.lang.StringEscapeUtils;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
@@ -58,7 +50,6 @@ public class JavadocApiMethodGeneratorMojo extends AbstractApiMethodGeneratorMoj
}
protected static final String DEFAULT_EXCLUDE_PACKAGES = "javax?\\.lang.*";
- private static final Pattern ARGTYPES_PATTERN = Pattern.compile("\\s*([^<\\s,]+\\s*(<[^>]+>)?)\\s*,?");
private static final Pattern RAW_ARGTYPES_PATTERN = Pattern.compile("\\s*([^<\\s,]+)\\s*(<[^>]+>)?\\s*,?");
@Parameter(property = PREFIX + "excludePackages", defaultValue = DEFAULT_EXCLUDE_PACKAGES)
@@ -139,9 +130,7 @@ public class JavadocApiMethodGeneratorMojo extends AbstractApiMethodGeneratorMoj
}
final String resultType = getResultType(aClass, name, types);
if (resultType != null) {
- final StringBuilder signature = new StringBuilder(resultType);
- signature.append(" ").append(name).append(methodMap.get(method));
- result.put(method, signature.toString());
+ result.put(method, resultType + " " + name + methodMap.get(method));
}
}
}
@@ -194,152 +183,4 @@ public class JavadocApiMethodGeneratorMojo extends AbstractApiMethodGeneratorMoj
return result;
}
- private static class JavadocParser extends Parser {
- private static final String NON_BREAKING_SPACE = "\u00A0";
- private String hrefPattern;
-
- private ParserState parserState;
- private String methodWithTypes;
- private StringBuilder methodTextBuilder = new StringBuilder();
-
- private List<String> methods = new ArrayList<String>();
- private Map<String, String> methodText = new HashMap<String, String>();
- private String errorMessage;
-
- public JavadocParser(DTD dtd, String docPath) {
- super(dtd);
- this.hrefPattern = docPath + "#";
- }
-
- @Override
- protected void startTag(TagElement tag) throws ChangedCharSetException {
- super.startTag(tag);
-
- final HTML.Tag htmlTag = tag.getHTMLTag();
- if (htmlTag != null) {
- if (HTML.Tag.A.equals(htmlTag)) {
- final SimpleAttributeSet attributes = getAttributes();
- final Object name = attributes.getAttribute(HTML.Attribute.NAME);
- if (name != null) {
- final String nameAttr = (String) name;
- if (parserState == null && "method_summary".equals(nameAttr)) {
- parserState = ParserState.METHOD_SUMMARY;
- } else if (parserState == ParserState.METHOD_SUMMARY && nameAttr.startsWith("methods_inherited_from_class_")) {
- parserState = null;
- } else if (parserState == ParserState.METHOD && methodWithTypes == null) {
- final Object href = attributes.getAttribute(HTML.Attribute.HREF);
- if (href != null) {
- String hrefAttr = (String) href;
- if (hrefAttr.contains(hrefPattern)) {
- // unescape HTML
- methodWithTypes = unescapeHtml(hrefAttr.substring(hrefAttr.indexOf('#') + 1));
- }
- }
- }
- }
- } else if (parserState == ParserState.METHOD_SUMMARY && HTML.Tag.CODE.equals(htmlTag)) {
- parserState = ParserState.METHOD;
- }
- }
- }
-
- private static String unescapeHtml(String htmlString) {
- String result = StringEscapeUtils.unescapeHtml(htmlString).replaceAll(NON_BREAKING_SPACE, " ");
- try {
- result = URLDecoder.decode(result, "UTF-8");
- } catch (UnsupportedEncodingException ignored) {
-
- }
- return result;
- }
-
- @Override
- protected void handleEmptyTag(TagElement tag) {
- if (parserState == ParserState.METHOD && HTML.Tag.CODE.equals(tag.getHTMLTag())) {
- if (methodWithTypes != null) {
- // process collected method data
- methods.add(methodWithTypes);
- this.methodText.put(methodWithTypes, getArgSignature());
-
- // clear the text builder for next method
- methodTextBuilder.delete(0, methodTextBuilder.length());
- methodWithTypes = null;
- }
-
- parserState = ParserState.METHOD_SUMMARY;
- }
- }
-
- private String getArgSignature() {
- final String typeString = methodWithTypes.substring(methodWithTypes.indexOf('(') + 1, methodWithTypes.indexOf(')'));
- if (typeString.isEmpty()) {
- return "()";
- }
-
- // split types list
- final List<String> typeList = new ArrayList<String>();
- final Matcher typeMatcher = ARGTYPES_PATTERN.matcher(typeString);
- while (typeMatcher.find()) {
- typeList.add(typeMatcher.group(1).replaceAll(" ", ""));
- }
-
- // unescape HTML method text
- final String plainText = unescapeHtml(methodTextBuilder.toString());
- final String argsString = plainText.substring(plainText.indexOf('(') + 1, plainText.indexOf(')'));
- final Matcher argMatcher = ApiMethodParser.ARGS_PATTERN.matcher(argsString);
- final List<String> argNames = new ArrayList<String>();
- while (argMatcher.find()) {
- argNames.add(argMatcher.group(3));
- }
-
- // make sure number of types and names match
- final int nTypes = typeList.size();
- if (nTypes != argNames.size()) {
- throw new IllegalArgumentException("Unexpected Javadoc error, different number of arg types and names");
- }
-
- final String[] names = argNames.toArray(new String[nTypes]);
- final StringBuilder builder = new StringBuilder("(");
- int i = 0;
- for (String type : typeList) {
- // split on space or non-breaking space
- builder.append(type).append(' ').append(names[i++]);
- if (i < nTypes) {
- builder.append(',');
- }
- }
- builder.append(')');
- return builder.toString();
- }
-
- @Override
- protected void handleText(char[] text) {
- if (parserState == ParserState.METHOD && methodWithTypes != null) {
- methodTextBuilder.append(text);
- }
- }
-
- @Override
- protected void handleError(int ln, String msg) {
- if (msg.startsWith("exception ")) {
- this.errorMessage = "Exception parsing Javadoc line " + ln + ": " + msg;
- }
- }
-
- private String getErrorMessage() {
- return errorMessage;
- }
-
- private List<String> getMethods() {
- return methods;
- }
-
- private Map<String, String> getMethodText() {
- return methodText;
- }
- }
-
- private static enum ParserState {
- METHOD_SUMMARY, METHOD;
- }
}
http://git-wip-us.apache.org/repos/asf/camel/blob/7eef2d12/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/JavadocParser.java
----------------------------------------------------------------------
diff --git a/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/JavadocParser.java b/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/JavadocParser.java
new file mode 100644
index 0000000..24e4489
--- /dev/null
+++ b/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/JavadocParser.java
@@ -0,0 +1,197 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.camel.maven;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.swing.text.ChangedCharSetException;
+import javax.swing.text.SimpleAttributeSet;
+import javax.swing.text.html.HTML;
+import javax.swing.text.html.parser.DTD;
+import javax.swing.text.html.parser.Parser;
+import javax.swing.text.html.parser.TagElement;
+
+import org.apache.commons.lang.StringEscapeUtils;
+
+/**
+ * Parses Javadoc HTML to get Method Signatures from Method Sumary. Supports Java 6, 7 and 8 Javadoc formats.
+ */
+public class JavadocParser extends Parser {
+
+ private static final String NON_BREAKING_SPACE = "\u00A0";
+
+ private final String hrefPattern;
+
+ private ParserState parserState;
+ private String methodWithTypes;
+ private StringBuilder methodTextBuilder = new StringBuilder();
+
+ private List<String> methods = new ArrayList<String>();
+ private Map<String, String> methodText = new HashMap<String, String>();
+ private String errorMessage;
+
+ public JavadocParser(DTD dtd, String docPath) {
+ super(dtd);
+ this.hrefPattern = docPath + "#";
+ parserState = ParserState.INIT;
+ }
+
+ public void reset() {
+ parserState = ParserState.INIT;
+
+ methodWithTypes = null;
+ methodTextBuilder = new StringBuilder();
+
+ methods.clear();
+ methodText.clear();
+
+ errorMessage = null;
+ }
+
+ @Override
+ protected void startTag(TagElement tag) throws ChangedCharSetException {
+ super.startTag(tag);
+
+ final HTML.Tag htmlTag = tag.getHTMLTag();
+ if (htmlTag != null) {
+ if (HTML.Tag.A.equals(htmlTag)) {
+ final SimpleAttributeSet attributes = getAttributes();
+ final Object name = attributes.getAttribute(HTML.Attribute.NAME);
+ if (name != null) {
+ final String nameAttr = (String) name;
+ if (parserState == ParserState.INIT
+ && ("method_summary".equals(nameAttr) || "method.summary".equals(nameAttr))) {
+ parserState = ParserState.METHOD_SUMMARY;
+ } else if (parserState == ParserState.METHOD) {
+ if (methodWithTypes == null) {
+
+ final String hrefAttr = (String) attributes.getAttribute(HTML.Attribute.HREF);
+ if (hrefAttr != null && hrefAttr.contains(hrefPattern)) {
+
+ // unescape HTML
+ String methodSignature = hrefAttr.substring(hrefAttr.indexOf('#') + 1);
+ final int firstHyphen = methodSignature.indexOf('-');
+ if (firstHyphen != -1) {
+ final int lastHyphen = methodSignature.lastIndexOf('-');
+ methodSignature = methodSignature.substring(0, firstHyphen) + "("
+ + methodSignature.substring(firstHyphen + 1, lastHyphen) + ")";
+ methodSignature = methodSignature.replaceAll("-", ",");
+ }
+ // support varargs
+ if (methodSignature.contains("...)")) {
+ methodSignature = methodSignature.replaceAll("\\.\\.\\.\\)", "[])");
+ }
+ // map Java8 array types
+ if (methodSignature.contains(":A")) {
+ methodSignature = methodSignature.replaceAll(":A", "[]");
+ }
+ methodWithTypes = unescapeHtml(methodSignature);
+ }
+ } else {
+ final String title = (String) attributes.getAttribute(HTML.Attribute.TITLE);
+ if (title != null) {
+ // append package name to type name text
+ methodTextBuilder.append(title.substring(title.lastIndexOf(' '))).append('.');
+ }
+ }
+ }
+ }
+ } else if (parserState == ParserState.METHOD_SUMMARY && HTML.Tag.CODE.equals(htmlTag)) {
+ parserState = ParserState.METHOD;
+ }
+ }
+ }
+
+ private static String unescapeHtml(String htmlString) {
+ String result = StringEscapeUtils.unescapeHtml(htmlString).replaceAll(NON_BREAKING_SPACE, " ");
+ try {
+ result = URLDecoder.decode(result, "UTF-8");
+ } catch (UnsupportedEncodingException ignored) {
+
+ }
+ return result;
+ }
+
+ @Override
+ protected void handleEmptyTag(TagElement tag) {
+ if (parserState == ParserState.METHOD && HTML.Tag.CODE.equals(tag.getHTMLTag())) {
+ if (methodWithTypes != null) {
+ // process collected method data
+ methods.add(methodWithTypes);
+ this.methodText.put(methodWithTypes, getArgSignature());
+
+ // clear the text builder for next method
+ methodTextBuilder.delete(0, methodTextBuilder.length());
+ methodWithTypes = null;
+ }
+
+ parserState = ParserState.METHOD_SUMMARY;
+ } else if (parserState == ParserState.METHOD_SUMMARY && HTML.Tag.TABLE.equals(tag.getHTMLTag())) {
+ // end of method summary table
+ parserState = ParserState.INIT;
+ }
+ }
+
+ private String getArgSignature() {
+ final String typeString = methodWithTypes.substring(methodWithTypes.indexOf('(') + 1, methodWithTypes.indexOf(')'));
+ if (typeString.isEmpty()) {
+ return "()";
+ }
+
+ // unescape HTML method text
+ String plainText = unescapeHtml(methodTextBuilder.toString());
+ // support varargs
+ if (plainText.contains("...")) {
+ plainText = plainText.replaceAll("\\.\\.\\.", "[]");
+ }
+ return plainText.substring(plainText.indexOf('('), plainText.indexOf(')') + 1);
+ }
+
+ @Override
+ protected void handleText(char[] text) {
+ if (parserState == ParserState.METHOD && methodWithTypes != null) {
+ methodTextBuilder.append(text);
+ }
+ }
+
+ @Override
+ protected void handleError(int ln, String msg) {
+ if (msg.startsWith("exception ")) {
+ this.errorMessage = "Exception parsing Javadoc line " + ln + ": " + msg;
+ }
+ }
+
+ public String getErrorMessage() {
+ return errorMessage;
+ }
+
+ public List<String> getMethods() {
+ return methods;
+ }
+
+ public Map<String, String> getMethodText() {
+ return methodText;
+ }
+
+ private static enum ParserState {
+ INIT, METHOD_SUMMARY, METHOD
+ }
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/7eef2d12/tooling/maven/camel-api-component-maven-plugin/src/test/java/org/apache/camel/maven/JavadocParserTest.java
----------------------------------------------------------------------
diff --git a/tooling/maven/camel-api-component-maven-plugin/src/test/java/org/apache/camel/maven/JavadocParserTest.java b/tooling/maven/camel-api-component-maven-plugin/src/test/java/org/apache/camel/maven/JavadocParserTest.java
new file mode 100644
index 0000000..c98812d
--- /dev/null
+++ b/tooling/maven/camel-api-component-maven-plugin/src/test/java/org/apache/camel/maven/JavadocParserTest.java
@@ -0,0 +1,55 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.camel.maven;
+
+import java.io.InputStreamReader;
+import java.net.URL;
+import javax.swing.text.html.parser.DTD;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Test JavadocParser using {@link java.lang.String} javadoc for Java 6, 7 and 8.
+ */
+public class JavadocParserTest extends Assert {
+
+ private static final String JAVA6_STRING = "http://docs.oracle.com/javase/6/docs/api/java/lang/String.html";
+ private static final String JAVA7_STRING = "http://docs.oracle.com/javase/7/docs/api/java/lang/String.html";
+ private static final String JAVA8_STRING = "http://docs.oracle.com/javase/8/docs/api/java/lang/String.html";
+
+ @Test
+ public void testGetMethods() throws Exception {
+ final DTD dtd = DTD.getDTD("html.dtd");
+ final String javaDocPath = String.class.getName().replaceAll("\\.", "/") + ".html";
+ final JavadocParser htmlParser = new JavadocParser(dtd, javaDocPath);
+
+ htmlParser.parse(new InputStreamReader(new URL(JAVA6_STRING).openStream(), "UTF-8"));
+ assertNull("Java6 getErrorMessage", htmlParser.getErrorMessage());
+ assertFalse("Java6 getMethods", htmlParser.getMethods().isEmpty());
+ htmlParser.reset();
+
+ htmlParser.parse(new InputStreamReader(new URL(JAVA7_STRING).openStream(), "UTF-8"));
+ assertNull("Java7 getErrorMessage", htmlParser.getErrorMessage());
+ assertFalse("Java7 getMethods", htmlParser.getMethods().isEmpty());
+ htmlParser.reset();
+
+ htmlParser.parse(new InputStreamReader(new URL(JAVA8_STRING).openStream(), "UTF-8"));
+ assertNull("Java8 getErrorMessage", htmlParser.getErrorMessage());
+ assertFalse("Java8 getMethods", htmlParser.getMethods().isEmpty());
+ }
+}