2 * Copyright (c) 2009 The openGion Project.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13 * either express or implied. See the License for the specific language
14 * governing permissions and limitations under the License.
16 package org.opengion.fukurou.taglet; // 7.4.4.0 (2021/06/30) openGionV8事前準備(taglet2→taglet)
18 import jdk.javadoc.doclet.DocletEnvironment ;
19 // import jdk.javadoc.doclet.Doclet ;
20 // import jdk.javadoc.doclet.Reporter ;
21 // import javax.lang.model.element.Element ;
22 import javax.lang.model.element.Modifier ;
23 import javax.lang.model.element.TypeElement;
24 // import javax.lang.model.element.ElementKind ;
25 // import javax.lang.model.element.VariableElement;
26 import javax.lang.model.element.ExecutableElement;
27 // import javax.lang.model.SourceVersion ;
28 import javax.lang.model.type.TypeMirror;
29 import javax.lang.model.type.TypeKind;
30 import javax.lang.model.util.ElementFilter ;
31 import javax.lang.model.util.Elements ;
32 import javax.tools.Diagnostic.Kind ;
33 import com.sun.source.doctree.DocCommentTree ;
34 import com.sun.source.util.DocTrees ;
35 // import com.sun.source.util.DocSourcePositions ;
36 // import com.sun.source.doctree.DocTree ;
38 // import java.util.Locale ;
41 // import java.util.HashMap;
42 import java.util.List;
43 import java.util.HashSet;
44 import java.util.Arrays;
45 // import java.util.stream.Stream; // 6.4.3.4 (2016/03/11)
46 // import java.util.stream.Collectors; // 6.4.3.4 (2016/03/11)
48 // import java.io.IOException;
49 // import java.io.File;
50 // import java.io.PrintWriter;
52 // import org.opengion.fukurou.util.FileUtil;
53 // import org.opengion.fukurou.util.StringUtil;
56 * ソースコメントから、パラメータ情報を取り出す Doclet クラスです。
57 * og.paramLevel タグと og.cryptography タグを切り出します。
58 * これらは、システムパラメータとしてGE12テーブルに設定される値をクラスより抽出する
62 * @author Kazuhiko Hasegawa
65 public class DocTreeTaglib extends AbstractDocTree {
66 private static final String OG_FOR_SMPL = "og.formSample";
67 private static final String OG_TAG_NAME = "og.tag";
68 private static final String OG_GROUP = "og.group";
70 private static final String DOC_PARAM = "param"; // 6.1.1.0 (2015/01/17)
72 private static final String OG_TAG_CLASS = "org.opengion.hayabusa.taglib";
74 private String version ;
75 private String outfile ;
77 // private DocTrees docUtil;
78 // private Elements eleUtil ;
83 * @og.rev 7.3.0.0 (2021/01/06) PMD refactoring. Each class should declare at least one constructor.
85 public DocTreeTaglib() { super(); } // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
88 * Doclet のエントリポイントメソッドです(昔の startメソッド)。
90 * @og.rev 7.3.0.0 (2021/01/06) 新しいJavaDoc対応
92 * @param docEnv ドックレットを1回呼び出す操作環境
97 public boolean run( final DocletEnvironment docEnv ) {
98 try( DocTreeWriter writer = new DocTreeWriter( outfile,ENCODE ) ) {
99 writer.printTag( "<?xml version=\"1.0\" encoding=\"", ENCODE , "\" ?>" );
100 writer.printTag( "<javadoc>" );
101 writer.printTag( " <version>",version,"</version>" );
102 writer.printTag( " <description></description>" );
103 writeContents( docEnv,writer );
104 writer.printTag( "</javadoc>" );
106 catch( final Throwable th ) {
107 reporter.print(Kind.ERROR, th.getMessage());
114 * DocletEnvironmentよりコンテンツを作成します。
116 * @og.rev 7.3.0.0 (2021/01/06) 新しいJavaDoc対応
117 * @og.rev 8.0.2.1 (2021/12/10) tagGroupがdescriptionと合わせて出力されるため、【】でくくります。
118 * @og.rev 8.0.2.1 (2021/12/10) コメント分割で『。』と半角の『。』の両方対応しておく。
120 * @param docEnv ドックレットの最上位
121 * @param writer DocTreeWriterオブジェクト
123 private void writeContents( final DocletEnvironment docEnv, final DocTreeWriter writer ) {
124 // docUtil = docEnv.getDocTrees();
125 // eleUtil = docEnv.getElementUtils();
127 // // get the DocTrees utility class to access document comments
128 final DocTrees docUtil = docEnv.getDocTrees();
129 final Elements eleUtil = docEnv.getElementUtils();
131 final Set<String> mtdClsSet = new HashSet<>(); // 6.4.3.1 (2016/02/12) 変数名も変えておきます。
134 for( final TypeElement typEle : ElementFilter.typesIn(docEnv.getIncludedElements())) {
135 final String fullName = String.valueOf( typEle.getQualifiedName() ) ;
136 // final String fullName = String.valueOf( typEle ) ;
137 writer.setClassName( fullName );
139 if( !typEle.getModifiers().contains( Modifier.PUBLIC ) ||
140 !fullName.contains( OG_TAG_CLASS ) ) { continue; } // public かつ taglib に絞る
142 final DocCommentTree docTree = docUtil.getDocCommentTree(typEle); // ドキュメンテーション・コメントが見つからない場合、null が返る。
144 // final List<? extends DocTree> desc = docTree == null ? EMPTY_LIST : docTree.getFirstSentence();
145 // final List<? extends DocTree> cmnt = docTree == null ? EMPTY_LIST : docTree.getFullBody();
146 final String[] cmnts = getTitleCmnt( docTree ); // 8.0.2.1 (2021/12/10)
148 final Map<String,List<String>> blkTagMap = blockTagsMap(docTree);
149 final String smplTags = getBlockTag( OG_FOR_SMPL, blkTagMap, "" );
150 final String grpTags = getBlockTag( OG_GROUP , blkTagMap, "," );
152 // String smplTags = "";
153 // final StringBuilder grpBuf = new StringBuilder();
154 // if( docTree != null ) {
155 // for( final DocTree dt : docTree.getBlockTags() ) {
156 // final String tag = String.valueOf(dt);
157 // if( tag.contains( OG_FOR_SMPL ) ) { smplTags = cutTag( tag,OG_FOR_SMPL ); }
158 // else if( tag.contains( OG_GROUP ) ) { grpBuf.append( '【' ).append( cutTag( tag,OG_GROUP ) ).append( "】," ); }
161 // final String grpTags = grpBuf.length() == 0 ? "" : grpBuf.substring(0,grpBuf.length()-1); // 最後のカンマを削除
163 // 5.7.1.1 (2013/12/13) タグのインデントを止める。
164 writer.printTag( "<classDoc>" );
165 writer.printTag( " <tagClass>" ,fullName ,"</tagClass>" );
166 writer.printTag( " <tagGroup>【" ,grpTags ,"】</tagGroup>" ); // 8.0.2.1 (2021/12/10)
167 // writer.printTag( " <description>" ,desc ,"</description>" );
168 writer.printTag( " <description>" ,cmnts[0] ,"</description>" ); // 8.0.2.1 (2021/12/10)
169 // writer.printTag( " <contents>" ,cmnt ,"</contents>" );
170 writer.printTag( " <contents>" ,cmnts[1] ,"</contents>" ); // 8.0.2.1 (2021/12/10)
171 writer.printTag( " <formSample>" ,smplTags ,"</formSample>" );
174 String className = String.valueOf( typEle );
175 TypeElement loopEle = typEle;
176 while( loopEle != null &&
177 className.contains( OG_TAG_CLASS ) ) {
179 writer.setClassName( className );
180 final String extendFlag = String.valueOf( className.contains( "HTMLTagSupport" ) );
182 // メソッドのみフィルタリングして取得する
183 for( final ExecutableElement ele : ElementFilter.methodsIn(loopEle.getEnclosedElements())) { // メソッドだけに絞る
184 if( !ele.getModifiers().contains( Modifier.PUBLIC ) ) { continue; } // public だけに絞る
186 final DocCommentTree mdoc = docUtil.getDocCommentTree(ele); // ドキュメンテーション・コメントが見つからない場合、null が返る。
187 if( mdoc == null ) { continue; }
189 final Map<String,List<String>> blkTagMap2 = blockTagsMap(mdoc);
190 final String tags = getBlockTag( OG_TAG_NAME , blkTagMap2, "" );
193 // for( final DocTree dt : mdoc.getBlockTags() ) {
194 // final String tag = String.valueOf(dt);
195 // if( tag.contains( OG_TAG_NAME ) ) { tags = cutTag( tag,OG_TAG_NAME ); }
198 if( !tags.isEmpty() ) {
199 final String fname = String.valueOf( ele );
200 if( !mtdClsSet.add( fname ) ) { continue; } // 継承もとに同じメソッド名がある場合は、無視する。
202 final String methodName = removeSetter( String.valueOf( ele.getSimpleName() ) );
204 // final List<? extends DocTree> ftag = mdoc.getFirstSentence();
205 // final List<? extends DocTree> mcmnt = mdoc.getFullBody();
206 final String[] fcmnts = getTitleCmnt( mdoc ); // 8.0.2.1 (2021/12/10)
208 final String[] keylblCd = methodLabelCode( mdoc );
210 // final List<? extends DocTree> doc1 = mdoc.getPostamble();
211 // final List<? extends DocTree> doc2 = mdoc.getPreamble();
213 // 5.7.1.1 (2013/12/13) タグのインデントを止める。
214 writer.printTag( " <method>" );
215 writer.printTag( " <name>" ,methodName ,"</name>" );
216 writer.printTag( " <label>" ,keylblCd[1],"</label>" ); // 6.1.1.0 (2015/01/17)
217 writer.printTag( " <comment>" ,keylblCd[2],"</comment>" ); // 6.2.5.0 (2015/06/05)
218 writer.printTag( " <code>" ,keylblCd[3],"</code>" ); // 6.1.1.0 (2015/01/17)
219 writer.printTag( " <htmlExtend>" ,extendFlag ,"</htmlExtend>" );
220 // writer.printTag( " <description>",ftag ,"</description>" ); // 8.0.2.1 (2021/12/10)
221 writer.printTag( " <description>",fcmnts[0] ,"</description>" );
222 // writer.printTag( " <contents>" ,mcmnt ,"" );
223 writer.printTag( " <contents>" ,fcmnts[0] ,"" ); // 8.0.2.1 (2021/12/10)
224 writer.printTag( "" ,tags ,"</contents>" );
225 writer.printTag( " </method>");
229 final TypeMirror superType = loopEle.getSuperclass();
230 className = String.valueOf( superType );
231 loopEle = null; // while ループの終了
232 if( !TypeKind.NONE.equals( superType.getKind() ) ) {
233 for( final TypeElement tp : eleUtil.getAllTypeElements(className) ) {
234 if( className.equals( String.valueOf(tp) ) ) {
235 loopEle = tp ; break;
240 writer.printTag( "</classDoc>" );
245 * セッターメソッドの setXXXX の set を削除し、次の文字を小文字化します。
246 * つまり、セッターメソッドから属性値を推測します。
247 * (超特殊処理)セッターメソッドのset以下2文字目が大文字の場合は、
248 * 1文字目も大文字と考えて小文字化を行いません。
249 * 例えば、setSYS や setUSER など、RequestValueTag.javaに使用するケースです。
251 * @param target 処理対象となる文字列
255 private String removeSetter( final String target ) {
256 if( target != null && target.startsWith( "set" ) ) {
257 char[] chs = target.toCharArray();
258 if( chs.length > 4 && !( chs[4] >= 'A' && chs[4] <= 'Z' ) ) {
259 chs[3] = Character.toLowerCase( chs[3] ) ;
261 return new String( chs,3,chs.length-3 );
267 * MethodDocを受け取り、0:パラメータ、1:ラベル、2:コメント、3:コードを文字列配列に入れて返します。
269 * これは、タグリブのラベルリソース登録時に使用する情報です。
270 * タグリブのローカルルールとして、0:パラメータ 1:ラベル 2:ラベル以降の解説 3:コード
271 * という記述を行う事を前提にしています。
273 * 0:パラメータは、引数です。メソッド名ではありませんので、ご注意ください。
274 * 1:ラベルは、パラメータの次の空白文字から、次の空白文字、または、"[" までの文字です。
275 * 2:コメントは、ラベル以降の文字列で、コードの記述部分も含みます。
276 * 3:コード は、特別な処理を行います。"[" と "]" 内に記述された内容を取り出します。
278 * @og.rev 7.3.0.0 (2021/01/06) 新しいJavaDoc対応
280 * @param mdoc DocCommentTreeオブジェクト
282 * @return 0:パラメータ、1:ラベル、2:コメント、3:コードを文字列配列に詰めた値(長さ4の配列)
285 private String[] methodLabelCode( final DocCommentTree mdoc ) {
286 final String[] arys = new String[] { "","","","" } ; // 後で内容を更新する。
288 final Map<String,List<String>> blkTagMap = blockTagsMap(mdoc);
289 final String prmTag = getBlockTag( DOC_PARAM, blkTagMap, "" );
291 // String prmTag = "";
292 // for( final DocTree dt : mdoc.getBlockTags() ) {
293 // final String tag = String.valueOf(dt);
294 // if( tag.contains( DOC_PARAM ) ) {
295 // prmTag = cutTag( tag,DOC_PARAM ); break; // Taglibのsetter は、paramは一つだけのハズ
299 // 最大3つ と指定しているが、0:パラメータと1:ラベルの2つしか保証されていない。
300 final String[] temp = prmTag.split( "[\\s]+",3 ); // 空白文字で3つに分解する。
301 System.arraycopy( temp,0,arys,0,temp.length ); // 6.3.6.0 (2015/08/16)
303 // 3:コード があれば、2:コメントから取り出す。
304 final int st1 = arys[2].indexOf( '[' );
306 final int st2 = arys[2].indexOf( ']',st1 );
308 // 前後の [] は、取り除き、'/' があれば、' ' に置換する。(コード文字列化)
309 arys[3] = arys[2].substring( st1+1,st2 ).replace( '/' , ' ' );
317 * サポートされているすべてのオプションを返します。
319 * @return サポートされているすべてのオプションを含むセット、存在しない場合は空のセット
322 public Set<? extends Option> getSupportedOptions() {
323 final Option[] options = {
324 new AbstractOption( "-outfile", "-version" ) {
327 * 必要に応じてオプションと引数を処理します。
330 * @param arguments 引数をカプセル化したリスト
331 * @return 操作が成功した場合はtrue、そうでない場合はfalse
334 public boolean process(final String opt, final List<String> arguments) {
335 if( "-outfile".equalsIgnoreCase(opt) ) {
336 outfile = arguments.get(0);
338 else if( "-version".equalsIgnoreCase(opt) ) {
339 version = arguments.get(0);
345 return new HashSet<>(Arrays.asList(options));