You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2020/12/08 12:18:01 UTC

[isis] branch master updated: ISIS-2473: generate ascii-doc summary from java source file

This is an automated email from the ASF dual-hosted git repository.

ahuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git


The following commit(s) were added to refs/heads/master by this push:
     new 09b23fa  ISIS-2473: generate ascii-doc summary from java source file
09b23fa is described below

commit 09b23fa7d3909bdb24a954575e29d677df90b473
Author: Andi Huber <ah...@apache.org>
AuthorDate: Tue Dec 8 13:17:45 2020 +0100

    ISIS-2473: generate ascii-doc summary from java source file
---
 .../org/apache/isis/tooling/cli/doclet/Doclet.java | 135 +++++++++++++++++++++
 .../apache/isis/tooling/cli/doclet/Doclets.java    |  78 ++++++++++++
 .../isis/tooling/cli/projdoc/ProjectDocModel.java  |   1 +
 .../isis/tooling/cli/{ => test}/CliConfigTest.java |   3 +-
 .../isis/tooling/cli/test/doclet/DocletTest.java   |  59 +++++++++
 .../cli/test/doclet}/samples/ExecutionContext.java |   2 +-
 .../cli/test/doclet}/samples/SudoService.java      |   2 +-
 .../cli/test/doclet}/samples/UserMemento.java      |   2 +-
 .../cli/test/doclet}/samples/UserService.java      |  21 +++-
 .../isis/tooling/cli/{ => test}/isis-tooling.yml   |   0
 .../isis/tooling/javamodel}/CodeClasses.java       |  16 +--
 .../isis/tooling/javamodel/CompilationUnits.java   |  57 +++++++++
 .../apache/isis/tooling/javamodel/Javadocs.java    |  64 ++++++++++
 .../isis/tooling/javamodel}/MemberInfos.java       |  12 +-
 .../tooling/javamodel/MethodDeclarations.java}     |  20 ++-
 .../isis/tooling/javamodel/TypeDeclarations.java}  |  33 ++---
 .../isis/tooling/javamodel/test/AnalyzerTest.java  |  31 +++--
 .../tooling/javamodel/test/MethodProcessor.java    |  69 -----------
 .../isis/tooling/model4adoc/AsciiDocFactory.java   |   6 +-
 19 files changed, 478 insertions(+), 133 deletions(-)

diff --git a/tooling/cli/src/main/java/org/apache/isis/tooling/cli/doclet/Doclet.java b/tooling/cli/src/main/java/org/apache/isis/tooling/cli/doclet/Doclet.java
new file mode 100644
index 0000000..55656e7
--- /dev/null
+++ b/tooling/cli/src/main/java/org/apache/isis/tooling/cli/doclet/Doclet.java
@@ -0,0 +1,135 @@
+/*
+ *  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.isis.tooling.cli.doclet;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+import com.github.javaparser.StaticJavaParser;
+import com.github.javaparser.ast.body.TypeDeclaration;
+
+import org.apache.isis.commons.collections.Can;
+import org.apache.isis.tooling.javamodel.CompilationUnits;
+import org.apache.isis.tooling.javamodel.Javadocs;
+import org.apache.isis.tooling.javamodel.TypeDeclarations;
+import org.apache.isis.tooling.model4adoc.AsciiDocFactory;
+import org.apache.isis.tooling.model4adoc.AsciiDocWriter;
+
+import lombok.NonNull;
+import lombok.Value;
+import lombok.val;
+import lombok.extern.log4j.Log4j2;
+
+@Value
+@Log4j2
+public class Doclet {
+
+    private final TypeDeclaration<?> td;
+
+    public static Optional<Doclet> parse(final @NonNull File sourceFile) {
+
+        try {
+            val cu = StaticJavaParser.parse(sourceFile);
+
+            return Stream.of(cu)
+            .flatMap(CompilationUnits::streamPublicTypeDeclarations)
+            .filter(Doclets::isApacheIsisDoclet)
+            .map(Doclet::new)
+            .findFirst();
+
+        } catch (Exception e) {
+            log.error("failed to parse java source file {}", sourceFile, e);
+            return Optional.empty();
+        }
+
+    }
+
+    public String toAsciiDoc() {
+        
+        val doc = AsciiDocFactory.doc();
+        
+        val introBlock = AsciiDocFactory.block(doc);
+        val javaSourceBlock = AsciiDocFactory.block(doc);
+        val footNoteBlock = AsciiDocFactory.block(doc);
+        
+        val mds = TypeDeclarations.streamPublicMethodDeclarations(td)
+                .filter(Javadocs::presentAndNotHidden)
+                .collect(Can.toCan());
+
+        // -- intro
+        
+        td.getJavadoc().ifPresent(javadoc->{
+            introBlock.setSource(Doclets.toAsciiDoc(javadoc));    
+        });
+        
+        // -- java content
+        
+        val java = new StringBuilder();
+        
+        java.append(String.format("type %s {\n", td.getName().asString()));
+        
+        mds.forEach(md->{
+
+            java.append(String.format("\n  %s // <.>\n", Doclets.toNormalizedMethodDeclaration(md)));
+            
+        });
+
+        java.append("}\n");
+        
+        javaSourceBlock.setSource(AsciiDocFactory.SourceFactory.java(java.toString(), td.getName().asString()));
+        
+        // -- foot notes
+        
+        val footNotes = new StringBuilder();
+        
+        mds.forEach(md->{
+            
+            md.getJavadoc()
+            .ifPresent(javadoc->{
+            
+                footNotes.append(String.format("\n<.> `%s` %s\n",
+                        Doclets.toNormalizedMethodDeclaration(md),
+                        Doclets.toAsciiDoc(javadoc)));
+                
+            });
+            
+        });
+        
+        footNoteBlock.setSource(footNotes.toString());
+        
+        try {
+            doc.setTitle(td.getName().asString());
+            return AsciiDocWriter.toString(doc);
+        } catch (IOException e) {
+            e.printStackTrace();
+            return "ERROR: " + e.getMessage();
+        }
+        
+    }
+
+
+    // -- HELPER
+
+
+
+
+
+}
diff --git a/tooling/cli/src/main/java/org/apache/isis/tooling/cli/doclet/Doclets.java b/tooling/cli/src/main/java/org/apache/isis/tooling/cli/doclet/Doclets.java
new file mode 100644
index 0000000..9d7d947
--- /dev/null
+++ b/tooling/cli/src/main/java/org/apache/isis/tooling/cli/doclet/Doclets.java
@@ -0,0 +1,78 @@
+/*
+ *  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.isis.tooling.cli.doclet;
+
+import com.github.javaparser.ast.body.MethodDeclaration;
+import com.github.javaparser.ast.body.TypeDeclaration;
+import com.github.javaparser.javadoc.Javadoc;
+import com.github.javaparser.javadoc.description.JavadocInlineTag;
+import com.github.javaparser.javadoc.description.JavadocSnippet;
+
+import org.apache.isis.tooling.javamodel.Javadocs;
+
+import lombok.NonNull;
+import lombok.val;
+
+final class Doclets {
+
+    static boolean isApacheIsisDoclet(final @NonNull TypeDeclaration<?> td) {
+        return td.getJavadoc()
+        .map(javadoc->{
+        
+            val toBeIncluded = Javadocs.streamTagContent(javadoc, "since") 
+            .anyMatch(since->since.toText().contains("{@index}"));
+            
+            return toBeIncluded;
+            
+        }) 
+        .orElse(false);
+    }
+    
+    static String toNormalizedMethodDeclaration(final @NonNull MethodDeclaration md) {
+        return md.getDeclarationAsString(false, false, true).trim();
+    }
+    
+    static String toAsciiDoc(final @NonNull Javadoc javadoc) {
+        
+        val adoc = new StringBuilder();
+        
+        javadoc.getDescription().getElements()
+        .forEach(e->{
+            
+            if(e instanceof JavadocSnippet) {
+                adoc.append(normalizeHtmlTags(e.toText()));
+            } else if(e instanceof JavadocInlineTag) {
+                adoc.append(" _").append(((JavadocInlineTag) e).getContent().trim()).append("_ ");
+            } else {
+                adoc.append(e.toText());
+            }
+            
+        });
+        
+        return adoc.toString();
+    }
+    
+    // -- HELPER 
+    
+    private static String normalizeHtmlTags(final @NonNull String s) {
+        return s.replace("<p>", "\n").replace("</p>", "");
+    }
+    
+    
+}
diff --git a/tooling/cli/src/main/java/org/apache/isis/tooling/cli/projdoc/ProjectDocModel.java b/tooling/cli/src/main/java/org/apache/isis/tooling/cli/projdoc/ProjectDocModel.java
index c2d8d05..73dcb5d 100644
--- a/tooling/cli/src/main/java/org/apache/isis/tooling/cli/projdoc/ProjectDocModel.java
+++ b/tooling/cli/src/main/java/org/apache/isis/tooling/cli/projdoc/ProjectDocModel.java
@@ -44,6 +44,7 @@ import org.apache.isis.commons.internal.graph._Graph;
 import org.apache.isis.tooling.c4.C4;
 import org.apache.isis.tooling.cli.CliConfig.ProjectDoc;
 import org.apache.isis.tooling.javamodel.AnalyzerConfigFactory;
+import org.apache.isis.tooling.javamodel.CodeClasses;
 import org.apache.isis.tooling.model4adoc.AsciiDocFactory;
 import org.apache.isis.tooling.model4adoc.AsciiDocWriter;
 import org.apache.isis.tooling.projectmodel.ArtifactCoordinates;
diff --git a/tooling/cli/src/test/java/org/apache/isis/tooling/cli/CliConfigTest.java b/tooling/cli/src/test/java/org/apache/isis/tooling/cli/test/CliConfigTest.java
similarity index 95%
rename from tooling/cli/src/test/java/org/apache/isis/tooling/cli/CliConfigTest.java
rename to tooling/cli/src/test/java/org/apache/isis/tooling/cli/test/CliConfigTest.java
index a1f688d..67e1944 100644
--- a/tooling/cli/src/test/java/org/apache/isis/tooling/cli/CliConfigTest.java
+++ b/tooling/cli/src/test/java/org/apache/isis/tooling/cli/test/CliConfigTest.java
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.tooling.cli;
+package org.apache.isis.tooling.cli.test;
 
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
@@ -27,6 +27,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import org.apache.isis.commons.internal.resources._Yaml;
+import org.apache.isis.tooling.cli.CliConfig;
 
 import lombok.val;
 
diff --git a/tooling/cli/src/test/java/org/apache/isis/tooling/cli/test/doclet/DocletTest.java b/tooling/cli/src/test/java/org/apache/isis/tooling/cli/test/doclet/DocletTest.java
new file mode 100644
index 0000000..32077a3
--- /dev/null
+++ b/tooling/cli/src/test/java/org/apache/isis/tooling/cli/test/doclet/DocletTest.java
@@ -0,0 +1,59 @@
+/*
+ *  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.isis.tooling.cli.test.doclet;
+
+import java.io.File;
+import java.util.Optional;
+
+import org.junit.jupiter.api.Test;
+
+import org.apache.isis.tooling.cli.doclet.Doclet;
+import org.apache.isis.tooling.javamodel.AnalyzerConfigFactory;
+
+import lombok.val;
+
+import guru.nidi.codeassert.config.Language;
+
+import static guru.nidi.codeassert.config.Language.JAVA;
+
+class DocletTest {
+
+    @Test
+    void testJavaDocMining() {
+
+        val projDir = new File("./").getAbsoluteFile();
+        val analyzerConfig = AnalyzerConfigFactory.mavenTest(projDir, Language.JAVA).main();
+
+        analyzerConfig.getSources(JAVA)
+        .stream()
+        .filter(source->source.toString().contains("UserService"))
+        .peek(source->System.out.println("parsing source: " + source))
+        .map(Doclet::parse)
+        .filter(Optional::isPresent)
+        .map(Optional::get)
+        .forEach(doclet->{
+            
+            System.out.println("--------------------------------------------------");
+            System.out.println(doclet.toAsciiDoc());
+            System.out.println("--------------------------------------------------");
+
+        });
+    }
+    
+}
diff --git a/tooling/javamodel/src/test/java/org/apache/isis/tooling/javamodel/test/samples/ExecutionContext.java b/tooling/cli/src/test/java/org/apache/isis/tooling/cli/test/doclet/samples/ExecutionContext.java
similarity index 93%
rename from tooling/javamodel/src/test/java/org/apache/isis/tooling/javamodel/test/samples/ExecutionContext.java
rename to tooling/cli/src/test/java/org/apache/isis/tooling/cli/test/doclet/samples/ExecutionContext.java
index bb4d5f7..92dee61 100644
--- a/tooling/javamodel/src/test/java/org/apache/isis/tooling/javamodel/test/samples/ExecutionContext.java
+++ b/tooling/cli/src/test/java/org/apache/isis/tooling/cli/test/doclet/samples/ExecutionContext.java
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.tooling.javamodel.test.samples;
+package org.apache.isis.tooling.cli.test.doclet.samples;
 
 public class ExecutionContext {
 
diff --git a/tooling/javamodel/src/test/java/org/apache/isis/tooling/javamodel/test/samples/SudoService.java b/tooling/cli/src/test/java/org/apache/isis/tooling/cli/test/doclet/samples/SudoService.java
similarity index 93%
rename from tooling/javamodel/src/test/java/org/apache/isis/tooling/javamodel/test/samples/SudoService.java
rename to tooling/cli/src/test/java/org/apache/isis/tooling/cli/test/doclet/samples/SudoService.java
index 14a3bc1..87f241c 100644
--- a/tooling/javamodel/src/test/java/org/apache/isis/tooling/javamodel/test/samples/SudoService.java
+++ b/tooling/cli/src/test/java/org/apache/isis/tooling/cli/test/doclet/samples/SudoService.java
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.tooling.javamodel.test.samples;
+package org.apache.isis.tooling.cli.test.doclet.samples;
 
 public interface SudoService {
 
diff --git a/tooling/javamodel/src/test/java/org/apache/isis/tooling/javamodel/test/samples/UserMemento.java b/tooling/cli/src/test/java/org/apache/isis/tooling/cli/test/doclet/samples/UserMemento.java
similarity index 94%
copy from tooling/javamodel/src/test/java/org/apache/isis/tooling/javamodel/test/samples/UserMemento.java
copy to tooling/cli/src/test/java/org/apache/isis/tooling/cli/test/doclet/samples/UserMemento.java
index 1a4ab8a..b208843 100644
--- a/tooling/javamodel/src/test/java/org/apache/isis/tooling/javamodel/test/samples/UserMemento.java
+++ b/tooling/cli/src/test/java/org/apache/isis/tooling/cli/test/doclet/samples/UserMemento.java
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.tooling.javamodel.test.samples;
+package org.apache.isis.tooling.cli.test.doclet.samples;
 
 import lombok.Value;
 
diff --git a/tooling/javamodel/src/test/java/org/apache/isis/tooling/javamodel/test/samples/UserService.java b/tooling/cli/src/test/java/org/apache/isis/tooling/cli/test/doclet/samples/UserService.java
similarity index 83%
rename from tooling/javamodel/src/test/java/org/apache/isis/tooling/javamodel/test/samples/UserService.java
rename to tooling/cli/src/test/java/org/apache/isis/tooling/cli/test/doclet/samples/UserService.java
index 0fdb0f5..89cff30 100644
--- a/tooling/javamodel/src/test/java/org/apache/isis/tooling/javamodel/test/samples/UserService.java
+++ b/tooling/cli/src/test/java/org/apache/isis/tooling/cli/test/doclet/samples/UserService.java
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.tooling.javamodel.test.samples;
+package org.apache.isis.tooling.cli.test.doclet.samples;
 
 import java.util.Optional;
 
@@ -24,6 +24,8 @@ import javax.annotation.Nullable;
 
 import org.apache.isis.commons.internal.exceptions._Exceptions;
 
+import lombok.NonNull;
+
 /**
  * The {@link UserService} allows the domain object to obtain the identity of the user 
  * interacting with said object.
@@ -31,7 +33,7 @@ import org.apache.isis.commons.internal.exceptions._Exceptions;
  * If {@link SudoService} has been used to temporarily override the user and/or roles, 
  * then this service will report the overridden values instead.
  *
- * @since 2.0 (+doc)
+ * @since 2.0 {@index}
  */
 public interface UserService {
 
@@ -40,14 +42,19 @@ public interface UserService {
     /**
      * Optionally gets the details about the current user, 
      * based on whether an {@link ExecutionContext} can be found with the current thread's context.
-     * @since 2.0 (+doc)
      */
     Optional<UserMemento> currentUser();
 
     /**
+     * Testimonial with arguments.
+     * @param arg1 - first argument (non-null)
+     * @param arg2 - second argument (non-null)
+     */
+    Optional<UserMemento> currentUser(@NonNull String arg1, @NonNull String arg2);
+    
+    /**
      * Gets the details about the current user.
      * @apiNote for backward compatibility
-     * @since 2.0 (+doc)
      */
     @Nullable
     default UserMemento getUser() {
@@ -66,7 +73,7 @@ public interface UserService {
     }
 
     /**
-     * Optionally gets the the current user's name, 
+     * Optionally gets the current user's name, 
      * based on whether an {@link ExecutionContext} can be found with the current thread's context.
      */
     default Optional<String> currentUserName() {
@@ -74,6 +81,10 @@ public interface UserService {
                 .map(UserMemento::getName);
     }
 
+    /**
+     * Gets the current user's name if available, otherwise returns {@literal Nobody}.
+     * @hidden
+     */
     default String currentUserNameElseNobody() {
         return currentUserName()
                 .orElse("Nobody");
diff --git a/tooling/cli/src/test/resources/org/apache/isis/tooling/cli/isis-tooling.yml b/tooling/cli/src/test/resources/org/apache/isis/tooling/cli/test/isis-tooling.yml
similarity index 100%
rename from tooling/cli/src/test/resources/org/apache/isis/tooling/cli/isis-tooling.yml
rename to tooling/cli/src/test/resources/org/apache/isis/tooling/cli/test/isis-tooling.yml
diff --git a/tooling/cli/src/main/java/org/apache/isis/tooling/cli/projdoc/CodeClasses.java b/tooling/javamodel/src/main/java/org/apache/isis/tooling/javamodel/CodeClasses.java
similarity index 78%
rename from tooling/cli/src/main/java/org/apache/isis/tooling/cli/projdoc/CodeClasses.java
rename to tooling/javamodel/src/main/java/org/apache/isis/tooling/javamodel/CodeClasses.java
index 513f0bb..cbc0429 100644
--- a/tooling/cli/src/main/java/org/apache/isis/tooling/cli/projdoc/CodeClasses.java
+++ b/tooling/javamodel/src/main/java/org/apache/isis/tooling/javamodel/CodeClasses.java
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.tooling.cli.projdoc;
+package org.apache.isis.tooling.javamodel;
 
 import java.util.function.Predicate;
 
@@ -28,11 +28,11 @@ import lombok.extern.log4j.Log4j2;
 import guru.nidi.codeassert.model.CodeClass;
 
 @Log4j2
-final class CodeClasses {
+public final class CodeClasses {
 
     // -- PREDICATES
     
-    static boolean isSpringStereoType(final @NonNull CodeClass codeClass) {
+    public static boolean isSpringStereoType(final @NonNull CodeClass codeClass) {
         return codeClass
         .getAnnotations()
         .stream()
@@ -40,27 +40,27 @@ final class CodeClasses {
         .anyMatch(name->name.startsWith("org.springframework.stereotype."));
     }
     
-    static Predicate<CodeClass> packageNameStartsWith(final @NonNull String packagePrefix) {
+    public static Predicate<CodeClass> packageNameStartsWith(final @NonNull String packagePrefix) {
         return codeClass->codeClass.getName().startsWith(packagePrefix);
     }
     
-    static Predicate<CodeClass> isApacheIsisPackage() {
+    public static Predicate<CodeClass> isApacheIsisPackage() {
         return packageNameStartsWith("org.apache.isis.");
     }
     
-    static boolean hasSourceFile(final @NonNull CodeClass codeClass) {
+    public static boolean hasSourceFile(final @NonNull CodeClass codeClass) {
         return _Strings.isNotEmpty(codeClass.getSourceFile())
                 && !"Unknown".equals(codeClass.getSourceFile());
     }
     
-    static boolean hasNoSourceFile(final @NonNull CodeClass codeClass) {
+    public static boolean hasNoSourceFile(final @NonNull CodeClass codeClass) {
         return !hasSourceFile(codeClass);
     }
     
     
     // -- LOGGER
     
-    static void log(final @NonNull CodeClass codeClass) {
+    public static void log(final @NonNull CodeClass codeClass) {
         log.info("codeClass: {}\n"
                 + "  methods:{}\n"
                 + "  source-file: {}", 
diff --git a/tooling/javamodel/src/main/java/org/apache/isis/tooling/javamodel/CompilationUnits.java b/tooling/javamodel/src/main/java/org/apache/isis/tooling/javamodel/CompilationUnits.java
new file mode 100644
index 0000000..9e1ad66
--- /dev/null
+++ b/tooling/javamodel/src/main/java/org/apache/isis/tooling/javamodel/CompilationUnits.java
@@ -0,0 +1,57 @@
+/*
+ *  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.isis.tooling.javamodel;
+
+import java.io.File;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+
+import com.github.javaparser.StaticJavaParser;
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.body.TypeDeclaration;
+
+import lombok.NonNull;
+import lombok.SneakyThrows;
+import lombok.val;
+
+public final class CompilationUnits {
+    
+    @SneakyThrows
+    public static CompilationUnit parse(final @NonNull File sourceFile) {
+        return StaticJavaParser.parse(sourceFile);
+    }
+
+    public static Predicate<CompilationUnit> isPublic() {
+        return cu->cu.getPrimaryType()
+        .map(primaryType->primaryType.isPublic())
+        .orElse(false);
+    }
+    
+    public static <T> Stream<TypeDeclaration<?>> streamPublicTypeDeclarations(
+            final @NonNull CompilationUnit compilationUnit) {
+        
+        val type = compilationUnit.getPrimaryType().orElse(null);
+        if(type==null) {
+            return Stream.empty();
+        }
+        return Stream.of(type);
+    }
+
+    
+}
diff --git a/tooling/javamodel/src/main/java/org/apache/isis/tooling/javamodel/Javadocs.java b/tooling/javamodel/src/main/java/org/apache/isis/tooling/javamodel/Javadocs.java
new file mode 100644
index 0000000..c591d09
--- /dev/null
+++ b/tooling/javamodel/src/main/java/org/apache/isis/tooling/javamodel/Javadocs.java
@@ -0,0 +1,64 @@
+/*
+ *  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.isis.tooling.javamodel;
+
+import java.util.stream.Stream;
+
+import com.github.javaparser.ast.body.MethodDeclaration;
+import com.github.javaparser.javadoc.Javadoc;
+import com.github.javaparser.javadoc.JavadocBlockTag;
+import com.github.javaparser.javadoc.description.JavadocDescription;
+
+import lombok.NonNull;
+
+public final class Javadocs {
+
+    public static Stream<JavadocBlockTag> streamTagsByName(
+            final @NonNull Javadoc javadoc,
+            final @NonNull String tagName) {
+        
+        return javadoc.getBlockTags().stream()
+        .filter(tag->tag.getTagName().equals(tagName));
+    }
+    
+    public static Stream<JavadocDescription> streamTagContent(
+            final @NonNull Javadoc javadoc,
+            final @NonNull String tagName) {
+        
+        return streamTagsByName(javadoc, tagName)
+        .map(tag->tag.getContent());
+    }
+    
+    public static boolean presentAndNotHidden(
+            final @NonNull MethodDeclaration md) {
+        
+        return md.getJavadoc()
+        .map(jd->!hasHidden(jd))
+        .orElse(false);
+    }
+    
+    public static boolean hasHidden(
+            final @NonNull Javadoc javadoc) {
+        
+        return streamTagsByName(javadoc, "hidden") 
+        .findAny()
+        .isPresent();
+    }
+    
+}
diff --git a/tooling/cli/src/main/java/org/apache/isis/tooling/cli/projdoc/MemberInfos.java b/tooling/javamodel/src/main/java/org/apache/isis/tooling/javamodel/MemberInfos.java
similarity index 84%
copy from tooling/cli/src/main/java/org/apache/isis/tooling/cli/projdoc/MemberInfos.java
copy to tooling/javamodel/src/main/java/org/apache/isis/tooling/javamodel/MemberInfos.java
index fa9e8cf..db123bf 100644
--- a/tooling/cli/src/main/java/org/apache/isis/tooling/cli/projdoc/MemberInfos.java
+++ b/tooling/javamodel/src/main/java/org/apache/isis/tooling/javamodel/MemberInfos.java
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.tooling.cli.projdoc;
+package org.apache.isis.tooling.javamodel;
 
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
@@ -25,23 +25,23 @@ import lombok.NonNull;
 
 import guru.nidi.codeassert.model.MemberInfo;
 
-final class MemberInfos {
+public final class MemberInfos {
 
     // -- PREDICATES
     
-    static boolean isPublic(final @NonNull MemberInfo memberInfo) {
+    public static boolean isPublic(final @NonNull MemberInfo memberInfo) {
         return (memberInfo.getAccessFlags() & 1) == 1;
     }
     
-    // -- HELPER
-    
-    static String membersToMultilineString(final Stream<MemberInfo> memberInfoStream, final String delimiter) {
+    public static String membersToMultilineString(final Stream<MemberInfo> memberInfoStream, final String delimiter) {
         return memberInfoStream
                 .filter(MemberInfos::isPublic)
                 .map(mInfo->delimiter + memberToString(mInfo))
                 .collect(Collectors.joining());
     }
     
+    // -- HELPER
+    
     private static String memberToString(final MemberInfo memberInfo) {
         return String.format("%s(...)", memberInfo.getName());
     }
diff --git a/tooling/javamodel/src/test/java/org/apache/isis/tooling/javamodel/test/samples/UserMemento.java b/tooling/javamodel/src/main/java/org/apache/isis/tooling/javamodel/MethodDeclarations.java
similarity index 61%
rename from tooling/javamodel/src/test/java/org/apache/isis/tooling/javamodel/test/samples/UserMemento.java
rename to tooling/javamodel/src/main/java/org/apache/isis/tooling/javamodel/MethodDeclarations.java
index 1a4ab8a..afcdf70 100644
--- a/tooling/javamodel/src/test/java/org/apache/isis/tooling/javamodel/test/samples/UserMemento.java
+++ b/tooling/javamodel/src/main/java/org/apache/isis/tooling/javamodel/MethodDeclarations.java
@@ -16,12 +16,22 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.tooling.javamodel.test.samples;
+package org.apache.isis.tooling.javamodel;
 
-import lombok.Value;
+import com.github.javaparser.ast.body.MethodDeclaration;
 
-@Value
-public class UserMemento {
+import lombok.NonNull;
+
+public final class MethodDeclarations {
+
+    public static boolean isEffectivePublic(
+            final @NonNull MethodDeclaration md) {
+        //TODO effective public requires more context, eg. is the container an interface 
+        return !md.isPrivate() 
+                && !md.isAbstract() 
+                && !md.isProtected()
+                //&& !md.isDefault()
+                ;
+    }
     
-    private final String name; 
 }
diff --git a/tooling/cli/src/main/java/org/apache/isis/tooling/cli/projdoc/MemberInfos.java b/tooling/javamodel/src/main/java/org/apache/isis/tooling/javamodel/TypeDeclarations.java
similarity index 54%
rename from tooling/cli/src/main/java/org/apache/isis/tooling/cli/projdoc/MemberInfos.java
rename to tooling/javamodel/src/main/java/org/apache/isis/tooling/javamodel/TypeDeclarations.java
index fa9e8cf..5781a49 100644
--- a/tooling/cli/src/main/java/org/apache/isis/tooling/cli/projdoc/MemberInfos.java
+++ b/tooling/javamodel/src/main/java/org/apache/isis/tooling/javamodel/TypeDeclarations.java
@@ -16,35 +16,28 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.tooling.cli.projdoc;
+package org.apache.isis.tooling.javamodel;
 
-import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
-import lombok.NonNull;
+import com.github.javaparser.ast.body.MethodDeclaration;
+import com.github.javaparser.ast.body.TypeDeclaration;
 
-import guru.nidi.codeassert.model.MemberInfo;
+import lombok.NonNull;
 
-final class MemberInfos {
+public final class TypeDeclarations {
 
-    // -- PREDICATES
-    
-    static boolean isPublic(final @NonNull MemberInfo memberInfo) {
-        return (memberInfo.getAccessFlags() & 1) == 1;
+    public static <T> Stream<MethodDeclaration> streamMethodDeclarations(
+            final @NonNull TypeDeclaration<?> typeDeclaration) {
+        return typeDeclaration.getMethods().stream();
     }
     
-    // -- HELPER
-    
-    static String membersToMultilineString(final Stream<MemberInfo> memberInfoStream, final String delimiter) {
-        return memberInfoStream
-                .filter(MemberInfos::isPublic)
-                .map(mInfo->delimiter + memberToString(mInfo))
-                .collect(Collectors.joining());
-    }
-    
-    private static String memberToString(final MemberInfo memberInfo) {
-        return String.format("%s(...)", memberInfo.getName());
+    public static <T> Stream<MethodDeclaration> streamPublicMethodDeclarations(
+            final @NonNull TypeDeclaration<?> typeDeclaration) {
+        return streamMethodDeclarations(typeDeclaration)
+                .filter(MethodDeclarations::isEffectivePublic);
     }
     
+
     
 }
diff --git a/tooling/javamodel/src/test/java/org/apache/isis/tooling/javamodel/test/AnalyzerTest.java b/tooling/javamodel/src/test/java/org/apache/isis/tooling/javamodel/test/AnalyzerTest.java
index cb90577..fd4e159 100644
--- a/tooling/javamodel/src/test/java/org/apache/isis/tooling/javamodel/test/AnalyzerTest.java
+++ b/tooling/javamodel/src/test/java/org/apache/isis/tooling/javamodel/test/AnalyzerTest.java
@@ -26,6 +26,8 @@ import org.junit.jupiter.api.Test;
 
 import org.apache.isis.commons.internal.base._Files;
 import org.apache.isis.tooling.javamodel.AnalyzerConfigFactory;
+import org.apache.isis.tooling.javamodel.CompilationUnits;
+import org.apache.isis.tooling.javamodel.TypeDeclarations;
 
 import lombok.val;
 
@@ -62,22 +64,25 @@ class AnalyzerTest {
         .stream()
         .filter(source->source.toString().contains("UserService"))
         .peek(source->System.out.println("parsing source: " + source))
-        .forEach(source->{
+        .map(CompilationUnits::parse)
+        .flatMap(CompilationUnits::streamPublicTypeDeclarations)
+        .peek(td->{
             
-            MethodProcessor.visitMethodsOf(source, md->{
-                
-                md.getJavadocComment().ifPresent(javadocComment->{
-                    val javadoc = javadocComment.parse();
-                
-                    javadoc.getBlockTags().stream()
-                    .filter(tag->tag.getTagName().equals("since"))
-                    .forEach(tag->System.out.println("--- SINCE " + tag.getContent().toText()));
-                    
-                }); 
+            td.getJavadocComment().ifPresent(javadocComment->{
+                val javadoc = javadocComment.parse();
+            
+                javadoc.getBlockTags().stream()
+                .filter(tag->tag.getTagName().equals("since"))
+                .forEach(tag->System.out.println("--- SINCE " + tag.getContent().toText()));
                 
-                System.out.println("javadoc: " + md.getJavadocComment());
-                System.out.println("non private method: " + md.getDeclarationAsString());
             });
+            
+        })
+        .flatMap(TypeDeclarations::streamMethodDeclarations)
+        .forEach(md->{
+            
+            System.out.println("javadoc: " + md.getJavadocComment());
+            System.out.println("non private method: " + md.getDeclarationAsString());
 
         });
     }
diff --git a/tooling/javamodel/src/test/java/org/apache/isis/tooling/javamodel/test/MethodProcessor.java b/tooling/javamodel/src/test/java/org/apache/isis/tooling/javamodel/test/MethodProcessor.java
deleted file mode 100644
index d4845e0..0000000
--- a/tooling/javamodel/src/test/java/org/apache/isis/tooling/javamodel/test/MethodProcessor.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- *  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.isis.tooling.javamodel.test;
-
-import java.io.File;
-import java.util.function.Consumer;
-
-import com.github.javaparser.StaticJavaParser;
-import com.github.javaparser.ast.body.MethodDeclaration;
-import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
-
-import lombok.NonNull;
-import lombok.SneakyThrows;
-import lombok.val;
-
-public class MethodProcessor {
-
-    @SneakyThrows
-    public static void visitMethodsOf(
-            final @NonNull File source,
-            final @NonNull Consumer<MethodDeclaration> callback) {
-
-        val cu = StaticJavaParser.parse(source);
-        
-        cu.getPrimaryType()
-        .ifPresent(primaryType->{
-         
-            if(!primaryType.isPublic()) {
-                return;
-            }
-            
-            val methodVisitor = new MethodVisitor();
-            methodVisitor.visit(cu, callback);    
-            
-        });
-        
-    }
-    
-    // -- HELPER
-    
-    private static class MethodVisitor extends VoidVisitorAdapter<Consumer<MethodDeclaration>> {
-
-        @Override
-        public void visit(MethodDeclaration md, Consumer<MethodDeclaration> callback) {
-            super.visit(md, null);
-            if(md.isPrivate()) {
-                return;
-            }
-            callback.accept(md);
-        }
-    }
-
-}
diff --git a/tooling/model4adoc/src/main/java/org/apache/isis/tooling/model4adoc/AsciiDocFactory.java b/tooling/model4adoc/src/main/java/org/apache/isis/tooling/model4adoc/AsciiDocFactory.java
index 05fe99a..f218a63 100644
--- a/tooling/model4adoc/src/main/java/org/apache/isis/tooling/model4adoc/AsciiDocFactory.java
+++ b/tooling/model4adoc/src/main/java/org/apache/isis/tooling/model4adoc/AsciiDocFactory.java
@@ -135,15 +135,15 @@ public class AsciiDocFactory {
 
         public static String wrap(@NonNull String sourceType, @NonNull String source, @Nullable String title, Can<String> options) {
             val sb = new StringBuilder();
-            sb.append("[").append(sourceType);
-            options.stream().map(String::trim).filter(_Strings::isNotEmpty).map(s->","+s).forEach(sb::append);
-            sb.append("]\n").append("----\n");
             if(_Strings.isNotEmpty(title)) {
                 val trimmedTitle = title.trim();
                 if(!trimmedTitle.isEmpty()) {
                     sb.append(".").append(trimmedTitle).append("\n");
                 }
             }
+            sb.append("[").append(sourceType);
+            options.stream().map(String::trim).filter(_Strings::isNotEmpty).map(s->","+s).forEach(sb::append);
+            sb.append("]\n").append("----\n");
             _Text.normalize(_Text.getLines(source))
             .forEach(line->sb.append(line).append("\n"));
             sb.append("----\n");