diff --git a/src/main/jastadd/ToJson.jrag b/src/main/jastadd/ToJson.jrag
index a67880bab7348ef12ebe80ea8ab267d7726d4dda..82482270d7507dd61da409497c81bc0e6fb2bfba 100644
--- a/src/main/jastadd/ToJson.jrag
+++ b/src/main/jastadd/ToJson.jrag
@@ -100,6 +100,8 @@ aspect ToJson {
     JsonObject doc = jsonDocObject();
     if (doc != null && !doc.get("attribute").stringValue("").isEmpty()) {
       return "attr";
+    } else if (doc != null && !doc.get("relation").stringValue("").isEmpty()) {
+      return "rel";
     } else {
       return "method";
     }
diff --git a/src/main/java/org/extendj/ragdoc/JavaDocParser.java b/src/main/java/org/extendj/ragdoc/JavaDocParser.java
index 5111ce1ce418bb9787688f8d83a14c89ff29ad73..31178fcde688b758f94f203029ec69dd34cc5b97 100644
--- a/src/main/java/org/extendj/ragdoc/JavaDocParser.java
+++ b/src/main/java/org/extendj/ragdoc/JavaDocParser.java
@@ -117,6 +117,7 @@ public class JavaDocParser extends Object {
             tag.equals("astdecl") ||
             tag.equals("ast") || tag.equals("aspect") ||
             tag.equals("apilevel") || tag.equals("attribute") ||
+            tag.equals("relation") ||
         /* JavaDoc tags:
          * (http://docs.oracle.com/javase/7/docs/technotes/tools/windows/javadoc.html#javadoctags)
          */
diff --git a/src/main/java/org/extendj/ragdoc/JsonBuilder.java b/src/main/java/org/extendj/ragdoc/JsonBuilder.java
index d59c8dee259d4d75179eb464d152bb672fef97f9..07f98502c9d029c9bfe2c6228d49e9c0072a672c 100644
--- a/src/main/java/org/extendj/ragdoc/JsonBuilder.java
+++ b/src/main/java/org/extendj/ragdoc/JsonBuilder.java
@@ -29,6 +29,7 @@
  */
 package org.extendj.ragdoc;
 
+import org.extendj.ast.*;
 import org.extendj.ast.Access;
 import org.extendj.ast.BodyDecl;
 import org.extendj.ast.ClassDecl;
@@ -39,7 +40,9 @@ import org.extendj.ast.FieldDecl;
 import org.extendj.ast.InterfaceDecl;
 import org.extendj.ast.MethodDecl;
 import org.extendj.ast.ParameterDeclaration;
+import org.extendj.ast.SimpleSet;
 import org.extendj.ast.TypeDecl;
+import org.extendj.ast.UnknownType;
 import org.extendj.ast.Variable;
 import org.extendj.util.RelativePath;
 import org.extendj.util.Sorting;
@@ -72,7 +75,7 @@ public class JsonBuilder {
   /** Ordering of the package object kinds. */
   private static final String[] TYPE_KINDS = { "ast-class", "interface", "class" };
 
-  private static final String[] MEMBER_KINDS = { "constr", "attr", "field", "method" };
+  private static final String[] MEMBER_KINDS = { "constr", "attr", "rel", "field", "method" };
 
   private final File rootDir;
   private java.util.List<String> ragRoot = new java.util.LinkedList<>();
@@ -130,6 +133,8 @@ public class JsonBuilder {
 
   public void addMethod(MethodDecl method, JsonArray members) {
     JsonObject doc = method.jsonDocObject();
+    // System.out.println("" + method.type() + ": " + method + ", kind=" + method.objectKind());
+    // System.out.println("`-> doc=" + doc + " doc.get(relation)=" + (doc != null ? doc.get("relation") : "/"));
     if (shouldDocument(method, doc)) {
       JsonObject obj = new JsonObject();
       obj.add("name", Json.of(method.name()));
@@ -394,7 +399,8 @@ public class JsonBuilder {
           // Create declaration structure.
           JsonObject decl = parser.parse();
           if (!decl.get("e").stringValue("").isEmpty()) {
-            decl.set("e", typeRef(type.lookupType(decl.get("e").stringValue("")).singletonValue()));
+            decl.set("e",
+                typeRef(safeLookupType(type, decl.get("e").stringValue("")).singletonValue()));
           }
           doc.set("astdecl", decl);
           JsonArray array = decl.get("c").array();
@@ -402,7 +408,7 @@ public class JsonBuilder {
             JsonObject comp = c.object();
             if (!comp.get("e").stringValue("").isEmpty()) {
               comp.set("e",
-                  typeRef(type.lookupType(stripGenericPart(comp.get("e").stringValue(""))).singletonValue()));
+                  typeRef(safeLookupType(type, stripGenericPart(comp.get("e").stringValue("")))));
             }
           }
         } catch (IOException e) {
@@ -433,6 +439,15 @@ public class JsonBuilder {
     return obj;
   }
 
+  private TypeDecl safeLookupType(TypeDecl parent, String name) {
+    SimpleSet<TypeDecl> types = parent.lookupType(name);
+    if (types.isEmpty()) {
+      System.err.println("Could not find type for '" + name + "'");
+      return parent.unknownType();
+    }
+    return types.singletonValue();
+  }
+
   private String stripGenericPart(String s) {
     int ltIndex = s.indexOf('<');
     return ltIndex == -1 ? s : s.substring(0, ltIndex);
@@ -455,8 +470,10 @@ public class JsonBuilder {
    * Adds inherited members from superclasses.
    */
   private void addInheritedMembers(TypeDecl type, JsonObject obj) {
+    // TODO (rs): Add inherited relations
     if (type instanceof ClassDecl) {
       JsonArray inheritedMethods = new JsonArray();
+      JsonArray inheritedRelations = new JsonArray();
       JsonArray inheritedAttributes = new JsonArray();
       JsonArray inheritedFields = new JsonArray();
       // The locally declared set of methods.
@@ -471,6 +488,7 @@ public class JsonBuilder {
           break;
         }
         JsonArray methodArray = new JsonArray();
+        JsonArray relationArray = new JsonArray();
         JsonArray attributeArray = new JsonArray();
         // Set to keep track of which method names have already been listed for
         // the current type.
@@ -486,6 +504,10 @@ public class JsonBuilder {
               if (isAttribute(original)) {
                 // Add to attributes inherited from the current superclass.
                 attributeArray.add(original.name());
+              } else if (isRelation(original)) {
+                // Add to relations inherited from the current superclass.
+                System.out.println("got inherited relation");
+                relationArray.add(original.name());
               } else {
                 // Add to methods inherited from the current superclass.
                 methodArray.add(original.name());
@@ -504,6 +526,7 @@ public class JsonBuilder {
             }
           }
         }
+        // FIXME: array conversion should be put in extra method
         if (!methodArray.isEmpty()) {
           JsonObject inherited = new JsonObject();
           inherited.add("superclass", typeRef(superclass));
@@ -514,6 +537,16 @@ public class JsonBuilder {
           inherited.add("members", sorted);
           inheritedMethods.add(inherited);
         }
+        if (!relationArray.isEmpty()) {
+          JsonObject inherited = new JsonObject();
+          inherited.add("superclass", typeRef(superclass));
+          JsonArray sorted = new JsonArray();
+          for (JsonValue member : Sorting.sortBy(relationArray, Sorting.jsonStringFun)) {
+            sorted.add(member);
+          }
+          inherited.add("members", sorted);
+          inheritedRelations.add(inherited);
+        }
         if (!attributeArray.isEmpty()) {
           JsonObject inherited = new JsonObject();
           inherited.add("superclass", typeRef(superclass));
@@ -542,6 +575,9 @@ public class JsonBuilder {
       if (!inheritedAttributes.isEmpty()) {
         obj.add("inherited_attributes", inheritedAttributes);
       }
+      if (!inheritedRelations.isEmpty()) {
+        obj.add("inherited_relations", inheritedRelations);
+      }
       if (!inheritedFields.isEmpty()) {
         obj.add("inherited_fields", inheritedFields);
       }
@@ -557,6 +593,15 @@ public class JsonBuilder {
     return !(doc == null || doc.get("attribute").stringValue("").isEmpty());
   }
 
+  /**
+   * @return {@code true} if the argument is a relation,
+   * {@code false} if it is an ordinary method.
+   */
+  private static boolean isRelation(MethodDecl method) {
+    JsonObject doc = method.jsonDocObject();
+    return !(doc == null || doc.get("relation").stringValue("").isEmpty());
+  }
+
   private static JsonArray groupify(Map<String, JsonArray> groupMap, String[] kinds) {
     JsonArray groups = new JsonArray();
     for (String kind : kinds) {