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 2021/02/02 18:21:29 UTC

[isis] branch master updated: ISIS-2516: adds J2AdocUnit namespace logic

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 25d6bd7  ISIS-2516: adds J2AdocUnit namespace logic
25d6bd7 is described below

commit 25d6bd7378e42d650500273bc781fc8f3e28122c
Author: Andi Huber <ah...@apache.org>
AuthorDate: Tue Feb 2 19:21:11 2021 +0100

    ISIS-2516: adds J2AdocUnit namespace logic
    
    no ambiguity logging yet
---
 .../org/apache/isis/commons/collections/Can.java   | 72 +++++++++++++++--
 .../apache/isis/commons/collections/Can_Empty.java | 10 +++
 .../isis/commons/collections/Can_Multiple.java     | 21 ++++-
 .../isis/commons/collections/Can_Singleton.java    | 11 +++
 .../apache/isis/commons/collections/CanTest.java   | 22 ++++++
 isis-tooling.yml                                   |  2 +-
 .../main/java/org/apache/isis/tooling/cli/Cli.java | 22 +++++-
 .../cli/adocfix/OrphanedIncludeStatementFixer.java |  6 +-
 .../isis/tooling/cli/projdoc/ProjectDocModel.java  | 13 ++-
 .../isis/tooling/cli/projdoc/ProjectDocWriter.java |  9 +--
 .../apache/isis/tooling/j2adoc/J2AdocContext.java  | 76 +++++++++++++++++-
 .../org/apache/isis/tooling/j2adoc/J2AdocUnit.java | 39 +++++----
 .../tooling/j2adoc/convert/J2AdocConverter.java    | 12 +--
 .../j2adoc/convert/J2AdocConverterDefault.java     | 86 +++++++++++++-------
 .../j2adoc/format/UnitFormatterAbstract.java       | 24 +++---
 .../tooling/javamodel/ast/AnyTypeDeclaration.java  | 88 +++++++++++----------
 .../tooling/javamodel/ast/CompilationUnits.java    |  6 ++
 .../tooling/javamodel/ast/ImportDeclarations.java  | 92 ++++++++++++++++++++++
 18 files changed, 484 insertions(+), 127 deletions(-)

diff --git a/commons/src/main/java/org/apache/isis/commons/collections/Can.java b/commons/src/main/java/org/apache/isis/commons/collections/Can.java
index 57f9ad5..eacee9e 100644
--- a/commons/src/main/java/org/apache/isis/commons/collections/Can.java
+++ b/commons/src/main/java/org/apache/isis/commons/collections/Can.java
@@ -21,6 +21,7 @@ package org.apache.isis.commons.collections;
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Iterator;
 import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.Objects;
@@ -43,6 +44,7 @@ import org.apache.isis.commons.internal.exceptions._Exceptions;
 
 import static org.apache.isis.commons.internal.base._With.requires;
 
+import lombok.NonNull;
 import lombok.val;
 
 /**
@@ -394,11 +396,9 @@ extends Iterable<T>, Comparable<Can<T>>, Serializable {
 
     // -- TRAVERSAL
 
-    @Override
-    default void forEach(Consumer<? super T> action) {
-        requires(action, "action");
-        stream().forEach(action);
-    }
+    Iterator<T> reverseIterator();
+    
+    void forEach(@NonNull Consumer<? super T> action);
     
     /**
      * Similar to {@link #forEach(Consumer)}, but zipps in {@code zippedIn} to iterate through 
@@ -489,7 +489,7 @@ extends Iterable<T>, Comparable<Can<T>>, Serializable {
      * @param other
      * @return whether this is element-wise equal to {@code other}
      */
-    default boolean isEqualTo(Can<?> other) {
+    default boolean isEqualTo(final @Nullable Can<?> other) {
         if(other==null) {
             return false;
         }
@@ -508,6 +508,66 @@ extends Iterable<T>, Comparable<Can<T>>, Serializable {
         
         return true;
     }
+    
+    // -- PARTIAL EQUALITY
+
+    /**
+     * Let {@literal n} be the number of elements in {@code other}. 
+     * Returns whether the first {@literal n} elements of this {@code Can} are 
+     * element-wise equal to {@code other}.
+     * @param other
+     */
+    default boolean startsWith(final @Nullable Can<?> other) {
+        if(other==null
+                || other.isEmpty()) {
+            return true;
+        }
+        if(this.size()<other.size()) {
+            return false;
+        }
+        
+        val thisIterator = this.iterator();
+        val otherIterator = other.iterator();
+        
+        while(otherIterator.hasNext()) {
+            val otherElement = otherIterator.next();
+            val thisElement  = thisIterator.next();
+            
+            if(!thisElement.equals(otherElement)) {
+                return false;
+            }
+        }
+        return true; 
+    }
+
+    /**
+     * Let {@literal n} be the number of elements in {@code other}. 
+     * Returns whether the last {@literal n} elements of this {@code Can} are 
+     * element-wise equal to {@code other}.
+     * @param other
+     */
+    default boolean endsWith(final @Nullable Can<?> other) {
+        if(other==null
+                || other.isEmpty()) {
+            return true;
+        }
+        if(this.size()<other.size()) {
+            return false;
+        }
+        
+        val thisIterator = this.reverseIterator();
+        val otherIterator = other.reverseIterator();
+        
+        while(otherIterator.hasNext()) {
+            val otherElement = otherIterator.next();
+            val thisElement  = thisIterator.next();
+            
+            if(!thisElement.equals(otherElement)) {
+                return false;
+            }
+        }
+        return true; 
+    }
 
     // -- SHORTCUTS FOR PREDICATES
 
diff --git a/commons/src/main/java/org/apache/isis/commons/collections/Can_Empty.java b/commons/src/main/java/org/apache/isis/commons/collections/Can_Empty.java
index 7d2172c..adf3df4 100644
--- a/commons/src/main/java/org/apache/isis/commons/collections/Can_Empty.java
+++ b/commons/src/main/java/org/apache/isis/commons/collections/Can_Empty.java
@@ -26,6 +26,7 @@ import java.util.List;
 import java.util.Optional;
 import java.util.function.BiConsumer;
 import java.util.function.BiFunction;
+import java.util.function.Consumer;
 import java.util.function.Predicate;
 import java.util.function.Supplier;
 import java.util.stream.Stream;
@@ -99,6 +100,15 @@ final class Can_Empty<T> implements Can<T> {
     }
     
     @Override
+    public Iterator<T> reverseIterator() {
+        return iterator();
+    }
+    
+    @Override
+    public void forEach(Consumer<? super T> action) {
+    }
+    
+    @Override
     public Can<T> filter(@Nullable Predicate<? super T> predicate) {
         return this; // identity
     }
diff --git a/commons/src/main/java/org/apache/isis/commons/collections/Can_Multiple.java b/commons/src/main/java/org/apache/isis/commons/collections/Can_Multiple.java
index 8d0fdda..2e31b15 100644
--- a/commons/src/main/java/org/apache/isis/commons/collections/Can_Multiple.java
+++ b/commons/src/main/java/org/apache/isis/commons/collections/Can_Multiple.java
@@ -27,6 +27,7 @@ import java.util.List;
 import java.util.Optional;
 import java.util.function.BiConsumer;
 import java.util.function.BiFunction;
+import java.util.function.Consumer;
 import java.util.function.Predicate;
 import java.util.function.Supplier;
 import java.util.stream.Collectors;
@@ -36,6 +37,7 @@ import javax.annotation.Nullable;
 
 import org.apache.isis.commons.internal.base._Casts;
 import org.apache.isis.commons.internal.base._Objects;
+import org.apache.isis.commons.internal.exceptions._Exceptions;
 
 import lombok.NonNull;
 import lombok.RequiredArgsConstructor;
@@ -108,6 +110,18 @@ final class Can_Multiple<T> implements Can<T> {
     }
     
     @Override
+    public Iterator<T> reverseIterator() {
+        return new Iterator<T>() {
+            private int remainingCount = size();
+            @Override public boolean hasNext() { return remainingCount>0; }
+            @Override public T next() {
+                if(!hasNext()) { throw _Exceptions.noSuchElement(); }
+                return elements.get(--remainingCount);
+            }
+        };
+    }
+    
+    @Override
     public Can<T> reverse() {
         val reverse = new ArrayList<T>(elements.size());
         for(int i=elements.size()-1; i>=0; --i) {
@@ -117,7 +131,12 @@ final class Can_Multiple<T> implements Can<T> {
     }
     
     @Override
-    public Can<T> filter(@Nullable Predicate<? super T> predicate) {
+    public void forEach(final @NonNull Consumer<? super T> action) {
+        elements.forEach(action);
+    }
+    
+    @Override
+    public Can<T> filter(final @Nullable Predicate<? super T> predicate) {
         if(predicate==null) {
             return this; // identity
         }
diff --git a/commons/src/main/java/org/apache/isis/commons/collections/Can_Singleton.java b/commons/src/main/java/org/apache/isis/commons/collections/Can_Singleton.java
index 32f3214..f3a4f74 100644
--- a/commons/src/main/java/org/apache/isis/commons/collections/Can_Singleton.java
+++ b/commons/src/main/java/org/apache/isis/commons/collections/Can_Singleton.java
@@ -28,6 +28,7 @@ import java.util.Objects;
 import java.util.Optional;
 import java.util.function.BiConsumer;
 import java.util.function.BiFunction;
+import java.util.function.Consumer;
 import java.util.function.Predicate;
 import java.util.function.Supplier;
 import java.util.stream.Stream;
@@ -100,6 +101,16 @@ final class Can_Singleton<T> implements Can<T> {
     }
     
     @Override
+    public Iterator<T> reverseIterator() {
+        return iterator();
+    }
+    
+    @Override
+    public void forEach(@NonNull Consumer<? super T> action) {
+        action.accept(this.element);
+    }
+    
+    @Override
     public Can<T> filter(@Nullable Predicate<? super T> predicate) {
         if(predicate==null) {
             return this; // identity
diff --git a/commons/src/test/java/org/apache/isis/commons/collections/CanTest.java b/commons/src/test/java/org/apache/isis/commons/collections/CanTest.java
index 24814fa..bee5267 100644
--- a/commons/src/test/java/org/apache/isis/commons/collections/CanTest.java
+++ b/commons/src/test/java/org/apache/isis/commons/collections/CanTest.java
@@ -23,6 +23,8 @@ import java.io.IOException;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import org.apache.isis.commons.SerializationTester;
 
@@ -61,6 +63,26 @@ class CanTest {
         assertEquals(Can.<String>of("c", "b", "a"), Can.<String>of("a", "b", "c").reverse());
     }
     
+    @Test
+    void multiCan_startsWith() {
+        assertTrue(Can.<String>of("a", "b", "c").startsWith(Can.<String>of("a", "b", "c")));
+        assertFalse(Can.<String>of("a", "b", "c").startsWith(Can.<String>of("a", "b", "c", "x")));
+        assertTrue(Can.<String>of("a", "b", "c").startsWith(Can.<String>of("a", "b")));
+        assertTrue(Can.<String>of("a", "b", "c").startsWith(Can.<String>empty()));
+        assertTrue(Can.<String>of("a", "b", "c").startsWith(null));
+        assertFalse(Can.<String>of("a", "b", "c").startsWith(Can.<String>of("a", "b", "x")));
+    }
+    
+    @Test
+    void multiCan_endsWith() {
+        assertTrue(Can.<String>of("a", "b", "c").endsWith(Can.<String>of("a", "b", "c")));
+        assertFalse(Can.<String>of("a", "b", "c").endsWith(Can.<String>of("x", "a", "b", "c")));
+        assertTrue(Can.<String>of("a", "b", "c").endsWith(Can.<String>of("b", "c")));
+        assertTrue(Can.<String>of("a", "b", "c").endsWith(Can.<String>empty()));
+        assertTrue(Can.<String>of("a", "b", "c").endsWith(null));
+        assertFalse(Can.<String>of("a", "b", "c").endsWith(Can.<String>of("x", "b", "a")));
+    }
+    
     // -- FILTERING
     
     @Test
diff --git a/isis-tooling.yml b/isis-tooling.yml
index 183c13a..d3a1060 100644
--- a/isis-tooling.yml
+++ b/isis-tooling.yml
@@ -99,5 +99,5 @@ commands:
     description: "These tables summarize all Maven artifacts available with _Apache Isis_."
 
   index:
-    fixOrphanedAdocIncludeStatements: true
+    fixOrphanedAdocIncludeStatements: false
 
diff --git a/tooling/cli/src/main/java/org/apache/isis/tooling/cli/Cli.java b/tooling/cli/src/main/java/org/apache/isis/tooling/cli/Cli.java
index 5207145..e2ea0c9 100644
--- a/tooling/cli/src/main/java/org/apache/isis/tooling/cli/Cli.java
+++ b/tooling/cli/src/main/java/org/apache/isis/tooling/cli/Cli.java
@@ -120,9 +120,25 @@ class Cli implements Callable<Integer> {
             return 0;
         }
     }
+    
+    @Command(
+            name = "projdoc",
+            description = "Writes all generated (AsciiDoc) to given output.")
+    static class ProjectDocCommand extends CliCommandAbstract {
+
+        @Override
+        public Integer call() throws Exception {
+
+            if(getOutputPath() != null) {
+                getConfig().getGlobal().setOutputRootFolder(getOutputPath());
+            }
 
-    //TODO mvn2gradle
-    //description = "Detects differences between Maven and Gradle (multi-module) projects.",
+            val projTree = ProjectNodeFactory.maven(getProjectRoot());
+            val projectDocModel = new ProjectDocModel(projTree);
+            projectDocModel.generateAsciiDoc(getConfig(), ProjectDocModel.Mode.ALL);
+            return 0;
+        }
+    }
 
 
     // -- ENTRY POINT
@@ -134,7 +150,5 @@ class Cli implements Callable<Integer> {
         System.exit(exitCode);
     }
 
-    // -- HELPER
-
 
 }
diff --git a/tooling/cli/src/main/java/org/apache/isis/tooling/cli/adocfix/OrphanedIncludeStatementFixer.java b/tooling/cli/src/main/java/org/apache/isis/tooling/cli/adocfix/OrphanedIncludeStatementFixer.java
index 4565613..cc8d71f 100644
--- a/tooling/cli/src/main/java/org/apache/isis/tooling/cli/adocfix/OrphanedIncludeStatementFixer.java
+++ b/tooling/cli/src/main/java/org/apache/isis/tooling/cli/adocfix/OrphanedIncludeStatementFixer.java
@@ -27,7 +27,6 @@ import org.apache.isis.commons.internal.base._Refs;
 import org.apache.isis.commons.internal.base._Text;
 import org.apache.isis.tooling.cli.CliConfig;
 import org.apache.isis.tooling.j2adoc.J2AdocContext;
-import org.apache.isis.tooling.j2adoc.J2AdocUnit.LookupKey;
 import org.apache.isis.tooling.model4adoc.include.IncludeStatement;
 import org.apache.isis.tooling.model4adoc.include.IncludeStatements;
 
@@ -71,7 +70,8 @@ public final class OrphanedIncludeStatementFixer {
                 val correctedIncludeStatement = _Refs.<IncludeStatement>objectRef(null);
                 val typeSimpleName = include.getCanonicalName();
 
-                j2aContext.getUnit(LookupKey.typeSimpleName(typeSimpleName))
+                j2aContext.findUnitsByTypeSimpleName(typeSimpleName)
+                .getSingleton() // selects for exactly one result, if ambiguous does nothing
                 .ifPresent(unit->{
 
                     val expected = IncludeStatement.builder()
@@ -97,6 +97,8 @@ public final class OrphanedIncludeStatementFixer {
                     }
 
                 });
+                
+                //TODO log cases of ambiguity or when not found
 
                 return correctedIncludeStatement
                         .getValue()
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 e45b6cd..4998b26 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
@@ -23,14 +23,10 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Optional;
-import java.util.Set;
 import java.util.SortedSet;
 import java.util.TreeSet;
-import java.util.function.BiFunction;
-import java.util.function.BinaryOperator;
 import java.util.function.Consumer;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
@@ -92,8 +88,11 @@ public class ProjectDocModel {
     }
 
     public enum Mode {
+        ALL,
         OVERVIEW,
-        INDEX
+        INDEX;
+        public boolean includeOverview() {   return this == INDEX || this == ALL; }
+        public boolean includeIndex() {   return this == INDEX || this == ALL; }
     }
 
     public void generateAsciiDoc(final @NonNull CliConfig cliConfig, final @NonNull Mode mode) {
@@ -150,7 +149,7 @@ public class ProjectDocModel {
         // now generate the overview or index
         writeSections(sections, doc, j2aContext, mode, asciiDocFiles::add);
 
-        if (mode == Mode.OVERVIEW) {
+        if (mode.includeOverview()) {
             ProjectDocWriter.write(cliConfig, doc, j2aContext, mode);
         }
 
@@ -329,7 +328,7 @@ public class ProjectDocModel {
 
         sectionModules
                 .forEach(module -> {
-                    if(mode == Mode.INDEX) {
+                    if(mode.includeIndex()) {
                         gatherAdocFiles(module.getProjectDirectory(), onAdocFile);
                     }
 
diff --git a/tooling/cli/src/main/java/org/apache/isis/tooling/cli/projdoc/ProjectDocWriter.java b/tooling/cli/src/main/java/org/apache/isis/tooling/cli/projdoc/ProjectDocWriter.java
index a457abd..33a028f 100644
--- a/tooling/cli/src/main/java/org/apache/isis/tooling/cli/projdoc/ProjectDocWriter.java
+++ b/tooling/cli/src/main/java/org/apache/isis/tooling/cli/projdoc/ProjectDocWriter.java
@@ -52,7 +52,7 @@ final class ProjectDocWriter {
         val overview = cliConfig.getCommands().getOverview();
         val index = cliConfig.getCommands().getIndex();
 
-        val rootFolder = global.getOutputRootFolder();
+        //val rootFolder = global.getOutputRootFolder();
         val pagesFolder = global.getDocumentPagesFolder();
 
         val deleteCount = _Refs.intRef(0);
@@ -60,8 +60,7 @@ final class ProjectDocWriter {
 
         try {
 
-            // TODO: should split this out into two separate methods etc.
-            if (mode == ProjectDocModel.Mode.OVERVIEW) {
+            if (mode.includeOverview()) {
 
                 // write system overview
                 val overviewFile = new File(pagesFolder, overview.getSystemOverviewFilename());
@@ -70,12 +69,12 @@ final class ProjectDocWriter {
                 ++writeCount;
             }
 
-            if(mode == ProjectDocModel.Mode.INDEX) {
+            if(mode.includeIndex()) {
 
                 // delete all generated documents in the index
                 _Files.searchFiles(pagesFolder, dir->true, file-> {
                     val fileName = file.getName();
-                    return  fileName.endsWith(".adoc") &&
+                    return fileName.endsWith(".adoc") &&
                            !fileName.equals(overview.getSystemOverviewFilename());
                 })
                 .stream()
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 cb507bb..50045e0 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
@@ -28,13 +28,20 @@ import java.util.stream.Stream;
 
 import javax.annotation.Nullable;
 
+import com.github.javaparser.ast.ImportDeclaration;
+
+import org.apache.isis.commons.collections.Can;
+import org.apache.isis.commons.internal.base._Strings;
 import org.apache.isis.commons.internal.collections._Maps;
+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;
 import lombok.Getter;
@@ -80,14 +87,19 @@ public class J2AdocContext {
     // -- UNIT INDEX
     
     private final Map<LookupKey, J2AdocUnit> unitIndex = _Maps.newTreeMap();
+    private final ListMultimap<String, J2AdocUnit> unitsByTypeSimpleName = _Multimaps.newListMultimap();
     
     public J2AdocContext add(final @NonNull J2AdocUnit unit) {
-        val previousKey = unitIndex.put(LookupKey.of(unit.getResourceCoordinates()), unit);
+        val unitKey = LookupKey.of(unit.getResourceCoordinates());
+        val previousKey = unitIndex.put(unitKey, unit);
         if(previousKey!=null) {
             throw _Exceptions.unrecoverableFormatted(
-                    "J2AUnit index entries must be unique (index key collision on %s)", 
-                    previousKey);
+                    "J2AUnit index entries must be unique, "
+                    + "index key collision on \nexists: %s\nnew:    %s", 
+                    previousKey,
+                    unit);
         }
+        unitsByTypeSimpleName.putElement(unit.getName().stream().collect(Collectors.joining(".")), unit);
         return this;
     }
     
@@ -100,6 +112,60 @@ public class J2AdocContext {
         .stream();
     }
     
+    /**
+     * Find the J2AdocUnit by given search parameters.
+     * @param partialName - can be anything, originating eg. from java-doc {@literal link} tags.
+     * @param importDeclarations
+     */
+    public Optional<J2AdocUnit> findUnit(
+            final @Nullable String partialName, 
+            final @NonNull  Can<ImportDeclaration> importDeclarations) {
+        
+        if(_Strings.isNullOrEmpty(partialName)) {
+            return Optional.empty();
+        }
+        
+        if(partialName.contains("#")) {
+            // skip member reference lookup
+            //XXX reserved for future extensions ... 
+            //val partialNameWithoutMember = _Refs.stringRef(partialName).cutAtIndexOf("#");
+            return Optional.empty();  
+        }
+        
+        final Can<String> nameDiscriminator = Can.ofStream(
+                _Strings.splitThenStream(partialName, "."));
+        
+        final Can<Can<String>> potentialFqns = Can.ofStream(
+                ImportDeclarations
+                .streamPotentialFqns(nameDiscriminator, importDeclarations));
+        
+        
+        val nameDiscriminatorPartIterator = nameDiscriminator.reverseIterator();
+        val typeSimpeNameFirstCandidate = Can.ofSingleton(nameDiscriminatorPartIterator.next());
+        
+        return Stream.iterate(
+                typeSimpeNameFirstCandidate, 
+                __->nameDiscriminatorPartIterator.hasNext(), 
+                parts->parts.add(nameDiscriminatorPartIterator.next()))
+        .map((Can<String> typeSimpeNameParts)->typeSimpeNameParts.stream()
+                .collect(Collectors.joining(".")))
+        .flatMap((String typeSimpeNameCandidate)->unitsByTypeSimpleName
+                .getOrElseEmpty(typeSimpeNameCandidate)
+                .stream())
+        .filter((J2AdocUnit unit)->{
+                Can<String> unitFqnParts = unit.getFqnParts();
+                return potentialFqns.stream()
+                        .anyMatch(potentialFqn->potentialFqn.isEqualTo(unitFqnParts));
+        })
+        .findFirst();
+        
+        //TODO should log ambiguous cases
+    }
+    
+    public Can<J2AdocUnit> findUnitsByTypeSimpleName(String typeSimpleName) {
+        return Can.ofCollection(unitsByTypeSimpleName.getOrElseEmpty(typeSimpleName));
+    }
+    
     public Stream<J2AdocUnit> streamUnits() {
         return unitIndex.values().stream();
     }
@@ -127,5 +193,9 @@ public class J2AdocContext {
                 .formatterFactory(UnitFormatterCompact::new)
                 ;        
     }
+
+
+
+
     
 }
diff --git a/tooling/java2adoc/src/main/java/org/apache/isis/tooling/j2adoc/J2AdocUnit.java b/tooling/java2adoc/src/main/java/org/apache/isis/tooling/j2adoc/J2AdocUnit.java
index b0fcaf3..c5489e7 100644
--- a/tooling/java2adoc/src/main/java/org/apache/isis/tooling/j2adoc/J2AdocUnit.java
+++ b/tooling/java2adoc/src/main/java/org/apache/isis/tooling/j2adoc/J2AdocUnit.java
@@ -24,6 +24,7 @@ import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 import com.github.javaparser.StaticJavaParser;
+import com.github.javaparser.ast.ImportDeclaration;
 import com.github.javaparser.javadoc.Javadoc;
 
 import org.asciidoctor.ast.Document;
@@ -47,26 +48,30 @@ import lombok.extern.log4j.Log4j2;
 @Log4j2
 public final class J2AdocUnit {
     
-    //TODO not namespace aware yet
     @Value
     public static class LookupKey implements Comparable<LookupKey> {
-        private final @NonNull String key;
+        
+        /** full namespace, no parts discarded; delimited by {@literal .} */
+        private final @NonNull String namespace;
+        
+        /** full name, no parts discarded; delimited by {@literal $} */
+        private final @NonNull String name;
 
-        //XXX resco has all the info, to make keys namespace aware
         public static LookupKey of(final @NonNull ResourceCoordinates resco) {
-            return new LookupKey(resco.getName().stream().collect(Collectors.joining(".")));
-        }
-        //XXX in a better world we would resolve these types to fqn type names
-        public static @NonNull LookupKey typeSimpleName(final @NonNull String typeSimpleName) {
-            return new LookupKey(typeSimpleName);
-        }
-        //XXX in a better world we would resolve these links to fqn type names
-        public static @NonNull LookupKey javadocLink(final @NonNull String javadocLink) {
-            return new LookupKey(javadocLink);
+            return new LookupKey(
+                    resco.getNamespace().stream().collect(Collectors.joining(".")), 
+                    resco.getName().stream().collect(Collectors.joining("$")));
         }
+        
         @Override
         public int compareTo(LookupKey other) {
-            return _Strings.compareNullsFirst(this.key, other==null ? null : other.key);
+            if(other==null) {
+                return -1;
+            }
+            int c = _Strings.compareNullsFirst(this.namespace, other.namespace);
+            return (c!=0)
+                ?  c
+                : _Strings.compareNullsFirst(this.name, other.name);
         }
     }
 
@@ -156,6 +161,13 @@ public final class J2AdocUnit {
         return typeDeclaration.getKind().getJavaKeyword();
     }
     
+    public Can<ImportDeclaration> getImportDeclarations() {
+        return typeDeclaration.getImportDeclarations();
+    }
+    
+    @Getter(lazy = true)
+    private final Can<String> fqnParts = getNamespace().addAll(getName());
+    
     @Getter(lazy = true)
     private final Optional<Javadoc> javadoc = typeDeclaration.getJavadoc();
     
@@ -178,5 +190,4 @@ public final class J2AdocUnit {
                 getFriendlyName());
     }
 
-
 }
diff --git a/tooling/java2adoc/src/main/java/org/apache/isis/tooling/j2adoc/convert/J2AdocConverter.java b/tooling/java2adoc/src/main/java/org/apache/isis/tooling/j2adoc/convert/J2AdocConverter.java
index 4ff054d..f1dcb89 100644
--- a/tooling/java2adoc/src/main/java/org/apache/isis/tooling/j2adoc/convert/J2AdocConverter.java
+++ b/tooling/java2adoc/src/main/java/org/apache/isis/tooling/j2adoc/convert/J2AdocConverter.java
@@ -18,6 +18,7 @@
  */
 package org.apache.isis.tooling.j2adoc.convert;
 
+import com.github.javaparser.ast.ImportDeclaration;
 import com.github.javaparser.ast.body.AnnotationMemberDeclaration;
 import com.github.javaparser.ast.body.ConstructorDeclaration;
 import com.github.javaparser.ast.body.EnumConstantDeclaration;
@@ -27,6 +28,7 @@ import com.github.javaparser.javadoc.Javadoc;
 
 import org.asciidoctor.ast.Document;
 
+import org.apache.isis.commons.collections.Can;
 import org.apache.isis.tooling.j2adoc.J2AdocContext;
 import org.apache.isis.tooling.j2adoc.J2AdocUnit;
 
@@ -34,17 +36,17 @@ import lombok.NonNull;
 
 public interface J2AdocConverter {
 
-    Document javadoc(Javadoc javadoc);
+    Document javadoc(Javadoc javadoc, Can<ImportDeclaration> importDeclarations);
 
-    String annotationMemberDeclaration(AnnotationMemberDeclaration amd);
+    String annotationMemberDeclaration(AnnotationMemberDeclaration amd, Can<ImportDeclaration> importDeclarations);
     
     String enumConstantDeclaration(EnumConstantDeclaration ecd);
     
-    String fieldDeclaration(FieldDeclaration fd);
+    String fieldDeclaration(FieldDeclaration fd, Can<ImportDeclaration> importDeclarations);
     
-    String constructorDeclaration(ConstructorDeclaration cd);
+    String constructorDeclaration(ConstructorDeclaration cd, Can<ImportDeclaration> importDeclarations);
 
-    String methodDeclaration(MethodDeclaration md);
+    String methodDeclaration(MethodDeclaration md, Can<ImportDeclaration> importDeclarations);
     
     String xref(@NonNull J2AdocUnit unit);
     
diff --git a/tooling/java2adoc/src/main/java/org/apache/isis/tooling/j2adoc/convert/J2AdocConverterDefault.java b/tooling/java2adoc/src/main/java/org/apache/isis/tooling/j2adoc/convert/J2AdocConverterDefault.java
index 67c170f..3074618 100644
--- a/tooling/java2adoc/src/main/java/org/apache/isis/tooling/j2adoc/convert/J2AdocConverterDefault.java
+++ b/tooling/java2adoc/src/main/java/org/apache/isis/tooling/j2adoc/convert/J2AdocConverterDefault.java
@@ -23,6 +23,7 @@ import java.util.stream.Stream;
 
 import javax.annotation.Nullable;
 
+import com.github.javaparser.ast.ImportDeclaration;
 import com.github.javaparser.ast.body.AnnotationMemberDeclaration;
 import com.github.javaparser.ast.body.ConstructorDeclaration;
 import com.github.javaparser.ast.body.EnumConstantDeclaration;
@@ -45,7 +46,6 @@ 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.j2adoc.J2AdocUnit.LookupKey;
 import org.apache.isis.tooling.javamodel.ast.AnnotationMemberDeclarations;
 import org.apache.isis.tooling.javamodel.ast.ConstructorDeclarations;
 import org.apache.isis.tooling.javamodel.ast.EnumConstantDeclarations;
@@ -64,7 +64,9 @@ final class J2AdocConverterDefault implements J2AdocConverter {
     private final J2AdocContext j2aContext;
 
     @Override
-    public String annotationMemberDeclaration(AnnotationMemberDeclaration amd) {
+    public String annotationMemberDeclaration(
+            final @NonNull AnnotationMemberDeclaration amd,
+            final @NonNull Can<ImportDeclaration> importDeclarations) {
         val isDeprecated = amd.getAnnotations().stream()
                 .anyMatch(a->a.getNameAsString().equals("Deprecated"))
                 || amd.getJavadoc()
@@ -78,7 +80,7 @@ final class J2AdocConverterDefault implements J2AdocConverter {
         val annotMemberFormat =  j2aContext.getFormatter().getAnnotationMemberFormat();
        
         return String.format(annotMemberFormat,
-                type(amd.getType()), 
+                type(amd.getType(), importDeclarations), 
                 String.format(memberNameFormat, AnnotationMemberDeclarations.asNormalizedName(amd)));
     }
     
@@ -101,7 +103,10 @@ final class J2AdocConverterDefault implements J2AdocConverter {
     }
     
     @Override
-    public String fieldDeclaration(final @NonNull FieldDeclaration fd) {
+    public String fieldDeclaration(
+            final @NonNull FieldDeclaration fd,
+            final @NonNull Can<ImportDeclaration> importDeclarations) {
+        
         val isDeprecated = fd.getAnnotations().stream()
                 .anyMatch(a->a.getNameAsString().equals("Deprecated"))
                 || fd.getJavadoc()
@@ -119,12 +124,15 @@ final class J2AdocConverterDefault implements J2AdocConverter {
         val fieldFormat =  j2aContext.getFormatter().getFieldFormat();
        
         return String.format(fieldFormat,
-                type(fd.getCommonType()), 
+                type(fd.getCommonType(), importDeclarations), 
                 String.format(memberNameFormat, FieldDeclarations.asNormalizedName(fd)));
     }
     
     @Override
-    public String constructorDeclaration(final @NonNull ConstructorDeclaration cd) {
+    public String constructorDeclaration(
+            final @NonNull ConstructorDeclaration cd,
+            final @NonNull Can<ImportDeclaration> importDeclarations) {
+        
         val isDeprecated = cd.getAnnotations().stream()
                 .anyMatch(a->a.getNameAsString().equals("Deprecated"))
                 || cd.getJavadoc()
@@ -150,14 +158,16 @@ final class J2AdocConverterDefault implements J2AdocConverter {
         val args = Can.<Object>of(
                 isGenericMember ? typeParamters(typeParams) : null,  // Cans do ignored null 
                 String.format(memberNameFormat, ConstructorDeclarations.asNormalizedName(cd)),
-                parameters(cd.getParameters().stream())
+                parameters(cd.getParameters().stream(), importDeclarations)
                 );
        
         return String.format(constructorFormat, args.toArray(_Constants.emptyObjects));
     }
 
     @Override
-    public String methodDeclaration(final @NonNull MethodDeclaration md) {
+    public String methodDeclaration(
+            final @NonNull MethodDeclaration md, 
+            final @NonNull Can<ImportDeclaration> importDeclarations) {
         
         val isDeprecated = md.getAnnotations().stream()
                 .anyMatch(a->a.getNameAsString().equals("Deprecated"))
@@ -183,18 +193,20 @@ final class J2AdocConverterDefault implements J2AdocConverter {
         
         val args = Can.<Object>of(
                 isGenericMember ? typeParamters(typeParams) : null,  // Cans do ignored null 
-                type(md.getType()),
+                type(md.getType(), importDeclarations),
                 String.format(memberNameFormat, MethodDeclarations.asNormalizedName(md)), 
-                parameters(md.getParameters().stream())
+                parameters(md.getParameters().stream(), importDeclarations)
                 );
        
         return String.format(methodFormat, args.toArray(_Constants.emptyObjects));
                 
     }
     
-    public String parameters(final @NonNull Stream<Parameter> parameterStream) {
+    public String parameters(
+            final @NonNull Stream<Parameter> parameterStream,
+            final @NonNull Can<ImportDeclaration> importDeclarations) {
         return parameterStream
-                .map(this::parameterDeclaration)
+                .map(x->parameterDeclaration(x, importDeclarations))
                 .collect(Collectors.joining(", "));
     }
     
@@ -210,23 +222,29 @@ final class J2AdocConverterDefault implements J2AdocConverter {
                 .collect(Collectors.joining(", ")));
     }
     
-    public String type(final @NonNull Type type) {
+    public String type(
+            final @NonNull Type type,
+            final @NonNull Can<ImportDeclaration> importDeclarations) {
+        
         if(type instanceof ClassOrInterfaceType) {
-            return classOrInterfaceType((ClassOrInterfaceType) type);
+            return classOrInterfaceType((ClassOrInterfaceType) type, importDeclarations);
         }
         return type.asString();
     }
     
-    public String classOrInterfaceType(final @NonNull ClassOrInterfaceType type) {
+    public String classOrInterfaceType(
+            final @NonNull ClassOrInterfaceType type,
+            final @NonNull Can<ImportDeclaration> importDeclarations) {
+        
         val sb = new StringBuilder();
-        sb.append(xrefIfRequired(type.getNameAsString())); // type simple name, no generics
+        sb.append(xrefIfRequired(type.getNameAsString(), importDeclarations)); // type simple name, no generics
         type.getTypeArguments()
         .ifPresent(typeArgs->{
             sb
             .append("<")
             .append(
                     typeArgs.stream()
-                    .map(typeArg->type(typeArg))
+                    .map(typeArg->type(typeArg, importDeclarations))
                     .collect(Collectors.joining(", "))
             )
             .append(">");
@@ -236,21 +254,26 @@ final class J2AdocConverterDefault implements J2AdocConverter {
     }
         
     
-    public String parameterDeclaration(Parameter p) {
+    public String parameterDeclaration(
+            final @NonNull Parameter p,
+            final @NonNull Can<ImportDeclaration> importDeclarations) {
+        
         return String.format("%s%s %s",
-                type(p.getType()),
+                type(p.getType(), importDeclarations),
                 p.isVarArgs() ? "..." : "",
                 p.getNameAsString());
     }
     
     @Override
-    public Document javadoc(final @NonNull Javadoc javadoc) {
+    public Document javadoc(
+            final @NonNull Javadoc javadoc,
+            final @NonNull Can<ImportDeclaration> importDeclarations) {
 
         val doc = AsciiDocFactory.doc();
         
         Javadocs.streamTagContent(javadoc, "deprecated")
         .findFirst()
-        .map(javadocDescription->javadocDescription(javadocDescription))
+        .map(javadocDescription->javadocDescription(javadocDescription, importDeclarations))
         .ifPresent(deprecatedAdoc->{
             
             val deprecatedBlock = AsciiDocFactory.warning(doc);
@@ -258,20 +281,22 @@ final class J2AdocConverterDefault implements J2AdocConverter {
             deprecatedBlock.getBlocks().addAll(deprecatedAdoc.getBlocks());
         });
         
-        val descriptionAdoc = javadocDescription(javadoc.getDescription());
+        val descriptionAdoc = javadocDescription(javadoc.getDescription(), importDeclarations);
         
         doc.getBlocks().addAll(descriptionAdoc.getBlocks());
         
         return doc;
     }
     
-    public String inlineTag(final @NonNull JavadocInlineTag inlineTag) {
+    public String inlineTag(
+            final @NonNull JavadocInlineTag inlineTag, 
+            final @NonNull Can<ImportDeclaration> importDeclarations) {
 
         val inlineContent = inlineTag.getContent().trim();
 
         switch(inlineTag.getType()) {
         case LINK:
-            val referencedUnit = j2aContext.getUnit(LookupKey.javadocLink(inlineContent)).orElse(null);
+            val referencedUnit = j2aContext.findUnit(inlineContent, importDeclarations).orElse(null);
             if(referencedUnit!=null) {
                 return String.format(" %s ", xref(referencedUnit));
             }
@@ -298,8 +323,10 @@ final class J2AdocConverterDefault implements J2AdocConverter {
         return xref;
     }
 
-    private String xrefIfRequired(final @NonNull String typeSimpleName) {
-        return j2aContext.getUnit(LookupKey.typeSimpleName(typeSimpleName))
+    private String xrefIfRequired(
+            final @NonNull String typeSimpleName,
+            final @NonNull Can<ImportDeclaration> importDeclarations) {
+        return j2aContext.findUnit(typeSimpleName, importDeclarations)
                 .map(this::xref)
                 .orElse(typeSimpleName);
     }
@@ -310,7 +337,10 @@ final class J2AdocConverterDefault implements J2AdocConverter {
     
     // -- HELPER
     
-    private Document javadocDescription(final @NonNull JavadocDescription javadocDescription) {
+    private Document javadocDescription(
+            final @NonNull JavadocDescription javadocDescription,
+            final @NonNull Can<ImportDeclaration> importDeclarations) {
+        
         val javadocResolved = new StringBuilder();
 
         javadocDescription.getElements()
@@ -319,7 +349,7 @@ final class J2AdocConverterDefault implements J2AdocConverter {
             if(e instanceof JavadocSnippet) {
                 javadocResolved.append(javadocSnippet((JavadocSnippet)e));
             } else if(e instanceof JavadocInlineTag) {
-                javadocResolved.append(inlineTag((JavadocInlineTag) e));
+                javadocResolved.append(inlineTag((JavadocInlineTag) e, importDeclarations));
             } else {
                 javadocResolved.append(e.toText());
             }
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 7e0c8c6..df6425d 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
@@ -87,9 +87,12 @@ implements UnitFormatter {
     }
     
     protected void intro(final J2AdocUnit unit, final StructuralNode parent) {
+
+        val importDeclarations = unit.getImportDeclarations();
+        
         unit.getJavadoc()
         .filter(javadoc->!Javadocs.hasHidden(javadoc))
-        .map(javadoc->getConverter().javadoc(javadoc))
+        .map(javadoc->getConverter().javadoc(javadoc, importDeclarations))
         .ifPresent(doc->parent.getBlocks().addAll(doc.getBlocks()));
     }
     
@@ -108,6 +111,7 @@ implements UnitFormatter {
     
     protected void memberDescriptions(final J2AdocUnit unit, final StructuralNode parent) {
         
+        val importDeclarations = unit.getImportDeclarations();
         val ul = getMemberDescriptionContainer(parent);
         
         
@@ -119,7 +123,7 @@ implements UnitFormatter {
                 
                 appendMemberDescription(ul, 
                                 getConverter().enumConstantDeclaration(ecd),
-                                getConverter().javadoc(javadoc));
+                                getConverter().javadoc(javadoc, importDeclarations));
             });
         });
         
@@ -131,8 +135,8 @@ implements UnitFormatter {
             .ifPresent(javadoc->{
                 
                 appendMemberDescription(ul,
-                        getConverter().fieldDeclaration(fd),
-                        getConverter().javadoc(javadoc));
+                        getConverter().fieldDeclaration(fd, importDeclarations),
+                        getConverter().javadoc(javadoc, importDeclarations));
             });
             
         });
@@ -144,8 +148,8 @@ implements UnitFormatter {
             .ifPresent(javadoc->{
                 
                 appendMemberDescription(ul, 
-                                getConverter().annotationMemberDeclaration(ecd),
-                                getConverter().javadoc(javadoc));
+                                getConverter().annotationMemberDeclaration(ecd, importDeclarations),
+                                getConverter().javadoc(javadoc, importDeclarations));
             });
         });
         
@@ -157,8 +161,8 @@ implements UnitFormatter {
             .ifPresent(javadoc->{
                 
                 appendMemberDescription(ul,
-                        getConverter().constructorDeclaration(cd),
-                        getConverter().javadoc(javadoc));
+                        getConverter().constructorDeclaration(cd, importDeclarations),
+                        getConverter().javadoc(javadoc, importDeclarations));
             });
             
         });
@@ -171,8 +175,8 @@ implements UnitFormatter {
             .ifPresent(javadoc->{
                 
                 appendMemberDescription(ul,
-                        getConverter().methodDeclaration(md),
-                        getConverter().javadoc(javadoc));
+                        getConverter().methodDeclaration(md, importDeclarations),
+                        getConverter().javadoc(javadoc, importDeclarations));
             });
             
         });
diff --git a/tooling/javamodel/src/main/java/org/apache/isis/tooling/javamodel/ast/AnyTypeDeclaration.java b/tooling/javamodel/src/main/java/org/apache/isis/tooling/javamodel/ast/AnyTypeDeclaration.java
index 24383b1..870bf2e 100644
--- a/tooling/javamodel/src/main/java/org/apache/isis/tooling/javamodel/ast/AnyTypeDeclaration.java
+++ b/tooling/javamodel/src/main/java/org/apache/isis/tooling/javamodel/ast/AnyTypeDeclaration.java
@@ -21,6 +21,7 @@ package org.apache.isis.tooling.javamodel.ast;
 import java.util.Optional;
 
 import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.ImportDeclaration;
 import com.github.javaparser.ast.Node;
 import com.github.javaparser.ast.PackageDeclaration;
 import com.github.javaparser.ast.body.AnnotationDeclaration;
@@ -62,28 +63,28 @@ public final class AnyTypeDeclaration {
         public boolean isEnum() { return this == ENUM; }
         public boolean isInterface() { return this == INTERFACE; }
     }
-    
+
     private final @NonNull CompilationUnit cu;
     private final @NonNull Kind kind;
     private final TypeDeclaration<?> td;
     private final AnnotationDeclaration annotationDeclaration;
     private final ClassOrInterfaceDeclaration classOrInterfaceDeclaration; 
     private final EnumDeclaration enumDeclaration;
-    
+
     private final Can<AnnotationMemberDeclaration> annotationMemberDeclarations;
     private final Can<EnumConstantDeclaration> enumConstantDeclarations;
     private final Can<FieldDeclaration> publicFieldDeclarations;
     private final Can<ConstructorDeclaration> publicConstructorDeclarations;
     private final Can<MethodDeclaration> publicMethodDeclarations;
-    
-    
+
+
     // -- FACTORIES
-    
-    
+
+
     public static AnyTypeDeclaration of(
             final @NonNull AnnotationDeclaration annotationDeclaration,
             final @NonNull CompilationUnit cu) {
-        
+
         return new AnyTypeDeclaration(
                 cu,
                 Kind.ANNOTATION, 
@@ -93,38 +94,38 @@ public final class AnyTypeDeclaration {
                 null,
                 //members
                 AnnotationDeclarations.streamAnnotationMemberDeclarations(annotationDeclaration)
-                    .collect(Can.toCan()),
+                .collect(Can.toCan()),
                 Can.empty(),
                 AnnotationDeclarations.streamFieldDeclarations(annotationDeclaration)
-                    .collect(Can.toCan()),
+                .collect(Can.toCan()),
                 Can.empty(),
                 AnnotationDeclarations.streamMethodDeclarations(annotationDeclaration)
-                    .collect(Can.toCan())
+                .collect(Can.toCan())
                 );
     }
-    
+
     public static AnyTypeDeclaration of(
             final @NonNull ClassOrInterfaceDeclaration classOrInterfaceDeclaration,
             final @NonNull CompilationUnit cu) {
         return new AnyTypeDeclaration(
                 cu,
                 classOrInterfaceDeclaration.isInterface() ? Kind.INTERFACE : Kind.CLASS, 
-                classOrInterfaceDeclaration,
-                null,
-                classOrInterfaceDeclaration,
-                null,
-                //members
-                Can.empty(),
-                Can.empty(),
-                ClassOrInterfaceDeclarations.streamPublicFieldDeclarations(classOrInterfaceDeclaration)
-                    .collect(Can.toCan()),
-                ClassOrInterfaceDeclarations.streamPublicConstructorDeclarations(classOrInterfaceDeclaration)
-                    .collect(Can.toCan()),
-                ClassOrInterfaceDeclarations.streamPublicMethodDeclarations(classOrInterfaceDeclaration)
-                    .collect(Can.toCan())
+                        classOrInterfaceDeclaration,
+                        null,
+                        classOrInterfaceDeclaration,
+                        null,
+                        //members
+                        Can.empty(),
+                        Can.empty(),
+                        ClassOrInterfaceDeclarations.streamPublicFieldDeclarations(classOrInterfaceDeclaration)
+                        .collect(Can.toCan()),
+                        ClassOrInterfaceDeclarations.streamPublicConstructorDeclarations(classOrInterfaceDeclaration)
+                        .collect(Can.toCan()),
+                        ClassOrInterfaceDeclarations.streamPublicMethodDeclarations(classOrInterfaceDeclaration)
+                        .collect(Can.toCan())
                 );
     }
-    
+
     public static AnyTypeDeclaration of(
             final @NonNull EnumDeclaration enumDeclaration,
             final @NonNull CompilationUnit cu) {
@@ -138,20 +139,20 @@ public final class AnyTypeDeclaration {
                 //members
                 Can.empty(),
                 EnumDeclarations.streamEnumConstantDeclarations(enumDeclaration)
-                    .collect(Can.toCan()),
+                .collect(Can.toCan()),
                 EnumDeclarations.streamPublicFieldDeclarations(enumDeclaration)
-                    .collect(Can.toCan()),
+                .collect(Can.toCan()),
                 EnumDeclarations.streamPublicConstructorDeclarations(enumDeclaration)
-                    .collect(Can.toCan()),
+                .collect(Can.toCan()),
                 EnumDeclarations.streamPublicMethodDeclarations(enumDeclaration)
-                    .collect(Can.toCan())
+                .collect(Can.toCan())
                 );
     }
-    
-      public static AnyTypeDeclaration auto(
+
+    public static AnyTypeDeclaration auto(
             final @NonNull TypeDeclaration<?> td,
             final @NonNull CompilationUnit cu) {
-        
+
         if(td instanceof ClassOrInterfaceDeclaration) {
             return of((ClassOrInterfaceDeclaration)td, cu);
         }
@@ -163,34 +164,39 @@ public final class AnyTypeDeclaration {
         }
         throw _Exceptions.unsupportedOperation("unsupported TypeDeclaration %s", td.getClass());
     }
-    
+
     // -- UTILITY
-    
+
+    @Getter(lazy = true)
+    private final Can<ImportDeclaration> importDeclarations = CompilationUnits
+        .streamImportDeclarations(cu)
+        .collect(Can.toCan());
+
     public Optional<Javadoc> getJavadoc() {
         return td.getJavadoc();
     }
-    
+
     public Optional<PackageDeclaration> getPackageDeclaration() {
         return cu.getPackageDeclaration();
     }
-    
+
     public boolean hasIndexDirective() {
         return TypeDeclarations.hasIndexDirective(td);
     }
-    
+
     /**
      * Returns the recursively resolved (nested) type name. 
      * Same as {@link #getSimpleName()} if type is not nested. 
      */
     @Getter(lazy = true)
     private final Can<String> name = createName();
-    
+
     public String getSimpleName() {
         return td.getNameAsString();
     }
-    
+
     // -- HELPER 
-    
+
     private Can<String> createName() {
         val nameParts = _Lists.<String>newLinkedList();
         nameParts.push(td.getNameAsString());
@@ -204,5 +210,5 @@ public final class AnyTypeDeclaration {
         return Can.ofCollection(nameParts);
     }
 
-    
+
 }
diff --git a/tooling/javamodel/src/main/java/org/apache/isis/tooling/javamodel/ast/CompilationUnits.java b/tooling/javamodel/src/main/java/org/apache/isis/tooling/javamodel/ast/CompilationUnits.java
index cf2843c..8b89579 100644
--- a/tooling/javamodel/src/main/java/org/apache/isis/tooling/javamodel/ast/CompilationUnits.java
+++ b/tooling/javamodel/src/main/java/org/apache/isis/tooling/javamodel/ast/CompilationUnits.java
@@ -25,6 +25,7 @@ import java.util.stream.Stream;
 
 import com.github.javaparser.StaticJavaParser;
 import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.ImportDeclaration;
 import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
 import com.github.javaparser.ast.body.EnumDeclaration;
 import com.github.javaparser.ast.body.TypeDeclaration;
@@ -46,6 +47,11 @@ public final class CompilationUnits {
         .orElse(false);
     }
     
+    public static <T> Stream<ImportDeclaration> streamImportDeclarations(
+            final @NonNull CompilationUnit compilationUnit) {
+        return compilationUnit.getImports().stream();
+    }
+    
     public static <T> Stream<AnyTypeDeclaration> streamTypeDeclarations(
             final @NonNull CompilationUnit compilationUnit) {
         
diff --git a/tooling/javamodel/src/main/java/org/apache/isis/tooling/javamodel/ast/ImportDeclarations.java b/tooling/javamodel/src/main/java/org/apache/isis/tooling/javamodel/ast/ImportDeclarations.java
new file mode 100644
index 0000000..e86f216
--- /dev/null
+++ b/tooling/javamodel/src/main/java/org/apache/isis/tooling/javamodel/ast/ImportDeclarations.java
@@ -0,0 +1,92 @@
+/*
+ *  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.ast;
+
+import java.util.stream.Stream;
+
+import com.github.javaparser.ast.ImportDeclaration;
+
+import org.apache.isis.commons.collections.Can;
+import org.apache.isis.commons.internal.base._Strings;
+
+import lombok.val;
+
+public final class ImportDeclarations {
+
+    /**
+     * Given a Can of Java import declarations returns a stream of possible fqn names 
+     * represented as Can of parts, where parts are the type's namespace parts and name
+     * parts all together.
+     * @param nameDiscriminator
+     * @param importDeclarations
+     */
+    public static Stream<Can<String>> streamPotentialFqns(
+            final Can<String> nameDiscriminator,
+            final Can<ImportDeclaration> importDeclarations) {
+
+        return importDeclarations.stream()
+                .flatMap(importDeclaration->streamPotentialFqns(nameDiscriminator, importDeclaration));
+    }
+    
+    /**
+     * Given a Java import declaration returns a stream of possible fqn names 
+     * represented as Can of parts, where parts are the type's namespace parts and name
+     * parts all together.
+     * @param nameDiscriminator
+     * @param importDeclaration
+     */
+    public static Stream<Can<String>> streamPotentialFqns(
+            final Can<String> nameDiscriminator,
+            final ImportDeclaration importDeclaration) {
+                        
+        if(importDeclaration.isStatic()) {
+            return Stream.empty();
+        }
+        
+        val fqnParts = splitIntoParts(importDeclaration);
+        
+        if(!importDeclaration.isAsterisk()) {
+            
+            if(!fqnParts.endsWith(nameDiscriminator)) {
+                return Stream.empty();
+            }
+            
+            return Stream.of(fqnParts);
+        }
+        
+        // handle asterisk case
+        
+        val nameDiscriminatorPartIterator = nameDiscriminator.reverseIterator();
+
+        val firstCandidate = fqnParts.add(nameDiscriminatorPartIterator.next());
+        
+        return Stream.iterate(
+                firstCandidate, 
+                __->nameDiscriminatorPartIterator.hasNext(), 
+                parts->parts.add(nameDiscriminatorPartIterator.next()));
+    }
+    
+    // -- HELPER
+    
+    private static Can<String> splitIntoParts(final ImportDeclaration importDeclaration) {
+        return Can.ofStream(_Strings.splitThenStream(importDeclaration.getNameAsString(), "."));
+    }
+    
+
+}