You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2021/02/07 13:57:49 UTC

[isis] 01/02: ISIS-2526: reorganises UnitFormatter hierarchy

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

danhaywood pushed a commit to branch ISIS-2444
in repository https://gitbox.apache.org/repos/asf/isis.git

commit 3f3996429805b4e21406db5bac4e9789177707ca
Author: danhaywood <da...@haywood-associates.co.uk>
AuthorDate: Sun Feb 7 11:59:42 2021 +0000

    ISIS-2526: reorganises UnitFormatter hierarchy
---
 .../org/apache/isis/tooling/cli/CliConfig.java     |  20 ++
 .../isis/tooling/cli/projdoc/ProjectDocModel.java  |   4 +-
 .../apache/isis/tooling/j2adoc/J2AdocContext.java  |   5 +-
 .../j2adoc/convert/J2AdocConverterAbstract.java    |  17 +-
 ...erWithSourceAndFootNotes.java => Snippets.java} |  88 +++----
 .../j2adoc/format/UnitFormatterAbstract.java       | 265 ++++++++-------------
 .../j2adoc/format/UnitFormatterCompact.java        |  48 +++-
 .../format/UnitFormatterWithSourceAndCallouts.java | 115 +++++++++
 .../format/UnitFormatterWithSourceAndSections.java |  98 ++++++++
 .../isis/tooling/model4adoc/AsciiDocFactory.java   |   4 +-
 .../tooling/model4adoc/test/ast/FootnoteTest.java  |  24 +-
 11 files changed, 424 insertions(+), 264 deletions(-)

diff --git a/tooling/cli/src/main/java/org/apache/isis/tooling/cli/CliConfig.java b/tooling/cli/src/main/java/org/apache/isis/tooling/cli/CliConfig.java
index e177721..690541e 100644
--- a/tooling/cli/src/main/java/org/apache/isis/tooling/cli/CliConfig.java
+++ b/tooling/cli/src/main/java/org/apache/isis/tooling/cli/CliConfig.java
@@ -25,8 +25,13 @@ import java.util.Optional;
 import org.yaml.snakeyaml.constructor.ConstructorException;
 
 import org.apache.isis.commons.internal.resources._Yaml;
+import org.apache.isis.tooling.j2adoc.format.UnitFormatter;
+import org.apache.isis.tooling.j2adoc.format.UnitFormatterCompact;
+import org.apache.isis.tooling.j2adoc.format.UnitFormatterWithSourceAndCallouts;
+import org.apache.isis.tooling.j2adoc.format.UnitFormatterWithSourceAndSections;
 
 import lombok.Data;
+import lombok.Getter;
 import lombok.NonNull;
 
 @Data
@@ -94,6 +99,21 @@ public class CliConfig {
             private boolean skipTitleHeader = false;
             private boolean memberSections = false;
 
+            public enum Formatter {
+                COMPACT(UnitFormatterCompact.class),
+                JAVA_SOURCES_WITH_CALLOUTS(UnitFormatterWithSourceAndCallouts.class),
+                JAVA_SOURCES_WITH_SECTIONS(UnitFormatterWithSourceAndSections.class),
+                ;
+
+                @Getter
+                private final Class<? extends UnitFormatter> unitFormatterClass;
+                Formatter(Class<? extends UnitFormatter> unitFormatterClass) {
+                    this.unitFormatterClass = unitFormatterClass;
+                }
+            }
+
+            private Formatter formatter = Formatter.JAVA_SOURCES_WITH_SECTIONS;
+
             public File getDocumentIndexFolder(File outputRootFolder) {
                 return Optional.ofNullable(outputRootFolder)
                         .map(root->new File(root, getDocumentGlobalIndexPath()))
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 2176ae6..d79e3f1 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
@@ -47,7 +47,7 @@ import org.apache.isis.tooling.c4.C4;
 import org.apache.isis.tooling.cli.CliConfig;
 import org.apache.isis.tooling.cli.adocfix.OrphanedIncludeStatementFixer;
 import org.apache.isis.tooling.j2adoc.J2AdocContext;
-import org.apache.isis.tooling.j2adoc.format.UnitFormatterWithSourceAndFootNotes;
+import org.apache.isis.tooling.j2adoc.format.UnitFormatterWithSourceAndCallouts;
 import org.apache.isis.tooling.javamodel.AnalyzerConfigFactory;
 import org.apache.isis.tooling.javamodel.ast.CodeClasses;
 import org.apache.isis.tooling.model4adoc.AsciiDocFactory;
@@ -106,7 +106,7 @@ public class ProjectDocModel {
         val j2aContext = J2AdocContext.builder()
                 //.compactFormat()
 //                .javaSourceWithFootnotesFormat()
-                .formatterFactory(UnitFormatterWithSourceAndFootNotes::new)
+                .formatterFactory(UnitFormatterWithSourceAndCallouts::new)
                 .licenseHeader(cliConfig.getGlobal().getLicenseHeader())
                 .xrefPageIdFormat(cliConfig.getCommands().getIndex().getDocumentGlobalIndexXrefPageIdFormat())
                 .namespacePartsSkipCount(cliConfig.getGlobal().getNamespacePartsSkipCount())
diff --git a/tooling/java2adoc/src/main/java/org/apache/isis/tooling/j2adoc/J2AdocContext.java b/tooling/java2adoc/src/main/java/org/apache/isis/tooling/j2adoc/J2AdocContext.java
index 2414d36..e777533 100644
--- a/tooling/java2adoc/src/main/java/org/apache/isis/tooling/j2adoc/J2AdocContext.java
+++ b/tooling/java2adoc/src/main/java/org/apache/isis/tooling/j2adoc/J2AdocContext.java
@@ -35,10 +35,7 @@ import org.apache.isis.commons.internal.collections._Multimaps;
 import org.apache.isis.commons.internal.collections._Multimaps.ListMultimap;
 import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.tooling.j2adoc.J2AdocUnit.LookupKey;
-import org.apache.isis.tooling.j2adoc.convert.J2AdocConverter;
 import org.apache.isis.tooling.j2adoc.format.UnitFormatter;
-import org.apache.isis.tooling.j2adoc.format.UnitFormatterCompact;
-import org.apache.isis.tooling.j2adoc.format.UnitFormatterWithSourceAndFootNotes;
 import org.apache.isis.tooling.javamodel.ast.ImportDeclarations;
 
 import lombok.Builder;
@@ -253,7 +250,7 @@ public class J2AdocContext {
 //    public static J2AdocContextBuilder javaSourceWithFootnotesFormat() {
 //        return J2AdocContext.builder()
 //                .converterFactory(J2AdocConverter::createDefault)
-//                .formatterFactory(UnitFormatterWithSourceAndFootNotes::new)
+//                .formatterFactory(UnitFormatterWithSourceAndCallouts::new)
 //                ;
 //    }
 //
diff --git a/tooling/java2adoc/src/main/java/org/apache/isis/tooling/j2adoc/convert/J2AdocConverterAbstract.java b/tooling/java2adoc/src/main/java/org/apache/isis/tooling/j2adoc/convert/J2AdocConverterAbstract.java
index ba51965..fe7d55e 100644
--- a/tooling/java2adoc/src/main/java/org/apache/isis/tooling/j2adoc/convert/J2AdocConverterAbstract.java
+++ b/tooling/java2adoc/src/main/java/org/apache/isis/tooling/j2adoc/convert/J2AdocConverterAbstract.java
@@ -23,17 +23,11 @@ import java.util.stream.Stream;
 
 import javax.annotation.Nullable;
 
-import com.github.javaparser.ast.body.AnnotationMemberDeclaration;
-import com.github.javaparser.ast.body.ConstructorDeclaration;
-import com.github.javaparser.ast.body.EnumConstantDeclaration;
-import com.github.javaparser.ast.body.FieldDeclaration;
-import com.github.javaparser.ast.body.MethodDeclaration;
 import com.github.javaparser.ast.body.Parameter;
 import com.github.javaparser.ast.expr.SimpleName;
 import com.github.javaparser.ast.type.ClassOrInterfaceType;
 import com.github.javaparser.ast.type.Type;
 import com.github.javaparser.ast.type.TypeParameter;
-import com.github.javaparser.javadoc.Javadoc;
 import com.github.javaparser.javadoc.description.JavadocDescription;
 import com.github.javaparser.javadoc.description.JavadocInlineTag;
 import com.github.javaparser.javadoc.description.JavadocSnippet;
@@ -42,16 +36,8 @@ import org.asciidoctor.ast.Document;
 import org.jsoup.Jsoup;
 
 import org.apache.isis.commons.collections.Can;
-import org.apache.isis.commons.internal._Constants;
 import org.apache.isis.tooling.j2adoc.J2AdocContext;
 import org.apache.isis.tooling.j2adoc.J2AdocUnit;
-import org.apache.isis.tooling.javamodel.ast.AnnotationMemberDeclarations;
-import org.apache.isis.tooling.javamodel.ast.ConstructorDeclarations;
-import org.apache.isis.tooling.javamodel.ast.EnumConstantDeclarations;
-import org.apache.isis.tooling.javamodel.ast.FieldDeclarations;
-import org.apache.isis.tooling.javamodel.ast.Javadocs;
-import org.apache.isis.tooling.javamodel.ast.MethodDeclarations;
-import org.apache.isis.tooling.model4adoc.AsciiDocFactory;
 
 import lombok.NonNull;
 import lombok.val;
@@ -64,7 +50,6 @@ public abstract class J2AdocConverterAbstract implements J2AdocConverter {
         this.j2aContext = j2aContext;
     }
 
-
     protected String parameters(
             final @NonNull Stream<Parameter> parameterStream,
             final @NonNull J2AdocUnit unit) {
@@ -152,7 +137,7 @@ public abstract class J2AdocConverterAbstract implements J2AdocConverter {
                 .orElse(typeSimpleName);
     }
 
-    private String javadocSnippet(final @NonNull JavadocSnippet snippet) {
+    private static String javadocSnippet(final @NonNull JavadocSnippet snippet) {
         return snippet.toText();
     }
 
diff --git a/tooling/java2adoc/src/main/java/org/apache/isis/tooling/j2adoc/format/UnitFormatterWithSourceAndFootNotes.java b/tooling/java2adoc/src/main/java/org/apache/isis/tooling/j2adoc/format/Snippets.java
similarity index 64%
rename from tooling/java2adoc/src/main/java/org/apache/isis/tooling/j2adoc/format/UnitFormatterWithSourceAndFootNotes.java
rename to tooling/java2adoc/src/main/java/org/apache/isis/tooling/j2adoc/format/Snippets.java
index 27636c7..d5846f7 100644
--- a/tooling/java2adoc/src/main/java/org/apache/isis/tooling/j2adoc/format/UnitFormatterWithSourceAndFootNotes.java
+++ b/tooling/java2adoc/src/main/java/org/apache/isis/tooling/j2adoc/format/Snippets.java
@@ -28,6 +28,8 @@ import org.asciidoctor.ast.StructuralNode;
 import org.apache.isis.commons.collections.Can;
 import org.apache.isis.tooling.j2adoc.J2AdocContext;
 import org.apache.isis.tooling.j2adoc.J2AdocUnit;
+import org.apache.isis.tooling.j2adoc.convert.J2AdocConverter;
+import org.apache.isis.tooling.j2adoc.convert.J2AdocConverterDefault;
 import org.apache.isis.tooling.javamodel.ast.AnnotationMemberDeclarations;
 import org.apache.isis.tooling.javamodel.ast.ConstructorDeclarations;
 import org.apache.isis.tooling.javamodel.ast.EnumConstantDeclarations;
@@ -38,49 +40,62 @@ import org.apache.isis.tooling.model4adoc.AsciiDocFactory;
 
 import lombok.NonNull;
 import lombok.val;
+import lombok.experimental.UtilityClass;
 
-public class UnitFormatterWithSourceAndFootNotes
-extends UnitFormatterAbstract {
+@UtilityClass
+public class Snippets {
 
-    public UnitFormatterWithSourceAndFootNotes(final @NonNull J2AdocContext j2aContext) {
-        super(j2aContext);
+    public static String title(final J2AdocUnit unit) {
+        final String format = formatFor(unit);
+        return String.format(format,
+                        unit.getFriendlyName());
     }
 
-    protected Optional<String> javaSource(final J2AdocUnit unit) {
+    private static String formatFor(J2AdocUnit unit) {
+        switch (unit.getTypeDeclaration().getKind()) {
+            case ANNOTATION: return "@%s";
+            case CLASS: return "%s";
+            case ENUM: return "%s _(enum)_";
+            case INTERFACE: return "%s _(interface)_";
+            default:
+                throw new IllegalArgumentException(String.format(
+                        "unknown kind: %s", unit.getTypeDeclaration().getKind()));
+        }
+    }
 
-        val java = new StringBuilder();
+    public static String javaSourceFor(J2AdocUnit unit) {
+        val buf = new StringBuilder();
 
-        java.append(String.format("%s %s {\n",
+        buf.append(String.format("%s %s {\n",
                 unit.getDeclarationKeyword(),
                 unit.getSimpleName()));
 
-        appendJavaSourceMemberFormat(java,
+        appendJavaSourceMemberFormat(buf,
                 unit.getTypeDeclaration().getEnumConstantDeclarations(),
                 EnumConstantDeclarations::asNormalized);
 
-        appendJavaSourceMemberFormat(java,
+        appendJavaSourceMemberFormat(buf,
                 unit.getTypeDeclaration().getPublicFieldDeclarations(),
                 FieldDeclarations::asNormalized);
 
-        appendJavaSourceMemberFormat(java,
+        appendJavaSourceMemberFormat(buf,
                 unit.getTypeDeclaration().getAnnotationMemberDeclarations(),
                 AnnotationMemberDeclarations::asNormalized);
 
-        appendJavaSourceMemberFormat(java,
+        appendJavaSourceMemberFormat(buf,
                 unit.getTypeDeclaration().getPublicConstructorDeclarations(),
                 ConstructorDeclarations::asNormalized);
 
-        appendJavaSourceMemberFormat(java,
+        appendJavaSourceMemberFormat(buf,
                 unit.getTypeDeclaration().getPublicMethodDeclarations(),
                 MethodDeclarations::asNormalized);
 
-        java.append("}\n");
+        buf.append("}\n");
 
-        return Optional.of(
-                AsciiDocFactory.SourceFactory.java(java.toString(), unit.getCanonicalName() + ".java"));
+        return buf.toString();
     }
 
-    private <T extends NodeWithJavadoc<?>> void appendJavaSourceMemberFormat(
+    private static<T extends NodeWithJavadoc<?>> void appendJavaSourceMemberFormat(
             final StringBuilder java,
             final Can<T> declarations,
             final Function<T, String> normalizer) {
@@ -92,51 +107,12 @@ extends UnitFormatterAbstract {
         });
     }
 
-//XXX java language syntax (for footnote text), but not used any more
-//
-//    @Override
-//    public String getEnumConstantFormat() {
-//        return "`%s`";
-//    }
-//
-//    @Override
-//    public String getFieldFormat() {
-//        return "`%s %s`";
-//    }
-//
-//    @Override
-//    public String getConstructorFormat() {
-//        return "`%s(%s)`";
-//    }
-//
-//    @Override
-//    public String getGenericConstructorFormat() {
-//        return "`%s %s(%s)`";
-//    }
-//
-//    @Override
-//    public String getMethodFormat() {
-//        return "`%s %s(%s)`";
-//    }
-//
-//    @Override
-//    public String getGenericMethodFormat() {
-//        return "`%s %s %s(%s)`";
-//    }
-
-    @Override
-    protected StructuralNode getMemberDescriptionContainer(StructuralNode parent) {
-        return AsciiDocFactory.footnotes(parent);
-    }
-
-    // -- HELPER
-
     enum Callout { INCLUDE, EXCLUDE;
         public static Callout when(boolean javadocPresent) {
             return javadocPresent ? INCLUDE : EXCLUDE;
         }
     }
-    private String javaSourceMemberFormat(final Callout callout) {
+    private static String javaSourceMemberFormat(final Callout callout) {
         return callout == Callout.INCLUDE
                 ? "  %s     // <.>\n"
                 : "  %s\n";
diff --git a/tooling/java2adoc/src/main/java/org/apache/isis/tooling/j2adoc/format/UnitFormatterAbstract.java b/tooling/java2adoc/src/main/java/org/apache/isis/tooling/j2adoc/format/UnitFormatterAbstract.java
index a9707e5..25a4baa 100644
--- a/tooling/java2adoc/src/main/java/org/apache/isis/tooling/j2adoc/format/UnitFormatterAbstract.java
+++ b/tooling/java2adoc/src/main/java/org/apache/isis/tooling/j2adoc/format/UnitFormatterAbstract.java
@@ -49,7 +49,7 @@ import lombok.val;
 public abstract class UnitFormatterAbstract
 implements UnitFormatter {
 
-    private final @NonNull J2AdocContext j2aContext;
+    protected final @NonNull J2AdocContext j2aContext;
 
     @Override
     public String getEnumConstantFormat() {
@@ -86,168 +86,13 @@ implements UnitFormatter {
         return "`%3$s%1$s(%4$s)` : `%2$s`";
     }
 
-    protected Optional<String> title(final J2AdocUnit unit) {
-        return Optional.of(
-                String.format(formatFor(unit),
-                        unit.getFriendlyName()));
-    }
-
-    private static String formatFor(J2AdocUnit unit) {
-        switch (unit.getTypeDeclaration().getKind()) {
-            case ANNOTATION: return "@%s";
-            case CLASS: return "%s";
-            case ENUM: return "%s _(enum)_";
-            case INTERFACE: return "%s _(interface)_";
-            default:
-                throw new IllegalArgumentException(String.format(
-                    "unknown kind: %s", unit.getTypeDeclaration().getKind()));
-        }
-    }
-
-    protected void intro(final J2AdocUnit unit, final StructuralNode parent) {
-        J2AdocConverter converter = J2AdocConverterDefault.of(j2aContext);
-
-        unit.getJavadoc()
-        .filter(javadoc->!Javadocs.hasHidden(javadoc))
-        .map(javadoc->converter.javadoc(javadoc, unit))
-        .ifPresent(doc->parent.getBlocks().addAll(doc.getBlocks()));
-    }
-
-    protected Optional<String> javaSource(final J2AdocUnit unit) {
-        return Optional.empty();
-    }
-
-    protected abstract StructuralNode getMemberDescriptionContainer(StructuralNode parent);
-
-    protected void appendMemberDescription(StructuralNode ul, String member, Document javadoc) {
-        val li = AsciiDocFactory.listItem((List) ul, member);
-        val openBlock = AsciiDocFactory.openBlock(li);
-        val javaDocBlock = AsciiDocFactory.block(openBlock);
-        javaDocBlock.getBlocks().addAll(javadoc.getBlocks());
-    }
-
-    protected void memberDescriptions(final J2AdocUnit unit, final StructuralNode doc) {
-
-        val ul = getMemberDescriptionContainer(doc);
-
-        if(! j2aContext.isMemberSections() || true) {
-
-            val converter = J2AdocConverterDefault.of(j2aContext);
-            appendMemberDescriptions(ul, unit,
-                    unit.getTypeDeclaration().getEnumConstantDeclarations(),
-                    decl -> converter.enumConstantDeclaration(decl),
-                    (javadoc, j2Unit) -> converter.javadoc(javadoc, unit)
-            );
-
-            appendMemberDescriptions(ul, unit,
-                    unit.getTypeDeclaration().getPublicFieldDeclarations(),
-                    decl -> converter.fieldDeclaration(decl, unit),
-                    (javadoc, j2Unit) -> converter.javadoc(javadoc, unit));
-
-            appendMemberDescriptions(ul, unit,
-                    unit.getTypeDeclaration().getAnnotationMemberDeclarations(),
-                    decl -> converter.annotationMemberDeclaration(decl, unit),
-                    (javadoc, j2Unit) -> converter.javadoc(javadoc, unit));
-
-            appendMemberDescriptions(ul, unit,
-                    unit.getTypeDeclaration().getPublicConstructorDeclarations(),
-                    decl -> converter.constructorDeclaration(decl, unit),
-                    (javadoc, j2Unit) -> converter.javadoc(javadoc, unit));
-
-            appendMemberDescriptions(ul, unit,
-                    unit.getTypeDeclaration().getPublicMethodDeclarations(),
-                    decl -> converter.methodDeclaration(decl, unit),
-                    (javadoc, j2Unit) -> converter.javadoc(javadoc, unit));
-
-        } else {
-
-//            var converter = J2AdocConverterDefault.of(j2aContext);
-//            appendMemberDescriptions(ul, unit,
-//                    unit.getTypeDeclaration().getEnumConstantDeclarations(),
-//                    decl -> converter.enumConstantDeclaration(decl),
-//                    (javadoc, j2Unit) -> converter.javadoc(javadoc, unit)
-//            );
-//
-//            appendMemberDescriptions(ul, unit,
-//                    unit.getTypeDeclaration().getPublicFieldDeclarations(),
-//                    decl -> converter.fieldDeclaration(decl, unit),
-//                    (javadoc, j2Unit) -> converter.javadoc(javadoc, unit));
-//
-//            appendMemberDescriptions(ul, unit,
-//                    unit.getTypeDeclaration().getAnnotationMemberDeclarations(),
-//                    decl -> converter.annotationMemberDeclaration(decl, unit),
-//                    (javadoc, j2Unit) -> converter.javadoc(javadoc, unit));
-//
-//            appendMemberDescriptions(ul, unit,
-//                    unit.getTypeDeclaration().getPublicConstructorDeclarations(),
-//                    decl -> converter.constructorDeclaration(decl, unit),
-//                    (javadoc, j2Unit) -> converter.javadoc(javadoc, unit));
-//
-//            appendMemberDescriptions(ul, unit,
-//                    unit.getTypeDeclaration().getPublicMethodDeclarations(),
-//                    decl -> converter.methodDeclaration(decl, unit),
-//                    (javadoc, j2Unit) -> converter.javadoc(javadoc, unit));
-
-            val titleBlock = block(doc);
-             titleBlock.setSource("== Members");
-
-//            val converter = J2AdocConverterDefault.of(j2aContext);
-//            appendMemberDescriptions(ul, unit,
-//                    unit.getTypeDeclaration().getEnumConstantDeclarations(),
-//                    decl -> converter.enumConstantDeclaration(decl),
-//                    (javadoc, j2Unit) -> converter.javadoc(javadoc, unit)
-//            );
-//
-//            appendMemberDescriptions(ul, unit,
-//                    unit.getTypeDeclaration().getPublicFieldDeclarations(),
-//                    decl -> converter.fieldDeclaration(decl, unit),
-//                    (javadoc, j2Unit) -> converter.javadoc(javadoc, unit));
-//
-//            appendMemberDescriptions(ul, unit,
-//                    unit.getTypeDeclaration().getAnnotationMemberDeclarations(),
-//                    decl -> converter.annotationMemberDeclaration(decl, unit),
-//                    (javadoc, j2Unit) -> converter.javadoc(javadoc, unit));
-//
-//            appendMemberDescriptions(ul, unit,
-//                    unit.getTypeDeclaration().getPublicConstructorDeclarations(),
-//                    decl -> converter.constructorDeclaration(decl, unit),
-//                    (javadoc, j2Unit) -> converter.javadoc(javadoc, unit));
-//
-//            appendMemberDescriptions(ul, unit,
-//                    unit.getTypeDeclaration().getPublicMethodDeclarations(),
-//                    decl -> converter.methodDeclaration(decl, unit),
-//                    (javadoc, j2Unit) -> converter.javadoc(javadoc, unit));
-
-
-        }
-
-    }
-
-    private <T extends NodeWithJavadoc<?>> void appendMemberDescriptions(
-            final StructuralNode container,
-            final J2AdocUnit unit,
-            final Can<T> declarations,
-            final Function<T, String> memberDescriber,
-            final BiFunction<Javadoc, J2AdocUnit, Document> javadoc2Asciidocker) {
-
-        declarations.stream()
-        .filter(Javadocs::presentAndNotHidden)
-        .forEach(nwj->{
-            nwj.getJavadoc()
-            .ifPresent(javadoc->{
-                appendMemberDescription(container,
-                                memberDescriber.apply(nwj),
-                                javadoc2Asciidocker.apply(javadoc, unit));
-            });
-        });
-    }
-
-
-    protected Optional<String> outro(final J2AdocUnit unit) {
-        return Optional.empty();
-    }
-
 
+    /**
+     * Main algorithm for laying out a unit.
+     *
+     * @param unit
+     * @return
+     */
     @Override
     public Document apply(final J2AdocUnit unit) {
 
@@ -261,7 +106,7 @@ implements UnitFormatter {
 
         // -- license
 
-        _Strings.nonEmpty(getContext().getLicenseHeader())
+        _Strings.nonEmpty(j2aContext.getLicenseHeader())
         .ifPresent(notice->AsciiDocFactory.attrNotice(doc, notice));
 
 
@@ -290,15 +135,97 @@ implements UnitFormatter {
         return doc;
     }
 
-    // -- DEPENDENCIES
+    /**
+     * Mandatory hook method to return a representation of the java source (if any)
+     *
+     * @param unit
+     * @return
+     */
+    protected abstract Optional<String> javaSource(final J2AdocUnit unit);
+
+    /**
+     * Mandatory hook method to append representation of the members of the unit.
+     *
+     * @param unit
+     * @param doc
+     */
+    protected abstract void memberDescriptions(final J2AdocUnit unit, final StructuralNode doc);
 
-    protected final J2AdocContext getContext() {
-        return j2aContext;
+    protected Optional<String> title(final J2AdocUnit unit) {
+        return Optional.of(Snippets.title(unit));
     }
 
-//    protected final J2AdocConverter getConverter() {
-//        return j2aContext.getConverter();
-//    }
+    protected void intro(final J2AdocUnit unit, final StructuralNode parent) {
+        J2AdocConverter converter = J2AdocConverterDefault.of(j2aContext);
 
+        unit.getJavadoc()
+                .filter(javadoc->!Javadocs.hasHidden(javadoc))
+                .map(javadoc->converter.javadoc(javadoc, unit))
+                .ifPresent(doc->parent.getBlocks().addAll(doc.getBlocks()));
+    }
+
+    /**
+     * Helper method for use by subclasses; calls
+     * {@link #appendMemberToList(List, String, Document)}
+     * for all provided {@link NodeWithJavadoc declarations}, using the
+     * provided memberRepresenter and the provided strategy for converting the
+     * javadoc into Asciidoc.
+     *
+     * @param ul - the List within the Asciidoc document to append to.
+     * @param unit - the containing java unit
+     * @param declarations - the collection of {@link NodeWithJavadoc declarations} to process
+     * @param memberRepresenter - encodes which parts of the member are to be pulled out into a representation
+     * @param javadoc2Asciidocker - strategy for converting each node's javadoc into some Asciidoc
+     *
+     * @param <T> - the specific subtype of {@link NodeWithJavadoc}
+     */
+    protected <T extends NodeWithJavadoc<?>> void appendMembersToList(
+            final List ul,
+            final J2AdocUnit unit,
+            final Can<T> declarations,
+            final Function<T, String> memberRepresenter,
+            final BiFunction<Javadoc, J2AdocUnit, Document> javadoc2Asciidocker) {
+
+        declarations.stream()
+                .filter(Javadocs::presentAndNotHidden)
+                .forEach(nwj->{
+                    nwj.getJavadoc()
+                            .ifPresent(javadoc-> {
+                                final String memberRepresentation = memberRepresenter.apply(nwj);
+                                final Document asciidoc = javadoc2Asciidocker.apply(javadoc, unit);
+                                appendMemberToList(ul,
+                                        memberRepresentation,
+                                        asciidoc);
+                            });
+                });
+    }
+
+
+    /**
+     * Helper method called by {@link #appendMembersToList(List, J2AdocUnit, Can, Function, BiFunction)}.
+     *
+     * @param ul
+     * @param listItemText
+     * @param listItemParagraphs
+     */
+    private static void appendMemberToList(
+            final List ul,
+            final String listItemText,
+            final Document listItemParagraphs) {
+
+        val li = AsciiDocFactory.listItem(ul, listItemText);
+        val openBlock = AsciiDocFactory.openBlock(li);
+        val javaDocBlock = AsciiDocFactory.block(openBlock);
+        javaDocBlock.getBlocks().addAll(listItemParagraphs.getBlocks());
+    }
+
+    /**
+     * Hook method (with empty default implementation)
+     * @param unit
+     * @return
+     */
+    protected Optional<String> outro(final J2AdocUnit unit) {
+        return Optional.empty();
+    }
 
 }
diff --git a/tooling/java2adoc/src/main/java/org/apache/isis/tooling/j2adoc/format/UnitFormatterCompact.java b/tooling/java2adoc/src/main/java/org/apache/isis/tooling/j2adoc/format/UnitFormatterCompact.java
index 4090874..c438f27 100644
--- a/tooling/java2adoc/src/main/java/org/apache/isis/tooling/j2adoc/format/UnitFormatterCompact.java
+++ b/tooling/java2adoc/src/main/java/org/apache/isis/tooling/j2adoc/format/UnitFormatterCompact.java
@@ -18,12 +18,18 @@
  */
 package org.apache.isis.tooling.j2adoc.format;
 
+import java.util.Optional;
+
+import org.asciidoctor.ast.List;
 import org.asciidoctor.ast.StructuralNode;
 
 import org.apache.isis.tooling.j2adoc.J2AdocContext;
-import org.apache.isis.tooling.j2adoc.convert.J2AdocConverter;
+import org.apache.isis.tooling.j2adoc.J2AdocUnit;
+import org.apache.isis.tooling.j2adoc.convert.J2AdocConverterDefault;
 import org.apache.isis.tooling.model4adoc.AsciiDocFactory;
 
+import static org.apache.isis.tooling.model4adoc.AsciiDocFactory.block;
+
 import lombok.NonNull;
 import lombok.val;
 
@@ -35,8 +41,44 @@ extends UnitFormatterAbstract {
     }
 
     @Override
-    protected StructuralNode getMemberDescriptionContainer(StructuralNode parent) {
-        return AsciiDocFactory.list(parent);
+    protected Optional<String> javaSource(final J2AdocUnit unit) {
+        return Optional.empty();
+    }
+
+    @Override
+    protected void memberDescriptions(final J2AdocUnit unit, final StructuralNode doc) {
+
+        val ul = AsciiDocFactory.list(doc);
+
+        val converter = J2AdocConverterDefault.of(j2aContext);
+        appendMembersToList(ul, unit,
+                unit.getTypeDeclaration().getEnumConstantDeclarations(),
+                decl -> converter.enumConstantDeclaration(decl),
+                (javadoc, j2Unit) -> converter.javadoc(javadoc, unit)
+        );
+
+        appendMembersToList(ul, unit,
+                unit.getTypeDeclaration().getPublicFieldDeclarations(),
+                decl -> converter.fieldDeclaration(decl, unit),
+                (javadoc, j2Unit) -> converter.javadoc(javadoc, unit));
+
+        appendMembersToList(ul, unit,
+                unit.getTypeDeclaration().getAnnotationMemberDeclarations(),
+                decl -> converter.annotationMemberDeclaration(decl, unit),
+                (javadoc, j2Unit) -> converter.javadoc(javadoc, unit));
+
+        appendMembersToList(ul, unit,
+                unit.getTypeDeclaration().getPublicConstructorDeclarations(),
+                decl -> converter.constructorDeclaration(decl, unit),
+                (javadoc, j2Unit) -> converter.javadoc(javadoc, unit));
+
+        appendMembersToList(ul, unit,
+                unit.getTypeDeclaration().getPublicMethodDeclarations(),
+                decl -> converter.methodDeclaration(decl, unit),
+                (javadoc, j2Unit) -> converter.javadoc(javadoc, unit));
+
     }
 
+
+
 }
diff --git a/tooling/java2adoc/src/main/java/org/apache/isis/tooling/j2adoc/format/UnitFormatterWithSourceAndCallouts.java b/tooling/java2adoc/src/main/java/org/apache/isis/tooling/j2adoc/format/UnitFormatterWithSourceAndCallouts.java
new file mode 100644
index 0000000..b85f4eb
--- /dev/null
+++ b/tooling/java2adoc/src/main/java/org/apache/isis/tooling/j2adoc/format/UnitFormatterWithSourceAndCallouts.java
@@ -0,0 +1,115 @@
+/*
+ *  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.j2adoc.format;
+
+import java.util.Optional;
+
+import org.asciidoctor.ast.StructuralNode;
+
+import org.apache.isis.tooling.j2adoc.J2AdocContext;
+import org.apache.isis.tooling.j2adoc.J2AdocUnit;
+import org.apache.isis.tooling.j2adoc.convert.J2AdocConverterDefault;
+import org.apache.isis.tooling.model4adoc.AsciiDocFactory;
+
+import static org.apache.isis.tooling.model4adoc.AsciiDocFactory.block;
+
+import lombok.NonNull;
+import lombok.val;
+
+public class UnitFormatterWithSourceAndCallouts
+extends UnitFormatterAbstract {
+
+    public UnitFormatterWithSourceAndCallouts(final @NonNull J2AdocContext j2aContext) {
+        super(j2aContext);
+    }
+
+    protected Optional<String> javaSource(final J2AdocUnit unit) {
+
+        final String javaSource = Snippets.javaSourceFor(unit);
+        return Optional.of(
+                AsciiDocFactory.SourceFactory.java(javaSource, unit.getCanonicalName() + ".java"));
+    }
+
+    @Override
+    protected void memberDescriptions(final J2AdocUnit unit, final StructuralNode doc) {
+
+        val ul = AsciiDocFactory.callouts(doc);
+
+        val converter = J2AdocConverterDefault.of(j2aContext);
+        appendMembersToList(ul, unit,
+                unit.getTypeDeclaration().getEnumConstantDeclarations(),
+                decl -> converter.enumConstantDeclaration(decl),
+                (javadoc, j2Unit) -> converter.javadoc(javadoc, unit)
+        );
+
+        appendMembersToList(ul, unit,
+                unit.getTypeDeclaration().getPublicFieldDeclarations(),
+                decl -> converter.fieldDeclaration(decl, unit),
+                (javadoc, j2Unit) -> converter.javadoc(javadoc, unit));
+
+        appendMembersToList(ul, unit,
+                unit.getTypeDeclaration().getAnnotationMemberDeclarations(),
+                decl -> converter.annotationMemberDeclaration(decl, unit),
+                (javadoc, j2Unit) -> converter.javadoc(javadoc, unit));
+
+        appendMembersToList(ul, unit,
+                unit.getTypeDeclaration().getPublicConstructorDeclarations(),
+                decl -> converter.constructorDeclaration(decl, unit),
+                (javadoc, j2Unit) -> converter.javadoc(javadoc, unit));
+
+        appendMembersToList(ul, unit,
+                unit.getTypeDeclaration().getPublicMethodDeclarations(),
+                decl -> converter.methodDeclaration(decl, unit),
+                (javadoc, j2Unit) -> converter.javadoc(javadoc, unit));
+
+    }
+
+    //XXX java language syntax (for footnote text), but not used any more
+//
+//    @Override
+//    public String getEnumConstantFormat() {
+//        return "`%s`";
+//    }
+//
+//    @Override
+//    public String getFieldFormat() {
+//        return "`%s %s`";
+//    }
+//
+//    @Override
+//    public String getConstructorFormat() {
+//        return "`%s(%s)`";
+//    }
+//
+//    @Override
+//    public String getGenericConstructorFormat() {
+//        return "`%s %s(%s)`";
+//    }
+//
+//    @Override
+//    public String getMethodFormat() {
+//        return "`%s %s(%s)`";
+//    }
+//
+//    @Override
+//    public String getGenericMethodFormat() {
+//        return "`%s %s %s(%s)`";
+//    }
+
+}
diff --git a/tooling/java2adoc/src/main/java/org/apache/isis/tooling/j2adoc/format/UnitFormatterWithSourceAndSections.java b/tooling/java2adoc/src/main/java/org/apache/isis/tooling/j2adoc/format/UnitFormatterWithSourceAndSections.java
new file mode 100644
index 0000000..0cb4e47
--- /dev/null
+++ b/tooling/java2adoc/src/main/java/org/apache/isis/tooling/j2adoc/format/UnitFormatterWithSourceAndSections.java
@@ -0,0 +1,98 @@
+/*
+ *  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.j2adoc.format;
+
+import java.util.Optional;
+import java.util.function.BiFunction;
+
+import com.github.javaparser.javadoc.Javadoc;
+
+import org.asciidoctor.ast.Document;
+import org.asciidoctor.ast.StructuralNode;
+
+import org.apache.isis.tooling.j2adoc.J2AdocContext;
+import org.apache.isis.tooling.j2adoc.J2AdocUnit;
+import org.apache.isis.tooling.j2adoc.convert.J2AdocConverterDefault;
+import org.apache.isis.tooling.model4adoc.AsciiDocFactory;
+
+import lombok.NonNull;
+import lombok.val;
+
+public class UnitFormatterWithSourceAndSections
+extends UnitFormatterAbstract {
+
+    public UnitFormatterWithSourceAndSections(final @NonNull J2AdocContext j2aContext) {
+        super(j2aContext);
+    }
+
+    protected Optional<String> javaSource(final J2AdocUnit unit) {
+
+        final String javaSource = Snippets.javaSourceFor(unit);
+        return Optional.of(
+                AsciiDocFactory.SourceFactory.java(javaSource, unit.getCanonicalName() + ".java"));
+    }
+
+    @Override
+    protected void memberDescriptions(final J2AdocUnit unit, final StructuralNode doc) {
+
+        val ul = AsciiDocFactory.callouts(doc);
+
+        var converter = J2AdocConverterDefault.of(j2aContext);
+        val strategy = new BiFunction<Javadoc, J2AdocUnit, Document>() {
+            @Override
+            public Document apply(Javadoc javadoc, J2AdocUnit j2Unit) {
+                return converter.javadoc(javadoc, unit);
+            }
+        };
+
+        appendMembersToList(ul, unit,
+                unit.getTypeDeclaration().getEnumConstantDeclarations(),
+                decl -> converter.enumConstantDeclaration(decl),
+                strategy
+        );
+
+        appendMembersToList(ul, unit,
+                unit.getTypeDeclaration().getPublicFieldDeclarations(),
+                decl -> converter.fieldDeclaration(decl, unit),
+                strategy);
+
+        appendMembersToList(ul, unit,
+                unit.getTypeDeclaration().getAnnotationMemberDeclarations(),
+                decl -> converter.annotationMemberDeclaration(decl, unit),
+                strategy);
+
+        appendMembersToList(ul, unit,
+                unit.getTypeDeclaration().getPublicConstructorDeclarations(),
+                decl -> converter.constructorDeclaration(decl, unit),
+                strategy);
+
+        appendMembersToList(ul, unit,
+                unit.getTypeDeclaration().getPublicMethodDeclarations(),
+                decl -> converter.methodDeclaration(decl, unit),
+                strategy);
+
+
+        val titleBlock = AsciiDocFactory.block(doc);
+        titleBlock.setSource("== Members");
+
+
+
+    }
+
+}
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 434a299..40f263e 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
@@ -148,13 +148,13 @@ public class AsciiDocFactory {
 
     // -- FOOTNOTES
 
-    public static org.asciidoctor.ast.List footnotes(StructuralNode parent) {
+    public static org.asciidoctor.ast.List callouts(StructuralNode parent) {
         val footnoteList = list(parent);
         footnoteList.setStyle("arabic");
         return footnoteList;
     }
 
-    public static ListItem footnote(org.asciidoctor.ast.List parent, @NonNull String source) {
+    public static ListItem callout(org.asciidoctor.ast.List parent, @NonNull String source) {
         return listItem(parent, source);
     }
 
diff --git a/tooling/model4adoc/src/test/java/org/apache/isis/tooling/model4adoc/test/ast/FootnoteTest.java b/tooling/model4adoc/src/test/java/org/apache/isis/tooling/model4adoc/test/ast/FootnoteTest.java
index b203cf9..fed4696 100644
--- a/tooling/model4adoc/src/test/java/org/apache/isis/tooling/model4adoc/test/ast/FootnoteTest.java
+++ b/tooling/model4adoc/src/test/java/org/apache/isis/tooling/model4adoc/test/ast/FootnoteTest.java
@@ -41,7 +41,7 @@ class FootnoteTest extends AbstractAsciiDocWriterTest {
         super.debugEnabled = false;
     }
 
-    
+
     //<.> fn-1
     //+
     //--
@@ -63,30 +63,30 @@ class FootnoteTest extends AbstractAsciiDocWriterTest {
     //--
     @Test
     void testFootnote() throws IOException {
-        
-        val footnotes = AsciiDocFactory.footnotes(doc);
-        val footnoteLI = AsciiDocFactory.footnote(footnotes, "fn-1");
+
+        val footnotes = AsciiDocFactory.callouts(doc);
+        val footnoteLI = AsciiDocFactory.callout(footnotes, "fn-1");
         val footnote = AsciiDocFactory.openBlock(footnoteLI);
-        
-        
+
+
         val note = AsciiDocFactory.warning(footnote);
         AsciiDocFactory.block(note, "warn-1");
         AsciiDocFactory.block(note, "warn-2");
-        
+
         AsciiDocFactory.block(footnote, "para-1");
         AsciiDocFactory.block(footnote, "para-2");
-        
+
         val nestedList = AsciiDocFactory.list(footnote);
         AsciiDocFactory.listItem(nestedList, "li-1");
         AsciiDocFactory.listItem(nestedList, "li-2");
-        
+
         AsciiDocFactory.block(footnote, "para-3");
-        
+
         AsciiDocFactory.tip(doc, "Here's something worth knowing...");
-        
+
         assertDocumentIsCorrectlyWritten(doc);
     }
-    
+
 
 
 }