GithubHelp home page GithubHelp logo

dnault / therapi-runtime-javadoc Goto Github PK

View Code? Open in Web Editor NEW
109.0 109.0 20.0 420 KB

Read Javadoc comments at run time.

License: Apache License 2.0

Java 100.00%
annotation-processor javadoc javadoc-comments javadocs runtime

therapi-runtime-javadoc's People

Contributors

bbottema avatar dnault avatar joffrey-bion avatar kirkch avatar linyongliang2018 avatar sheikah45 avatar skissane avatar yanxiyue avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

therapi-runtime-javadoc's Issues

Basic support for JEP 413 (Code Snippets in Java API Documentation)

JDK 18 delivered the @snippet tag for javadoc: https://openjdk.java.net/jeps/413

Java 18 Snippet documentation: https://docs.oracle.com/en/java/javase/18/code-snippet/index.html

The JEP 413 supports a wide range of options adding code snippets to the javadoc.
Supporting everything would be overkill:

local.zip=94123                # @highlight regex="[0-9]+"
System.out.println("Hello World!");  // @link substring="System.out" target="System#out"
System.out.println("Hello World!");  // @replace regex='".*"' replacement="..."
{@snippet file="ShowOptional.java" region="example"}

I think even a basic support would be a great addition.

a, support for inline @snippet

{@snippet :
  if (v.isPresent()) {
     System.out.println("v: " + v.get());
  }
}

b, support for external @snippet (as-is, without region; both file and class)

 {@snippet file=HelloWorld.java}
 {@snippet class=HelloWorld}
 {@snippet file=config.properties}

c, attributes

class — a class containing the content for the snippet
file — a file containing the content for the snippet
id — an identifier for the snippet, to identify the snippet in the generated documentation
lang — the language or format for the snippet

No support for region

d, indentations

The content of an inline snippet is the text between the newline after the initial colon (:) and the final right curly bracket (}). Incidental white space is removed from the content in the same way as with String.stripIndent. This means you can control the amount of indentation in the generated output by adjusting the indentation of the final right bracket.

Enhanced support for record classes

Implement the features suggested by @xeals in #52:

  • The class docs could be re-applied to the primary constructor, which can be determined by the GENERATED or RECORD flags set on the method (which I think is specified, but I can't find the exact mention in the JVM spec)
  • @param tags from the primary constructor could be applied to the fields and/or methods

Provide RuntimeJavadoc.getJavadoc(Method)

Currently, there is no way to directly get the doc for a method, and this is not a trivial thing to do with the current API, because you have to:

  • get the ClassJavadoc of the declaring class of the method
  • get the list of MethodJavadocs for that class
  • find the doc of the method among this list <= HARD!

The last bit is really not trivial, because the method name is not sufficient to find the matching methods due to overloading, and MethodJavadoc.getSignature() always returns "".

The only way I can think of is to first find methods with matching names, and then try to match parameter names, but this is invalid because overloads are distinguished by parameter types, not names.
Also, parameter names are absent at runtime (unless special compilation flags are used I imagine), so even this almost-working hack wouldn't work.

It would be nice to somehow provide the list of parameter types in the MethodJavadoc in order to allow this kind of method matching.

0.5.0 artifacts missing from Maven Central

It looks like 0.5.0 were not synced between JCenter and Maven Central, because I can only access 0.4.0 on Maven Central, while JCenter has the last version.

It looks like your bintray plugin config in Gradle is set up with disabled sync to Maven Central. It would probably make things easier to deploy if you just activated the sync from there.

Reader throws AssertionError when parsing malformed @see tag

So I found that using an @see tag will fail to match the the linkPattern in the LinkParser class if it contains a period at the end.

This may not necessarily be a bug since I don't believe that a comment type tag should end in a period, though the documentation is somewhat sparse and other tag types do not fail but I'm pointing this out for good measure.

Exception in thread "main" java.lang.AssertionError: SeeAlso not recognized as string literal, HTML link or Javadoc link
	at com.github.therapi.runtimejavadoc.internal.parser.SeeAlsoParser.parseSeeAlso(SeeAlsoParser.java:27)
	at com.github.therapi.runtimejavadoc.internal.parser.JavadocParser.parseMethodJavadoc(JavadocParser.java:66)
	at com.github.therapi.runtimejavadoc.internal.JsonJavadocReader.readMethodDoc(JsonJavadocReader.java:67)
	at com.github.therapi.runtimejavadoc.internal.JsonJavadocReader.readMethodDocs(JsonJavadocReader.java:57)
	at com.github.therapi.runtimejavadoc.internal.JsonJavadocReader.readClassJavadoc(JsonJavadocReader.java:28)
	at com.github.therapi.runtimejavadoc.RuntimeJavadoc.parseJavadocResource(RuntimeJavadoc.java:102)
	at com.github.therapi.runtimejavadoc.RuntimeJavadoc.getJavadoc(RuntimeJavadoc.java:85)
	at com.github.therapi.runtimejavadoc.RuntimeJavadoc.getJavadoc(RuntimeJavadoc.java:37)
	at example.JavadocReader.printClassJavadocClass(JavadocReader.java:16)
	at example.JavadocReader.main(JavadocReader.java:12)
  /**
   * This is a test inner class level javadoc.      // this shouldn't throw an assertion error
   */
  public static class InnerTestClass {

    /**
     * This is a test inner class method level javadoc.
     *
     * @param string a string input.           // this will not throw assertion error
     *
     * @return the length of the string.      // this will not throw assertion error
     */
    public int stringLength(String string) {
      return string.length();
    }

    /**
     * @see InnerTestClass#stringLength(String).      // this WILL throw assertion error
     */
    public void testSeeWithPeriod() {}
  }

Add support for fields' Javadoc

I just realized we couldn't access the Javadoc of a class's fields, or did I just miss it somewhere?
Anyway, I believe this feature would be very useful, and not too hard to add given the existing structure I believe.

Separate the annotation processor from the runtime library

It would be nice to have 2 separate artifacts for the annotation processor used at compile time VS the library used at runtime to access the javadoc.
Gradle 5.0 will disable annotation processor that are on the compile classpath, and thus prevent the use of this library if not split (or force the user to include it twice).

Version 0.11.0 introduced a bug in usage formatting (missing character escapes)

Version 0.11.0 introduces bug.

I'm printing the usage of a command, which works fine up until 0.10.0, but breaks in 0.11.0:

CommandLine.usage(new CommandLine(command).setUsageHelpWidth(textWidth), out, COLOR_SCHEME);

Which results in:

java.util.MissingFormatArgumentException: Format specifier '%s'

image

Please let me know if you need anything else. It's not trivial though to show you how the command is produced in my code, which is all automatic with reflection.

Released versions don't included Javadoc and/or sources jar

It seems Javadoc and/or Sources jars are not included in the release to Maven Central. Because of this, when inspecting classes and methods in IntelliJ, all documentation is missing.

I don't know how it works in Gradle, but in maven the following would solve the issue:

<project>
	<build>
	(..)
		<plugins>
			(..)
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-source-plugin</artifactId>
				<version>3.0.1</version>
				<executions>
					<execution>
						<id>attach-sources</id>
						<goals>
							<goal>jar-no-fork</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-javadoc-plugin</artifactId>
				<version>2.9.1</version>
				<executions>
					<execution>
						<id>attach-javadocs</id>
						<goals>
							<goal>jar</goal>
						</goals>
						<configuration>
							<!--<additionalparam>-Xdoclint:none</additionalparam>-->
							<additionalparam>-Xdoclint:all</additionalparam>
							<additionalparam>-Xdoclint:-missing</additionalparam>
							<show>public</show>
							<nohelp>true</nohelp>
							<excludePackageNames>*.internal.*</excludePackageNames>
						</configuration>
					</execution>
				</executions>
				<configuration>
					<failOnError>false</failOnError>
				</configuration>
			</plugin>
		</plugins>
	</build>

This causes maven to also generate standard jars for javadoc and sources which are automatically included in the deploy plugin. IDE's like IntelliJ look for these for any dependency they download.

Preserve generic type variables and bounds

In the annotation processor we erase all the type parameters so the param types of methods are limited to their bounds which can be seen on the generic method in Documented Class in #63. However the javadoc tool actually preserves the generic type and bounds.

Do we want to preserve the generic type and bounds in the param types of the retained javadoc?

RuntimeJavadoc.getJavadoc(Method) fails if parameter has annotation

I'm on 0.9.0 and since I'm heavily relying on all the api and quirks from that version I'm not ready to upgrade until I'm on Java 8.

However, the following simply stops returning data, Everything works fine when compiled with Java 1.7, but is completely empty when compiled with Java 1.8 (and not just params, but everything):

image

You can easily reproduce this problem as follows:

  1. check out https://github.com/bbottema/simple-java-mail.git (default branch develop)
  2. add the following property to the root pom: <java.version>1.8</java.version>
  3. run mvn clean test (I'm running with Maven 3.5.0 and jdk1.8.0_241)

It fails on the cli-module's unit tests. I get the same error in IntelliJ. Any idea what might cause this?

Provide the fully qualified class name in Link elements

For now, the class name provided in Link elements is taken directly from the Javadoc's text. This is barely usable to actually find the corresponding class/method.
It would be nice to find a way to actually read the corresponding fully qualified class name from the imports, so that we can provide the actual Class<?>/Method object at runtime.

@see on classes appears under other

When a "@see" tag is present on class-level Javadoc, it should be exposed in the ClassJavadoc.getSeeAlso(). Instead, it's returned as an "other" tag.

Related to #43 where we fixed this for everything except ClassJavadoc.

@Code tag doesn't always get reformatted

I noticed when running the formatter over a doc with slightly different code blocks that some appear to get formatted with <code> tags and others do not.

The driver:

import com.github.therapi.runtimejavadoc.ClassJavadoc;
import com.github.therapi.runtimejavadoc.CommentFormatter;
import com.github.therapi.runtimejavadoc.MethodJavadoc;
import com.github.therapi.runtimejavadoc.RuntimeJavadoc;

public class Driver {

  public static void main(String[] args) {
    ClassJavadoc javadoc = RuntimeJavadoc.getJavadoc(Test.class);
    MethodJavadoc methodJavadoc = javadoc.getMethods().get(0);
    String format = new CommentFormatter().format(methodJavadoc.getComment());
    System.out.println(format);
  }
}

The Test file:

public class Test {

  /**
   * <pre>{@code
   *    <Class>
   *         <Load>ask</Load>
   *         <ConstructArg>
   *            <ArgName>facilities</ArgName>
   *            <ArgType>java.lang.String</ArgType>
   *            <ArgValue>ZDC,ZOB,ZNY</ArgValue>
   *         </ConstructArg>
   *     </Class>
   * }</pre>
   *
   * <pre>{@code
   * echo 'net.ipv4.igmp_max_memberships=1024' > /usr/lib/sysctl.d/51-adsb.conf
   * }</pre>
   */
  public void testMethod() {}
}

The output:

<pre>{@code
    <Class>
         <Load>ask</Load>
         <ConstructArg>
            <ArgName>facilities</ArgName>
            <ArgType>java.lang.String</ArgType>
            <ArgValue>ZDC,ZOB,ZNY</ArgValue>
         </ConstructArg>
     </Class>
 }</pre>

 <pre><code>echo 'net.ipv4.igmp_max_memberships=1024' &gt; /usr/lib/sysctl.d/51-adsb.conf
 </code></pre>

Can't get Javadoc for nested class in default package

Inner classes in the default package as the JavaReader fails to the return a valid comment from the javadoc.

Attaching a stand alone example

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.example</groupId>
  <artifactId>JavadocRuntimeReader</artifactId>
  <version>1.0-SNAPSHOT</version>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.1</version>
        <configuration>
          <source>8</source>
          <target>8</target>
          <annotationProcessorPaths>
            <annotationProcessorPath>
              <groupId>com.github.therapi</groupId>
              <artifactId>therapi-runtime-javadoc-scribe</artifactId>
              <version>0.9.0</version>
            </annotationProcessorPath>
          </annotationProcessorPaths>
        </configuration>

      </plugin>
    </plugins>
  </build>
  <dependencies>
    <!-- Annotation processor -->
<!--    <dependency>-->
<!--      <groupId>com.github.therapi</groupId>-->
<!--      <artifactId>therapi-runtime-javadoc-scribe</artifactId>-->
<!--      <version>0.9.0</version>-->
<!--      <scope>provided</scope>-->
<!--    </dependency>-->

    <!-- Runtime library -->
    <dependency>
      <groupId>com.github.therapi</groupId>
      <artifactId>therapi-runtime-javadoc</artifactId>
      <version>0.9.0</version>
    </dependency>
  </dependencies>
</project>

Example class reader

import com.github.therapi.runtimejavadoc.ClassJavadoc;
import com.github.therapi.runtimejavadoc.CommentFormatter;
import com.github.therapi.runtimejavadoc.MethodJavadoc;
import com.github.therapi.runtimejavadoc.RuntimeJavadoc;

public class JavadocReader {
  private static final CommentFormatter FORMATTER = new CommentFormatter();

  public static void main(String[] args) {
    printClassJavadocClass(TestClass.class);
  }

  private static void printClassJavadocClass(Class<?> clazz) {
    ClassJavadoc classDoc = RuntimeJavadoc.getJavadoc(clazz);
    if (classDoc.isEmpty()) {
      System.out.println("Failed to return javadoc");
      return;
    }
    System.out.println(FORMATTER.format(classDoc.getComment()));
    StringBuilder sb = new StringBuilder();
    for (MethodJavadoc methodDoc : classDoc.getMethods()) {
      sb.append(methodDoc.getName())
          .append(methodDoc.getParamTypes())
          .append(FORMATTER.format(methodDoc.getComment()))
          .append("  returns ")
          .append(FORMATTER.format(methodDoc.getReturns()))
          .append(System.lineSeparator());
    }
    System.out.println("\t" + sb.toString());
  }

  /**
   * This is a test class level javadoc.
   */
  static class TestClass {

    /**
     * This is a test method level javadoc.
     */
    public void testMethod() {}
  }
}

Originally posted by @jhameier in #34 (comment)

Allow the use of a package whitelist instead of annotating on each class

Annotating every class with @RetainJavadoc can be really cumbersome depending on the use case, especially when there are a lot of classes involved.

In particular, it is impractical when we want to keep the Javadoc for all classes in a package because of the semantics of the package, and not of each individual class (e.g. model classes in the model package). If we often create new classes there, we need to remember to add the annotation each time.

It would be nice to be able to provide a way to use a package whitelist (maybe via a resource file) in addition to the annotation mechanism. If the class is in a white-listed package OR is annotated with @RetainJavadoc, then we keep the Javadoc.

The processor could, for instance, read a resource file with a specific name like /runtime-javadoc/package-whitelist.txt, which would contain a list of package prefixes. Then we could add features like the use of wildcards etc, but even a plain list of package prefixes would be great.

I could help if you're interested, what do you think?

Parameter lists in @Link are not parsed properly

Parameter lists (ie {@link ClassName#someMethod(String, Integer) label}), are not parsed properly, resulting in a member of "someMethod(String, " and a label of ", Integer) label" or sometinhg similar.

Member parameter lists should be parsed properly. At the same time, it would be good if the parameter list was stored on Link as an array instead of a single string.

Add links and tags elements to Comment

It looks like the Comment and CommentFormatter classes have been designed to support the multiple elements we can find in javadoc comments.
However, all I can find is a single CommentText node containing the whole Javadoc comment.

It would be nice to finish this feature so that users can make use of the CommentFormatter.

Retain only javadoc from classes that have the @RetainJavadoc or some other annotation

So things have been working fairly well and of course like most development work there is feature creep. I've been asked to run the javadoc reader as a maven plugin. I thought okay shouldn't be that big of a deal, moved the reader and markdown generation code to a new project and included the primary jar with the have the generated json files). So far so good.

Then I realized that I'm getting a json file for every class within the primary jar. With 6000+ classes at 2K each that is quite a bit more data that is not really needed in our jar at runtime since the document is getting created and that is what I need not the javadoc itself. Yea I know its an edge case.

What I really need is a way to specify only the classes that are either marked with the @RetainJavadcoc (which is currently about 100 classes in dozens of packages) or a way to specify a different Annotation to pass to a filter for the annotation processor to use. It doesn't seem right to pass it to the PackageFilter as the name implies its to filter packages.

Looking through the code I see that if I use the -A when compiling that I can specify specific packages but by default it includes everything.

  1. Is there a way to specify NO packages (this way at worse case I add the @RetainJavadoc annotation to the classes I want to retain.

  2. Is there a way (or could there be) a way to specify different annotations for retention (that would allow me to use existing annotations as a kind of filter for which classes I would generate for). This one is a long shot but have to ask anyway.

Thanks in advance!

Constructor javadoc is missing when there is no class level java doc

During testing, I noticed that I could retrieve the constructor java docs for

/**
 * abc
 */
public static class A {
    /**
     * Lorem ipsum dolor sit amet, consectetur adipiscing elit.
     */
    public A() {}
}

but not for

public static class A {
    /**
     * Lorem ipsum dolor sit amet, consectetur adipiscing elit.
     */
    public A() {}
}

The only difference in the two classes was whether they had javadocs at the class level. Running a debugger I can see that within RuntimeJavadoc.getJavadoc(Constructor); ClassJavadoc.getConstructors() returns an empty list.

While it is unusual for a constructor to have documentation and the class to not, it can still happen.

The problem appears to be located here, notice that it looks like the constructor check is .isArray() and will always return true.

if (isBlank(classDoc) && fieldDocs.isEmpty() && enumConstantDocs.isEmpty() && methodDocs.isEmpty() && constructorDocs.isArray()) {

I just thought you should know

I just thought you should know that I've just released Simple Java Mail 6.0.0-rc1, which includes CLI support based on your library. How? Because Simple Java Mail generates CLI options (using the excellent picocli) using the embedded Javadoc as usage documentation!

Pretty sweet right, I have my builder api and respective documentation in one place and it's exactly the same code compared to using just the Java api.

I couldn't have done it without your excellent library (and your cooperation when I backported it to JDK7+), so a big thank you to you!

Why the shadow plugin?

It looks like the purpose of the shadow plugin is to build a fat jar. I believe this is only desirable when packaging an end-user application that needs runtime dependencies.
A library, on the other hand, is used within a build system, and its dependencies will be fetched via standard transitive deps resolution.

Is there a particular reason why you're using this plugin for your lib?

Don't duplicate minimal-json classes

minimal-json gets bundled into both the runtime library and the annotation processor.

In both cases, it's relocated to the same package. This leads to duplicate classes on the class path, which is no good.

See if the annotation processor can just use the version in the runtime library. If we can't make that work, then relocate to different locations.

@see on fields appears under other

For classes, methods, and constructors the @see javadoc tag gets separated out into BaseJavadoc.seeAlso; however with fields it gets left in 'other' and 'seeAlso' remains empty.

error: module not found: therapi.runtime.javadoc

As titled, I'm trying to get therapi-runtime-javadoc working in a Gradle multiproject with JPMS

The problematic module is scijava-discovery-therapi

I added the dependencies as shown on the readme

    // Annotation processor (prior to Gradle 4.6, use `compileOnly` instead)
    annotationProcessor("com.github.therapi:therapi-runtime-javadoc-scribe:0.12.0")

    // Runtime library
    implementation("com.github.therapi:therapi-runtime-javadoc:0.12.0")

But at sync I keep getting

/home/elect/IdeaProjects/incubator/scijava/scijava-discovery-therapi/src/main/java/module-info.java:8: error: module not found: therapi.runtime.javadoc
requires therapi.runtime.javadoc;

The module-info.java is the following

module org.scijava.discovery.therapi {

	exports org.scijava.discovery.therapi;
	opens org.scijava.discovery.therapi to therapi.runtime.javadoc;

	requires org.scijava.discovery;
	requires transitive org.scijava.parse2;
	requires therapi.runtime.javadoc; // this is the problematic line
}

If I click on the therapi.runtime.javadoc I do end up in the right dependency

Screenshot from 2021-11-07 10-27-29

All the Default packages have annotation processing enable as follow

Screenshot from 2021-11-07 10-28-52

While the Gradle imported has a custom one:

Screenshot from 2021-11-07 10-29-46

Which I think is fine, but I still cant understand why it cannot find this module..

@throws never parsed as ThrowsJavadoc

MethodJavadoc constructor always received empty lists of "exceptions" and "seeAlso"

please complete
com.github.therapi.runtimejavadoc.internal.parser.JavadocParser#parseMethodJavadoc
method or give a way to substitute with custom implementation

thanx

Link therapi-runtime-javadoc-scribe to JCenter

I see that the new artifact for the annotation processor is not linked to JCenter. Just pointing that out in case you didn't already request the inclusion.
Thanks a lot for the very quick response regarding the artifact separation by the way!

Link misses information to find class types

I'm trying to locate the actual Method object referenced by the Link.

Is it possible when creating Link objects to include the package relevant to the classname being referenced? Either the package is included in the class name itself, or the package comes from an import. It would take some trickery for sure, but the information could be very useful in runtime.

public class Link {
    private final String label;
    private final String referencedPackage;
    private final String referencedClassName;
    private final String referencedMemberName;

    (..)
}

Alternatively, you could add a list of all imports to ClassJavadoc so I can match it later manually. I imagine this to be a lot easier to implement in the short term.

public class ClassJavadoc extends BaseJavadoc {

    private final List<Import> imports;
    private final List<FieldJavadoc> fields;
    private final List<FieldJavadoc> enumConstants;
    private final List<MethodJavadoc> methods;

    (..)
}

IllegalArgumentException when getting Javadoc for nested class that has no Javadoc

Affected version: 0.14.0

Class `javasource.foo.DocumentedClass.NestedWithoutJavadoc` does not match class doc for `javasource.foo.DocumentedClass$NestedWithoutJavadoc`
java.lang.IllegalArgumentException: Class `javasource.foo.DocumentedClass.NestedWithoutJavadoc` does not match class doc for `javasource.foo.DocumentedClass$NestedWithoutJavadoc`
	at com.github.therapi.runtimejavadoc.ClassJavadoc.createEnhancedClassJavadoc(ClassJavadoc.java:102)
	at com.github.therapi.runtimejavadoc.RuntimeJavadoc.getJavadoc(RuntimeJavadoc.java:55)
        ...

Error while creating ClassJavadoc - with class constructors

Hello @dnault
I am running into this error below. It parses my class and parses it into json the docs, methods, even enums, but the input stream does not read in my constructors which causes this error. Would it be possible to modify the readMethodDocs function to ignore if the methods JsonValue methodsValue == null or something like that?

java.lang.NullPointerException
	at com.github.therapi.runtimejavadoc.internal.JsonJavadocReader.readMethodDocs(JsonJavadocReader.java:56)
	at com.github.therapi.runtimejavadoc.internal.JsonJavadocReader.readClassJavadoc(JsonJavadocReader.java:30)
	at com.github.therapi.runtimejavadoc.RuntimeJavadoc.parseJavadocResource(RuntimeJavadoc.java:103)
	at com.github.therapi.runtimejavadoc.RuntimeJavadoc.getJavadoc(RuntimeJavadoc.java:86)
	at com.github.therapi.runtimejavadoc.RuntimeJavadoc.getJavadoc(RuntimeJavadoc.java:38)
	at org.web.util.JavadocUtil.printJavadoc(JavadocUtil.java:20)
	at org.web.util.JavadocUtilTest.testJavaDoc(JavadocUtilTest.java:13)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:675)
	at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:125)
	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:132)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:124)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:74)
	at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:104)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:62)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:43)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:35)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:202)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:198)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:135)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
	at java.util.ArrayList.forEach(ArrayList.java:1257)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
	at java.util.ArrayList.forEach(ArrayList.java:1257)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:248)
	at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$5(DefaultLauncher.java:211)
	at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:226)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:199)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:132)
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:220)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53)

NullPointerException in RuntimeJavadoc due to null ClassLoader

Here is the stacktrace I got when using Livedoc v4.3.2 which uses therapi-runtime-javadoc 0.4.0:

java.lang.NullPointerException: null
        at com.github.therapi.runtimejavadoc.RuntimeJavadoc.getJavadoc(RuntimeJavadoc.java:41) ~[therapi-runtime-javadoc-0.4.0.jar:na]
        at com.github.therapi.runtimejavadoc.RuntimeJavadoc.getJavadoc(RuntimeJavadoc.java:32) ~[therapi-runtime-javadoc-0.4.0.jar:na]
        at com.github.therapi.runtimejavadoc.RuntimeJavadoc.getJavadoc(RuntimeJavadoc.java:75) ~[therapi-runtime-javadoc-0.4.0.jar:na]

It looks like RuntimeJavadoc crashes at line 41:

try (InputStream is = classLoader.getResourceAsStream(resourceName)) {

My bet is that the classloader is null, which is possible as the doc states:

Returns the class loader for the class. Some implementations may use
null to represent the bootstrap class loader. This method will return
null in such implementations if this class was loaded by the bootstrap
class loader.

One solution would be to directly use the getResourceAsStream() method on the class itself rather than on its ClassLoader. I understand that the getJavadoc(String, ClassLoader) overload is needed for tests, but it should be easy to just extract the code properly to maximize code reuse while avoiding using the classloader overload in production code.

Add Javadoc from overridden method if none exists

Currently if a method exists with no javadoc that overrides a method in a base class that has javadoc no java doc is returned when specifying the overriding method.

It would be nice if the overriden method inherited the javadoc from the base method when none exists on itself. As this is the behavior of the javadoc tools provided by oracle.

Make this available in Java 7?

Hi @dnault,

What an innovative and interesting way of including Javadoc in runtime! Reminds me of Lombok.

I would love to use this library in my own open source library Simple Java Mail, but I'm restricted to Java 7 and your library is out of reach because of that. Is it possible to make this library available to Java 7? I know what a pain it is to not be able to use Java 8 for my own library, but since Java 7 is still is used by a significant audience I have no choice if I want to service them.

I would love to try and make this library work for my own use case, which is that I'm using Java reflection to generate CLI support and I would like to use therapi-runtime-javadoc to dynamically include the Javadoc as documentation. Otherwise I would have to maintain the documentation both in Javadoc as well as annotations. You library would reach a lot of people if I could use it somehow.

Support record classes in annotation processor

Record classes are unmodifiable data class introduced in Java 16 and included in the recent LTS version Java 17. Since records are a new syntax for Java, they generate an ElementKind.RECORD AST element instead of ElementKind.CLASS and are not supported by the current visitor.

Javadoc for a record is the same as a regular class, except it may include @param fields referring to record components:

/**
 * Example class.
 *
 * @param a first component input
 * @param b second input
 */
public class Foo(boolean a, String b) {

  /** Alternate constructor */
  public Foo(boolean a) {
    this(a, null);
  }
}

General thoughts:

  • As best as I can tell, the compiler doesn't attach any docs to the generated fields or methods, or to the primary constructor
  • There's no way to directly comment the record components

Depending on how an implementation might balance representation vs. intent:

  • The class docs could be re-applied to the primary constructor, which can be determined by the GENERATED or RECORD flags set on the method (which I think is specified, but I can't find the exact mention in the JVM spec)
  • @param tags from the primary constructor could be applied to the fields and/or methods

No javadoc created from constructors.

Found that there is no way to pull the javadoc from a constructor.

Test Class:

/**
 * This is the class level javadoc.
 */
public class TestClass {

  /**
   * This is the ctor javadoc.
   */
  public TestClass() {}

  /**
   * This is the method javadoc.
   */
  public void testMethod() {}
}

Driver:

import com.github.therapi.runtimejavadoc.ClassJavadoc;
import com.github.therapi.runtimejavadoc.RuntimeJavadoc;

public class Test {
  public static void main(String[] args) {
    ClassJavadoc classJavadoc = RuntimeJavadoc.getJavadoc(TestClass.class);
    System.out.println(classJavadoc);
  }
}

Output

ClassJavadoc {
   name='TestClass', 
   comment=This is the class level javadoc., 
   fields=[], 
   methods=[MethodJavadoc {
                        name='testMethod', 
                        paramTypes='[]', 
                        comment=This is the method javadoc., 
                        params=[], 
                        exceptions=[],
                        other=[], 
                        returns=, 
                        seeAlso=[]
                   }], 
   seeAlso=[], 
   other=[]
}

@see (seeAlso) not implemented for Methods?

I went through the code quickly, but is my understanding correct that @see parsing is not implemented for Method Javadoc? In runtime I do see the tag under other with name "see" and value CommentText rather than InlineLink.

image

This is unfortunate, since the rules for @see works exactly the same as @link except it can also be string literal or an HTML link (<a href>).

Comment elements should have a reference to the previous element

Currently it is impossible to perform context-based formatting, because while formatting a CommentElement, we don't have access to the entire comment structure. For example, in formatLink(..), I would like to perform different kind of formatting based on the preceding CommentElement, which is now impossible.

This can be solved in two ways:

  1. Add a field in CommentElement: private final CommentElement previousCommentElement; which is passed in constructor.
  2. Add the list of comment elements plus current index to formatLink(..) and all other formatting methods so you have the information needed.

Personally, I find the first solution the cleanest. Only the constructor call is expanded as opposed to expanding all the formatting methods. And 3rd parties creating a custom CommentFormatter can decide where to use this new API if at all.

If you agree this would be a useful addition, please let me know which approach you prefer and I'll get it sorted.

Require Java 1.8 or later

@bbottema I'd like to drop support for Java 1.7 so we can take advantage of Gradle toolchains and bump a couple of dependency versions. Are you ready for this?

Each time i try to get java doc , It returns Empty java doc, I am using this Code

`package com.ps.apps.utility.docgenerator;

import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import com.github.therapi.runtimejavadoc.ClassJavadoc;
import com.github.therapi.runtimejavadoc.CommentFormatter;
import com.github.therapi.runtimejavadoc.MethodJavadoc;
import com.github.therapi.runtimejavadoc.OtherJavadoc;
import com.github.therapi.runtimejavadoc.RuntimeJavadoc;
import com.github.therapi.runtimejavadoc.SeeAlsoJavadoc;
import com.github.therapi.runtimejavadoc.ThrowsJavadoc;
import com.github.therapi.runtimejavadoc.*;
import com.github.therapi.runtimejavadoc.ParamJavadoc;

public class DocExtractorUtil {
// formatters are reusable and thread-safe
private static final CommentFormatter formatter = new CommentFormatter();

public static DocumentationHolder getDocumentation(String fullyQualifiedClassName) throws IOException {
	DocumentationHolder documentationHolder = new DocumentationHolder();
    ClassJavadoc classDoc = RuntimeJavadoc.getJavadoc(fullyQualifiedClassName);
    documentationHolder.setClassName(classDoc.getName());
    documentationHolder.setClassDocumenation(format(classDoc.getComment()));

                            
	List<String> classTags = Collections.emptyList();
    // @see tags
    for (SeeAlsoJavadoc see : classDoc.getSeeAlso()) {
    	classTags.add("See also: " + see.getLink());
    }
    
    documentationHolder.setTags(classTags);
    
	Map<String, String> classMiscellaneousJavadoc = Collections.emptyMap();

    // miscellaneous and custom javadoc tags (@author, etc.)
    for (OtherJavadoc other : classDoc.getOther()) {
    	classMiscellaneousJavadoc.put(other.getName() , format(other.getComment()));
    }
    documentationHolder.setMiscellaneousJavadoc(classMiscellaneousJavadoc);
    
	List<MethodDocumentations> methods = Collections.emptyList();	

    for (MethodJavadoc methodDoc : classDoc.getMethods()) {
    	MethodDocumentations methodDocumentations = new MethodDocumentations();
    	methodDocumentations.setName(methodDoc.getName());
    	methodDocumentations.setParamTypes(methodDoc.getParamTypes());
    	methodDocumentations.setComment(format(methodDoc.getComment()));
    	methodDocumentations.setReturnType(format(methodDoc.getReturns()));
    	List<String> tags = Collections.emptyList();
        for (SeeAlsoJavadoc see : methodDoc.getSeeAlso()) {
        	tags.add("  See also: " + see.getLink());
        }            
        methodDocumentations.setTags(tags);
        
    	Map<String, String> miscellaneousJavadoc = Collections.emptyMap();
        for (OtherJavadoc other : methodDoc.getOther()) {
        	miscellaneousJavadoc.put(other.getName(), format(other.getComment()));
        }
        methodDocumentations.setMiscellaneousJavadoc(miscellaneousJavadoc);
        
    	Map<String, String> paramJavaDoc = Collections.emptyMap();
        for (ParamJavadoc paramDoc : methodDoc.getParams()) {
        	paramJavaDoc.put(paramDoc.getName(),  format(paramDoc.getComment()));
        }           
        methodDocumentations.setParams(paramJavaDoc);
        
        
        Map<String, String> throwsDocMap = Collections.emptyMap();
        
        for (ThrowsJavadoc throwsDoc : methodDoc.getThrows()) {
        	paramJavaDoc.put(throwsDoc.getName(),  format(throwsDoc.getComment()));
        }
        methodDocumentations.setThrowsDoc(throwsDocMap);
        
        methods.add(methodDocumentations);
    }
    documentationHolder.setMethods(methods);
    return documentationHolder;
}

private static String format(Comment c) {
    return formatter.format(c);
}

}`

I debugged the internal code and seems like i am missing "__Javadoc.json" file which supposed to be genrated on it's own or do i have to perform any specific task ? I am using maven. I do understand that 'therapi-runtime-javadoc-scribe' is used for baking docs but it's not working?

I want to know, If i should configure something in pom.xml or do i need to use any annotation on class that need bake _Javadoc.json file

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.