Giter Site home page Giter Site logo

joffrey-bion / livedoc Goto Github PK

View Code? Open in Web Editor NEW
3.0 0.0 2.0 1.66 MB

A not-so-annotation-based documentation generator for REST and websocket services

License: MIT License

Java 84.65% CSS 0.28% JavaScript 13.44% HTML 0.39% FreeMarker 0.15% Dockerfile 0.10% Shell 0.02% Kotlin 0.96%

livedoc's Introduction

Livedoc

Maven central version Github Build GitHub license

Livedoc is a documentation generator for REST and websocket services, inspired by the JSONDoc project.

Livedoc tries to read all the doc from the code and the Javadoc. Annotations are considered a failure of Livedoc to grasp an aspect of the code. They should mostly be used to add what Livedoc couldn't read from the code, or override a piece of documentation that does not match the user's needs.

This is one of the reasons why it should be quick to add Livedoc to your project.

Get started

Check out the official documentation to get started with Livedoc.

Livedoc UI Demo

Try it yourself! Run the demo:

docker run -p 8080:8080 docker.io/hildan/livedoc-demo:latest

Then navigate to http://localhost:8080/livedoc/index.html to see what it looks like. You can see the code directly in this Github repository as the sample-app subproject.

Credits

Credits to @fabiomaffioletti for his great work on the original JSONDoc project, and to all contributors that helped him build JSONDoc up to version 1.2.17, which I started from.

Special thanks to @ST-DDT for his very constructive feedback, both on the original project and on Livedoc.

Livedoc uses the therapi-runtime-javadoc library by @dnault for its Javadoc-related processing.

License

This library is released under the MIT license.

livedoc's People

Contributors

dependabot[bot] avatar joffrey-bion avatar mebubo avatar

Stargazers

 avatar  avatar  avatar

livedoc's Issues

Move annotations to own jar/lib

It would be nice if you could move the annotation to their own jar/lib.

Because we also have a separate jar for the dto classes, it is bothersome to add the core package as dependency and exclude all of its dependencies.

Annotations are optional thus it is not necessary to be present on the classpath during runtime.

deps dot

Broken playground

No playground displayed, even when turned on, and this error appears in the console:

handlebars.min.js:27 Uncaught Error: Parse error on line 9:
...y:none;" {{        /compare}}>        
----------------------^
Expecting 'ID', 'DATA', got 'SEP'
    at a.parseError (handlebars.min.js:27)
    at a.parse (handlebars.min.js:27)
    at c.e [as parse] (handlebars.min.js:27)
    at d (handlebars.min.js:27)
    at f (handlebars.min.js:27)
    at HTMLAnchorElement.<anonymous> (livedoc-ui.html?url=http://localhost:8080/jsondoc:1116)
    at HTMLAnchorElement.dispatch (jquery.js:4641)
    at HTMLAnchorElement.r.handle (jquery.js:4309)

NoClassDefFoundError: org/springframework/messaging/MessageHeaders

The issue

I'm using the latest version of livedoc, but I get a NoClassDefFoundError when i try to run the application.

<dependency>
    <groupId>org.hildan.livedoc</groupId>
    <artifactId>livedoc-springmvc</artifactId>
    <version>2.1.1</version>
</dependency>

Related: #36

Stacktrace

org.springframework.web.util.NestedServletException: Handler dispatch failed; nested exception is java.lang.NoClassDefFoundError: org/springframework/messaging/MessageHeaders
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:982) [spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901) [spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) [spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861) [spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:635) [servlet-api.jar:?]
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) [spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) [servlet-api.jar:?]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) [catalina.jar:8.5.15]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [catalina.jar:8.5.15]
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) [tomcat-websocket.jar:8.5.15]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [catalina.jar:8.5.15]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [catalina.jar:8.5.15]
	at org.springframework.web.filter.AbstractRequestLoggingFilter.doFilterInternal(AbstractRequestLoggingFilter.java:244) [spring-web-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [catalina.jar:8.5.15]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [catalina.jar:8.5.15]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:317) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346) [spring-web-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262) [spring-web-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [catalina.jar:8.5.15]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [catalina.jar:8.5.15]
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) [catalina.jar:8.5.15]
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [catalina.jar:8.5.15]
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478) [catalina.jar:8.5.15]
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [catalina.jar:8.5.15]
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80) [catalina.jar:8.5.15]
	at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:624) [catalina.jar:8.5.15]
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [catalina.jar:8.5.15]
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) [catalina.jar:8.5.15]
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799) [tomcat-coyote.jar:8.5.15]
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-coyote.jar:8.5.15]
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861) [tomcat-coyote.jar:8.5.15]
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1455) [tomcat-coyote.jar:8.5.15]
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-coyote.jar:8.5.15]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:1.8.0_144]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:1.8.0_144]
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-util.jar:8.5.15]
	at java.lang.Thread.run(Thread.java:748) [?:1.8.0_144]
Caused by: java.lang.NoClassDefFoundError: org/springframework/messaging/MessageHeaders
	at org.hildan.livedoc.springmvc.scanner.builder.SpringRequestBodyBuilder.<clinit>(SpringRequestBodyBuilder.java:28) ~[livedoc-springmvc-2.1.1.jar:?]
	at org.hildan.livedoc.springmvc.SpringDocReader.buildApiMethodDoc(SpringDocReader.java:91) ~[livedoc-springmvc-2.1.1.jar:?]
	at org.hildan.livedoc.springmvc.SpringDocReader.buildApiMethodDoc(SpringDocReader.java:65) ~[livedoc-springmvc-2.1.1.jar:?]
	at org.hildan.livedoc.core.LivedocReader.lambda$readApiMethodDoc$7(LivedocReader.java:172) ~[livedoc-core-2.1.1.jar:?]
	at org.hildan.livedoc.core.LivedocReader.readFromAllReadersAndMerge(LivedocReader.java:199) ~[livedoc-core-2.1.1.jar:?]
	at org.hildan.livedoc.core.LivedocReader.readApiMethodDoc(LivedocReader.java:171) ~[livedoc-core-2.1.1.jar:?]
	at org.hildan.livedoc.core.LivedocReader.lambda$readApiMethodDocs$6(LivedocReader.java:155) ~[livedoc-core-2.1.1.jar:?]
	at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193) ~[?:1.8.0_144]
	at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1374) ~[?:1.8.0_144]
	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481) ~[?:1.8.0_144]
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) ~[?:1.8.0_144]
	at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708) ~[?:1.8.0_144]
	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[?:1.8.0_144]
	at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499) ~[?:1.8.0_144]
	at org.hildan.livedoc.core.LivedocReader.buildDocs(LivedocReader.java:193) ~[livedoc-core-2.1.1.jar:?]
	at org.hildan.livedoc.core.LivedocReader.readApiMethodDocs(LivedocReader.java:155) ~[livedoc-core-2.1.1.jar:?]
	at org.hildan.livedoc.core.LivedocReader.lambda$readApiDoc$5(LivedocReader.java:150) ~[livedoc-core-2.1.1.jar:?]
	at java.util.Optional.ifPresent(Optional.java:159) ~[?:1.8.0_144]
	at org.hildan.livedoc.core.LivedocReader.readApiDoc(LivedocReader.java:150) ~[livedoc-core-2.1.1.jar:?]
	at org.hildan.livedoc.core.LivedocReader.lambda$readApiDocs$3(LivedocReader.java:145) ~[livedoc-core-2.1.1.jar:?]
	at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193) ~[?:1.8.0_144]
	at java.util.HashMap$KeySpliterator.forEachRemaining(HashMap.java:1548) ~[?:1.8.0_144]
	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481) ~[?:1.8.0_144]
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) ~[?:1.8.0_144]
	at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708) ~[?:1.8.0_144]
	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[?:1.8.0_144]
	at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499) ~[?:1.8.0_144]
	at org.hildan.livedoc.core.LivedocReader.buildDocs(LivedocReader.java:193) ~[livedoc-core-2.1.1.jar:?]
	at org.hildan.livedoc.core.LivedocReader.readApiDocs(LivedocReader.java:145) ~[livedoc-core-2.1.1.jar:?]
	at org.hildan.livedoc.core.LivedocReader.read(LivedocReader.java:84) ~[livedoc-core-2.1.1.jar:?]
	at org.hildan.livedoc.springmvc.controller.JsonLivedocController.getApi(JsonLivedocController.java:62) ~[livedoc-springmvc-2.1.1.jar:?]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_144]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_144]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_144]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_144]
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133) ~[spring-web-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97) ~[spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827) ~[spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738) ~[spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) ~[spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967) [spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	... 62 more
Caused by: java.lang.ClassNotFoundException: org.springframework.messaging.MessageHeaders
	at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1285) ~[catalina.jar:8.5.15]
	at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1119) ~[catalina.jar:8.5.15]
	at org.hildan.livedoc.springmvc.scanner.builder.SpringRequestBodyBuilder.<clinit>(SpringRequestBodyBuilder.java:28) ~[livedoc-springmvc-2.1.1.jar:?]
	at org.hildan.livedoc.springmvc.SpringDocReader.buildApiMethodDoc(SpringDocReader.java:91) ~[livedoc-springmvc-2.1.1.jar:?]
	at org.hildan.livedoc.springmvc.SpringDocReader.buildApiMethodDoc(SpringDocReader.java:65) ~[livedoc-springmvc-2.1.1.jar:?]
	at org.hildan.livedoc.core.LivedocReader.lambda$readApiMethodDoc$7(LivedocReader.java:172) ~[livedoc-core-2.1.1.jar:?]
	at org.hildan.livedoc.core.LivedocReader.readFromAllReadersAndMerge(LivedocReader.java:199) ~[livedoc-core-2.1.1.jar:?]
	at org.hildan.livedoc.core.LivedocReader.readApiMethodDoc(LivedocReader.java:171) ~[livedoc-core-2.1.1.jar:?]
	at org.hildan.livedoc.core.LivedocReader.lambda$readApiMethodDocs$6(LivedocReader.java:155) ~[livedoc-core-2.1.1.jar:?]
	at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193) ~[?:1.8.0_144]
	at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1374) ~[?:1.8.0_144]
	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481) ~[?:1.8.0_144]
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) ~[?:1.8.0_144]
	at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708) ~[?:1.8.0_144]
	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[?:1.8.0_144]
	at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499) ~[?:1.8.0_144]
	at org.hildan.livedoc.core.LivedocReader.buildDocs(LivedocReader.java:193) ~[livedoc-core-2.1.1.jar:?]
	at org.hildan.livedoc.core.LivedocReader.readApiMethodDocs(LivedocReader.java:155) ~[livedoc-core-2.1.1.jar:?]
	at org.hildan.livedoc.core.LivedocReader.lambda$readApiDoc$5(LivedocReader.java:150) ~[livedoc-core-2.1.1.jar:?]
	at java.util.Optional.ifPresent(Optional.java:159) ~[?:1.8.0_144]
	at org.hildan.livedoc.core.LivedocReader.readApiDoc(LivedocReader.java:150) ~[livedoc-core-2.1.1.jar:?]
	at org.hildan.livedoc.core.LivedocReader.lambda$readApiDocs$3(LivedocReader.java:145) ~[livedoc-core-2.1.1.jar:?]
	at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193) ~[?:1.8.0_144]
	at java.util.HashMap$KeySpliterator.forEachRemaining(HashMap.java:1548) ~[?:1.8.0_144]
	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481) ~[?:1.8.0_144]
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) ~[?:1.8.0_144]
	at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708) ~[?:1.8.0_144]
	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[?:1.8.0_144]
	at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499) ~[?:1.8.0_144]
	at org.hildan.livedoc.core.LivedocReader.buildDocs(LivedocReader.java:193) ~[livedoc-core-2.1.1.jar:?]
	at org.hildan.livedoc.core.LivedocReader.readApiDocs(LivedocReader.java:145) ~[livedoc-core-2.1.1.jar:?]
	at org.hildan.livedoc.core.LivedocReader.read(LivedocReader.java:84) ~[livedoc-core-2.1.1.jar:?]
	at org.hildan.livedoc.springmvc.controller.JsonLivedocController.getApi(JsonLivedocController.java:62) ~[livedoc-springmvc-2.1.1.jar:?]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_144]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_144]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_144]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_144]
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133) ~[spring-web-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97) ~[spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827) ~[spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738) ~[spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) ~[spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967) [spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	... 62 more

Complicated enum templates

For enum types, we get additional reflective information in the template (see below), which is not desired.
We should probably not display any template at all for enums.

{
  "declaringClass": {
    "name": "",
    "enumConstants": [],
    "protectionDomain": {
      "principals": [],
      "permissions": {
        "readOnly": true
      },
      "classLoader": {},
      "codeSource": {
        "location": {
          "protocol": "",
          "host": "",
          "port": 0,
          "file": "",
          "query": "",
          "authority": "",
          "path": "",
          "userInfo": "",
          "ref": "",
          "content": {},
          "defaultPort": 0
        },
        "certificates": [],
        "codeSigners": []
      }
    },
    "modifiers": 0,
    "interface": true,
    "array": true,
    "primitive": true,
    "annotatedInterfaces": [],
    "annotatedSuperclass": {
      "type": {
        "typeName": ""
      },
      "annotations": [],
      "declaredAnnotations": []
    },
    "annotations": [],
    "canonicalName": "",
    "classLoader": {},
    "classes": [],
    "constructors": [],
    "declaredAnnotations": [],
    "declaredClasses": [],
    "declaredConstructors": [],
    "declaredFields": [],
    "declaredMethods": [],
    "enclosingConstructor": {
      "parameters": [],
      "declaredAnnotations": [],
      "parameterTypes": [],
      "exceptionTypes": [],
      "modifiers": 0,
      "annotations": [],
      "parameterAnnotations": [],
      "name": "",
      "typeParameters": [],
      "synthetic": true,
      "parameterCount": 0,
      "varArgs": true,
      "annotatedReturnType": {
        "type": {
          "typeName": ""
        },
        "annotations": [],
        "declaredAnnotations": []
      },
      "genericExceptionTypes": [],
      "genericParameterTypes": [],
      "annotatedReceiverType": {
        "type": {
          "typeName": ""
        },
        "annotations": [],
        "declaredAnnotations": []
      },
      "annotatedParameterTypes": [],
      "annotatedExceptionTypes": [],
      "accessible": true
    },
    "enclosingMethod": {
      "parameters": [],
      "declaredAnnotations": [],
      "name": "",
      "parameterTypes": [],
      "exceptionTypes": [],
      "modifiers": 0,
      "annotations": [],
      "parameterAnnotations": [],
      "typeParameters": [],
      "default": true,
      "synthetic": true,
      "parameterCount": 0,
      "varArgs": true,
      "annotatedReturnType": {
        "type": {
          "typeName": ""
        },
        "annotations": [],
        "declaredAnnotations": []
      },
      "defaultValue": {},
      "genericExceptionTypes": [],
      "genericParameterTypes": [],
      "genericReturnType": {
        "typeName": ""
      },
      "bridge": true,
      "annotatedParameterTypes": [],
      "annotatedExceptionTypes": [],
      "annotatedReceiverType": {
        "type": {
          "typeName": ""
        },
        "annotations": [],
        "declaredAnnotations": []
      },
      "accessible": true
    },
    "fields": [],
    "genericInterfaces": [],
    "genericSuperclass": {
      "typeName": ""
    },
    "interfaces": [],
    "methods": [],
    "package": {
      "name": "",
      "annotations": [],
      "declaredAnnotations": [],
      "sealed": true,
      "implementationTitle": "",
      "implementationVendor": "",
      "implementationVersion": "",
      "specificationTitle": "",
      "specificationVendor": "",
      "specificationVersion": ""
    },
    "signers": [],
    "simpleName": "",
    "typeName": "",
    "typeParameters": [],
    "annotation": true,
    "anonymousClass": true,
    "enum": true,
    "localClass": true,
    "memberClass": true,
    "synthetic": true
  }
}

NoClassDefFoundError: org/springframework/messaging/handler/annotation/MessageMapping

The issue

Your org.hildan.livedoc.springmvc.scanner.builder.SpringPathBuilder.buildPath(Method) method contains a hard dependency to org.springframework:spring-messaging:4.2.0.RELEASE.

public static Set<String> buildPath(Method method) {
    Set<String> paths = new HashSet<>();

    if (method.isAnnotationPresent(MessageMapping.class)) { // <---
        paths.addAll(getMappings(method, MessageMapping.class));
    }
    if (method.isAnnotationPresent(SubscribeMapping.class)) {
        paths.addAll(getMappings(method, SubscribeMapping.class));
    }
    if (method.isAnnotationPresent(RequestMapping.class)) {
        paths.addAll(getMappings(method, RequestMapping.class));
    }

    return paths;
}

If I don't have it on the classpath it will throw a NoClassDefFoundError on execution.

Note: Other locations are affected as well/have the same issue.

Potential fix

I recommend changing that method to use something like a strategy pattern:

static {
    if (Class.forName("...MessageMapping") != null) {
        pathDiscoveryStrategies.add(new MessageMappingPathDiscoveryStrategy());
    }
    if (Class.forName("...RequestMapping") != null) {
        pathDectectionStrategies.add(new RequestMappingPathDiscoveryStrategy());
    }
}

public static Set<String> buildPath(Method method) {
    Set<String> paths = new HashSet<>();

    for (PathDiscoveryStrategy strategy : pathDiscoveryStrategies) {
        paths.addAll(strategy.getMappings(method));
    }

    return paths;
}

Stacktrace

rg.springframework.web.util.NestedServletException: Handler dispatch failed; nested exception is java.lang.NoClassDefFoundError: org/springframework/messaging/handler/annotation/MessageMapping
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:982) [spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901) [spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) [spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861) [spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:635) [servlet-api.jar:?]
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) [spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) [servlet-api.jar:?]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) [catalina.jar:8.5.15]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [catalina.jar:8.5.15]
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) [tomcat-websocket.jar:8.5.15]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [catalina.jar:8.5.15]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [catalina.jar:8.5.15]
	at org.springframework.web.filter.AbstractRequestLoggingFilter.doFilterInternal(AbstractRequestLoggingFilter.java:244) [spring-web-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [catalina.jar:8.5.15]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [catalina.jar:8.5.15]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:317) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177) [spring-security-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
	at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346) [spring-web-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262) [spring-web-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [catalina.jar:8.5.15]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [catalina.jar:8.5.15]
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) [catalina.jar:8.5.15]
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [catalina.jar:8.5.15]
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478) [catalina.jar:8.5.15]
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [catalina.jar:8.5.15]
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80) [catalina.jar:8.5.15]
	at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:624) [catalina.jar:8.5.15]
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [catalina.jar:8.5.15]
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) [catalina.jar:8.5.15]
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799) [tomcat-coyote.jar:8.5.15]
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-coyote.jar:8.5.15]
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861) [tomcat-coyote.jar:8.5.15]
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1455) [tomcat-coyote.jar:8.5.15]
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-coyote.jar:8.5.15]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:1.8.0_144]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:1.8.0_144]
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-util.jar:8.5.15]
	at java.lang.Thread.run(Thread.java:748) [?:1.8.0_144]
Caused by: java.lang.NoClassDefFoundError: org/springframework/messaging/handler/annotation/MessageMapping
	at org.hildan.livedoc.springmvc.scanner.builder.SpringPathBuilder.buildPath(SpringPathBuilder.java:19) ~[livedoc-springmvc-2.1.0.jar:?]
	at org.hildan.livedoc.springmvc.SpringDocReader.buildApiMethodDoc(SpringDocReader.java:83) ~[livedoc-springmvc-2.1.0.jar:?]
	at org.hildan.livedoc.springmvc.SpringDocReader.buildApiMethodDoc(SpringDocReader.java:65) ~[livedoc-springmvc-2.1.0.jar:?]
	at org.hildan.livedoc.core.LivedocReader.lambda$readApiMethodDoc$7(LivedocReader.java:171) ~[livedoc-core-2.1.0.jar:?]
	at org.hildan.livedoc.core.LivedocReader.readFromAllReadersAndMerge(LivedocReader.java:198) ~[livedoc-core-2.1.0.jar:?]
	at org.hildan.livedoc.core.LivedocReader.readApiMethodDoc(LivedocReader.java:170) ~[livedoc-core-2.1.0.jar:?]
	at org.hildan.livedoc.core.LivedocReader.lambda$readApiMethodDocs$6(LivedocReader.java:155) ~[livedoc-core-2.1.0.jar:?]
	at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193) ~[?:1.8.0_144]
	at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1374) ~[?:1.8.0_144]
	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481) ~[?:1.8.0_144]
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) ~[?:1.8.0_144]
	at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708) ~[?:1.8.0_144]
	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[?:1.8.0_144]
	at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499) ~[?:1.8.0_144]
	at org.hildan.livedoc.core.LivedocReader.buildDocs(LivedocReader.java:192) ~[livedoc-core-2.1.0.jar:?]
	at org.hildan.livedoc.core.LivedocReader.readApiMethodDocs(LivedocReader.java:155) ~[livedoc-core-2.1.0.jar:?]
	at org.hildan.livedoc.core.LivedocReader.lambda$readApiDoc$5(LivedocReader.java:150) ~[livedoc-core-2.1.0.jar:?]
	at java.util.Optional.ifPresent(Optional.java:159) ~[?:1.8.0_144]
	at org.hildan.livedoc.core.LivedocReader.readApiDoc(LivedocReader.java:150) ~[livedoc-core-2.1.0.jar:?]
	at org.hildan.livedoc.core.LivedocReader.lambda$readApiDocs$3(LivedocReader.java:145) ~[livedoc-core-2.1.0.jar:?]
	at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193) ~[?:1.8.0_144]
	at java.util.HashMap$KeySpliterator.forEachRemaining(HashMap.java:1548) ~[?:1.8.0_144]
	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481) ~[?:1.8.0_144]
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) ~[?:1.8.0_144]
	at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708) ~[?:1.8.0_144]
	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[?:1.8.0_144]
	at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499) ~[?:1.8.0_144]
	at org.hildan.livedoc.core.LivedocReader.buildDocs(LivedocReader.java:192) ~[livedoc-core-2.1.0.jar:?]
	at org.hildan.livedoc.core.LivedocReader.readApiDocs(LivedocReader.java:145) ~[livedoc-core-2.1.0.jar:?]
	at org.hildan.livedoc.core.LivedocReader.read(LivedocReader.java:84) ~[livedoc-core-2.1.0.jar:?]
	at org.hildan.livedoc.springmvc.controller.JsonLivedocController.getApi(JsonLivedocController.java:60) ~[livedoc-springmvc-2.1.0.jar:?]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_144]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_144]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_144]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_144]
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133) ~[spring-web-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97) ~[spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827) ~[spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738) ~[spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) ~[spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967) [spring-webmvc-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	... 62 more

Add proper support for custom property exploration

Type exploration, as of now, is based on fields instead of actual serializable properties.
Without a more flexible approach, we end up with problems like:
#10
fabiomaffioletti/jsondoc#153
fabiomaffioletti/jsondoc#159
fabiomaffioletti/jsondoc#199
fabiomaffioletti/jsondoc#215
fabiomaffioletti/jsondoc#207
fabiomaffioletti/jsondoc#230

We want to be able to customize the way we list properties of a class, in particular how we name them and which ones to ignore.

Jsondoc examples does not use settings from springs ObjectMapper

The issue

The example generated by jsondoc does match the settings that have been set on the Jackson2HttpMessageConverter.

objectMapper.findAndRegisterModules()
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
...

I don't know how the template is generated, so I cannot give you further hints how to fix this.
If you give me a pointer where/how they are generated I might be able to present a solution.

Livedoc output

{
  "name": "",
  "startupTime": {
    "year": 0,
    "month": "JANUARY",
    "dayOfMonth": 0,
    "dayOfWeek": "MONDAY",
    "dayOfYear": 0,
    "monthValue": 0,
    "nano": 0,
    "hour": 0,
    "minute": 0,
    "second": 0,
    "chronology": {
      "calendarType": "",
      "id": ""
    }
  },
  "currentTime": {
    "year": 0,
    "month": "JANUARY",
    "dayOfMonth": 0,
    "dayOfWeek": "MONDAY",
    "dayOfYear": 0,
    "monthValue": 0,
    "nano": 0,
    "hour": 0,
    "minute": 0,
    "second": 0,
    "chronology": {
      "calendarType": "",
      "id": ""
    }
  }
}

Expected output

{
  "name": "",
  "startupTime": "2017-03-01T13:37:00Z",
  "currentTime": "2017-03-01T13:37:00Z"
}

Add Javadoc on all public classes

Javadoc is absolutely essential on public classes that users are supposed to use. It should be there to describe precisely what is expected in terms of arguments, and also to describe classes in general, and what their purposes are.

Refactor types management

Types are messy in both their construction and their representation.

  • In the JSON output of the doc, there should be enough information to be able to build links to types descriptions in the UI, from the return type of an API method for instance. LivedocType should contain such information, for instance a list of AtomicTypes, each containing some sort of ID (like the fully qualified name of the class) to be able to uniquely identify a type, and thus create links.
  • The hierarchy of type declarations in nested generics should be preserved, so as to be displayed properly.
  • The current building code is very verbose and bug-prone, we should adopt a more generic approach, and make use of recursion properly

Add quick-start documentation in the README

Even without a comprehensive and detailed documentation about the ins and outs of Livedoc, we should at least provide a quickstart guide for each way of using Livedoc:

  • using livedoc-core and creating a LivedocReader (and potentially a controller or some sort of access to the JSON documentation)
  • using livedoc-springmvc and creating a basic controller
  • using livedoc-springboot and application.properties

Also, of course, mention the UI webjar and how to use it.

Negated spring header support

Header filters in @RequestMapping can also be negated using the notations "!header-name" and "header!=value". From the Spring documentation:

Expressions can be negated by using the "!=" operator, as in "My-Header!=myValue". "My-Header" style expressions are also supported, with such headers having to be present in the request (allowed to have any value).
Finally, "!My-Header" style expressions indicate that the specified header is not supposed to be present in the request.

Also supports media type wildcards (*), for headers such as Accept and Content-Type. For instance:

@RequestMapping(value = "/something", headers = "content-type=text/*")

will match requests with a Content-Type of "text/html", "text/plain", etc.

Add negated media-types support

From the Spring documentation:

Expressions can be negated by using the "!" operator, as in "!text/plain", which matches
all requests with a Accept other than "text/plain".

Add custom default values support in templates

Currently, template generation uses property inspection for any non-primitive and non-enum type.
This leads, for instance, to inspection of java.util.Date objects, which results in #42.

We should allow for custom default values for any given class, and special cases of primitive wrapper classes and enum classes should just be pre-configured.
Maybe we should consider pre-configuring Date objects as well.

Remove ConcreteSubtypeMapper in Spring mode

We shouldn't document implementations of interfaces when in Spring mode. In Spring, Jackson is used for serialization, so there is no contraint on having fields anymore. If the return type of a method is an interface, then the interface must define all methods that we want documented.

For this to be possible, we would need a new @ApiProperty annotation to support documentation on getters.

Query param absence support

From the Spring doc, query params in @RequestMapping can be negated, thus resolving only requests without the given parameter:

Expressions can be negated by using the "!=" operator, as in "myParam!=myValue". "myParam" style expressions are also supported, with such parameters having to be present in the request (allowed to have any value). Finally, "!myParam" style expressions indicate that the specified parameter is not supposed to be present in the request.

Add real support for websocket messages API

The @MessageMapping and @SubscribeMapping annotations should not be used to filled the same kind of doc object as the request mappings. They should be displayed differently in the UI so that the user understands that it is websocket API, and not HTTP requests.

Also, the playground should be disabled for such endpoints, or upgraded to deal with websockets.

Add option to document collections as if they were arrays

Once serialized in JSON, there is little use in making a distinction between a list, a set, and an array. They are all [a, b, c] in the JSON.

The only pieces of information the actual type brings are:

  • whether the order of elements matters (and thus will be consistent)
  • whether it is possible to have duplicates

Although it may be useful information in some cases, I would imagine that in most cases, we don't really care. When we don't care, it could be nice to avoid the noise of having different collection names by using a plain array notation like MyType[].

Type-level path not taken into account for inherited methods

This is a continuation of the discussion in fabiomaffioletti/jsondoc#225.

To summarize, assuming the following situation:

public class ParentController {

    @RequestMapping("/parentMethod")
    public void parentMethod() { }
}

@Controller
@RequestMapping("/typeLevelPath")
public class ChildController extends ParentController {

    @RequestMapping("/childMethod")
    public void childMethod() { }
}

Spring generates the following API:

  • /typeLevelPath/childMethod
  • /typeLevelPath/parentMethod

While Livedoc would document:

  • /typeLevelPath/childMethod
  • /parentMethod

Create a maintainable UI

The current UI code is not quite maintainable, and should be rewritten in some recent Javascript UI framework like React.

Support cross-origin requests on the jsondoc endpoint

Currently, the server providing the JSON documentation and the UI need to be on the same host, because cross-origin requests are forbidden.

This is a pity because we need to allow external domains to fetch and display the doc their own way, if someone wants to write his own UI hosted somewhere else and access the JSON documentation endpoint.

This can be done by enabling CORS support on the generated controller (in the Spring flavor of Livedoc).

Host a demo for users to have a feel of the UI

The original JsonDoc project provided a little demo that was nice to play with. It allowed the users to have a feel of the UI and its possibilities.

As suggested by @ST-DDT in #48, it could be nice to have something equivalent here. Maybe hosted on github.io pages or similar.

Add example value annotation for primitive types

As proposed by @ST-DDT in #44, we should create an ApiExample annotation (or a new attribute for @ApiObjectField) in order for the user to provide example values to use in templates.

Since annotations don't support object attributes, this would be limited to primitive value types.

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.