Java tutorial
/* * Copyright (c) 2003- Shinji Kashihara. All rights reserved. * This program are made available under the terms of the Common Public License * v1.0 which accompanies this distribution, and is available at cpl-v10.html. */ package mergedoc.core; import java.util.ArrayList; import java.util.List; import java.util.Stack; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Java ??? * @author Shinji Kashihara */ public class JavaBuffer { /** */ private static final Log log = LogFactory.getLog(JavaBuffer.class); /** class|interface|@interface|enum */ private String classKind; /** ?? */ private final String className; /** Java */ private final String source; /** ? */ private static final Pattern commentPattern = PatternCache.getPattern("(?sm)^ *?/\\*\\*.*?\\*/ *?\\n?"); /** ?? */ private final Matcher commentMatcher; /** ? */ private final StringBuffer outputBuffer = new StringBuffer(); /** ??????? */ private static class ClassBlock { final String name; final int end; ClassBlock(String name, int end) { this.name = name; this.end = end; } } /** ClassBlock */ private final Stack<ClassBlock> classStack = new Stack<ClassBlock>(); /** ?????? */ private static final String DUMMY_COMMENT = "/** Empty comment. " + JavaBuffer.class.getName() + ". */\n"; /** * ?? * @param classKind * @param className ?? * @param javaSource Java */ public JavaBuffer(String classKind, String className, String javaSource) { this.classKind = classKind; this.className = className; this.source = setupDummyComment(javaSource); commentMatcher = commentPattern.matcher(source); // ? ClassBlock cb = new ClassBlock(className, source.length()); classStack.push(cb); } /** * Javadoc ?????? * <p> * Javadoc ???? Java nextComment ? * ??????????? * ??? classBlock ????? * <p> * ????? Javadoc ??????? * ??? Javadoc ???????Javadoc * ???? Javadoc API ??? * <pre> * JDK1.4 javax.swing.JEditorPane ? ?? * JEditorPaneAccessibleHypertextSupport.HTMLLink ?? * </pre> * <p> * JDK1.4 java.beans.beancontext.BeanContextServicesSupport#BCSSChild ? * /* ????????Javadoc ????? * Javadoc API ??????????????? * ?????? * * @param src Java * @return ?? */ private String setupDummyComment(String src) { // ? Javadoc ??????? // ?????????????? // ????????? // ? //Matcher mat = Pattern.compile("\\{[^@]").matcher(src); //int pos = 0; //if (mat.find()) pos = mat.start(); //String head = src.substring(0, pos); //String body = src.substring(pos); //body = body.replaceAll( // "([^/\\s]( *?\n)+)((\\s*)[\\w\\s]*\\s(class|interface)\\s)", // "$1$4/\\*\\*" + DUMMY_COMMENT + "\\*/\n$3"); //return head + body; //---------------------------------------------------------------------- // ????? Profiler ????? // ??????????? 1 ???? // ??? 6 ?? // ???????????? // ? Javadoc ?????? // ?? // // ????? // JDK1.4 java.net.Authenticator ?? // ????? // JDK1.4 javax.swing.plaf.basic.BasicTableUI ?? //---------------------------------------------------------------------- char[] c = src.toCharArray(); int last = c.length - 1; List<Integer> dummyInsertPositions = new ArrayList<Integer>(); int declareMaxLength = 12; for (int i = declareMaxLength; i <= last; i++) { if (c[i - 1] == '/' && c[i] == '*') { // ??? for (i++; i <= last; i++) { if (c[i - 1] == '*' && c[i] == '/') { break; } } } else if (c[i - 1] == '/' && c[i] == '/') { // ??? for (i++; i <= last; i++) { if (c[i] == '\n') { i++; break; } } } else if (c[i - 1] != '\'' && c[i] == '"') { // ?????? for (i++; i <= last; i++) { if (c[i] == '"') { if (c[i - 1] != '\\' || (c[i - 1] == '\\' && c[i - 2] == '\\')) { break; } } } } else if (c[i - 1] != '"' && c[i] == '\'') { // ?????? for (i++; i <= last; i++) { if (c[i] == '\'') { if (c[i - 1] != '\\' || (c[i - 1] == '\\' && c[i - 2] == '\\')) { break; } } } } if (i >= last) { break; } // ??? // class|interface|@interface|enum int declaPos = -1; if (c[i] == ' ' || c[i] == '\n' || c[i] == '<') { if (c[i - 5] == 'c' && c[i - 4] == 'l' && c[i - 3] == 'a' && c[i - 2] == 's' && c[i - 1] == 's') { // class ?? if (c[i - 6] == ' ' || c[i - 6] == '\n') { declaPos = i - 7; } } else if (c[i - 9] == 'i' && c[i - 8] == 'n' && c[i - 7] == 't' && c[i - 6] == 'e' && c[i - 5] == 'r' && c[i - 4] == 'f' && c[i - 3] == 'a' && c[i - 2] == 'c' && c[i - 1] == 'e') { // interface ?? if (c[i - 10] == ' ' || c[i - 10] == '\n') { declaPos = i - 11; } else if (c[i - 10] == '@') { // @interface ?? if (c[i - 11] == ' ' || c[i - 11] == '\n') { declaPos = i - 12; } } } else if (c[i - 4] == 'e' && c[i - 3] == 'n' && c[i - 2] == 'u' && c[i - 1] == 'm') { // enum ?? if (c[i - 5] == ' ' || c[i - 5] == '\n') { declaPos = i - 6; } } } // ? Javadoc ?????? for (int j = declaPos; j > 0; j--) { if (c[j - 1] == '*' && c[j] == '/') { break; } if (c[j] == ';' || c[j] == '}' || c[j] == '{') { for (int k = j - 1; k > 0; k--) { if (c[k - 1] == '/' && c[k] == '/') { break; } if (c[k] == '\n') { for (int l = j + 1; l < i; l++) { if (c[l] == '\n') { dummyInsertPositions.add(l + 1); k = -1; j = -1; break; } } } } } } } // ??? Javadoc ? StringBuilder sb = new StringBuilder(src); for (int i = dummyInsertPositions.size() - 1; i >= 0; i--) { int pos = dummyInsertPositions.get(i); sb.insert(pos, DUMMY_COMMENT); } return sb.toString(); } /** * ??????? * ????????? * ???????????? * @return ????? true */ public boolean nextComment() { while (commentMatcher.find()) { // ??????? // /*******************/ // JDK1.4 java.io.ObjectStreamConstants ?? String sourceComment = getSourceComment(); if (FastStringUtils.matches(sourceComment, "\\s*/\\*+/\\s*\n")) { continue; } // ?????? if (sourceComment.contains(DUMMY_COMMENT)) { getSignature(); //?????? commentMatcher.appendReplacement(outputBuffer, ""); continue; } // ????????? Matcher nextMat = commentPattern.matcher(source); int currentEnd = commentMatcher.end(); if (nextMat.find(currentEnd)) { String c2c = source.substring(currentEnd, nextMat.start()); // ?(java.awt.GridBagLayoutorg.omg.PortableServer.Servant??) c2c = PatternCache.getPattern("(?s)/\\*(?:[^\\*].*?)?\\*/").matcher(c2c).replaceAll(""); c2c = PatternCache.getPattern("//.*").matcher(c2c).replaceAll(""); if (FastStringUtils.matches(c2c, "\\s*")) { continue; } } return true; } return false; } /** * ??????? * @return ??? */ private String getSourceComment() { return commentMatcher.group(); } /** * ????????? * @return ?????????? null */ public Signature getSignature() { int commentEndPos = commentMatcher.end(); String commentEndToEOF = source.substring(commentEndPos, source.length()); // ?????????? Matcher matcher = PatternCache.getPattern("(?s)/\\*(.*?)\\*/").matcher(commentEndToEOF); StringBuffer sb = new StringBuffer(commentEndToEOF.length()); while (matcher.find()) { matcher.appendReplacement(sb, "/*"); char[] cs = matcher.group(1).toCharArray(); for (char c : cs) { switch (c) { case '*': case '\n': sb.append(c); break; default: sb.append(' '); break; } } sb.append("*/"); } matcher.appendTail(sb); commentEndToEOF = sb.toString(); // ??????????? commentEndToEOF = FastStringUtils.replaceFirst(commentEndToEOF, "(?s)^(\\s*@[\\w]+\\s*\\(.*?\\))*\\s*", ""); Pattern sigPattern = PatternCache.getPattern("(?s)(.+?)(throws|\\{|\\=|;|,\\s*/\\*|\\})"); Matcher sigMatcher = sigPattern.matcher(commentEndToEOF); if (sigMatcher.find()) { // ????? ClassBlock classBlock = classStack.peek(); while (commentEndPos > classBlock.end && classStack.size() > 1) { classStack.pop(); classBlock = classStack.peek(); } // ???Javadoc ????? // ????????? String sigStr = sigMatcher.group(1); sigStr = FastStringUtils.replaceFirst(sigStr, "(?s)/\\*[^\\*].*?\\*/\\s*", ""); if (classKind.equals("@interface")) { sigStr = sigStr.replace("()", ""); } Signature sig = new Signature(classBlock.name, sigStr); // ???? if (sig.isDeclareInnerClass()) { String name = sig.getClassName(); int end = searchEndOfInner(commentEndToEOF, name); classBlock = new ClassBlock(name, end); classStack.push(classBlock); } return sig; } log.warn("Javadoc ?????????????\n" + commentEndToEOF); return null; } public static String repeat(char ch, int repeat) { char[] buf = new char[repeat]; for (int i = repeat - 1; i >= 0; i--) { buf[i] = ch; } return new String(buf); } /** * ?????? * @param currentToEnd ??????? * @param iClassName ?? * @return ?? */ private int searchEndOfInner(String currentToEnd, String iClassName) { // ? { ???}????????????? // ????? java.util.Spliterators int nestLevel = 0; char[] c = currentToEnd.toCharArray(); int last = c.length - 1; boolean startInnerClass = false; for (int i = 1; i <= last; i++) { if (c[i - 1] == '{') { nestLevel++; startInnerClass = true; } else if (c[i - 1] == '}') { nestLevel--; } if (startInnerClass == true && nestLevel == 0) { return commentMatcher.end() + i - 1; } if (c[i - 1] == '/' && c[i] == '*') { // ??? for (i++; i <= last; i++) { if (c[i - 1] == '*' && c[i] == '/') { break; } } } else if (c[i - 1] == '/' && c[i] == '/') { // ??? for (i++; i <= last; i++) { if (c[i] == '\n') { i++; break; } } } else if (c[i - 1] != '\'' && c[i] == '"') { // ?????? for (i++; i <= last; i++) { if (c[i] == '"') { if (c[i - 1] != '\\' || (c[i - 1] == '\\' && c[i - 2] == '\\')) { break; } } } } else if (c[i - 1] != '"' && c[i] == '\'') { // ?????? for (i++; i <= last; i++) { if (c[i] == '\'') { if (c[i - 1] != '\\' || (c[i - 1] == '\\' && c[i - 2] == '\\')) { break; } } } } } log.warn(" " + className + "#" + iClassName + " ???????????"); return -1; } /** * ???????? * ??? null ?????? * @param sig ?? * @param comment ?? */ public void setLocalizedComment(Signature sig, Comment comment) { if (comment == null) { return; } String srcComment = getSourceComment(); comment.setSourceBody(srcComment); String docComment = comment.buildComment(); // debug setLocalizedComment ????? //log.debug("??: " + sig); //log.debug(" Java :\n" + srcComment); //log.debug(" API :\n" + docComment + "\n--------------"); if (docComment == null || docComment.length() == 0) { return; } docComment = FastStringUtils.quoteReplacement(docComment); commentMatcher.appendReplacement(outputBuffer, docComment); } /** * ???? Java ???? * @return ?? Java */ public String finishToString() { commentMatcher.appendTail(outputBuffer); String str = outputBuffer.toString(); return str; } }