micronaut-openapi icon indicating copy to clipboard operation
micronaut-openapi copied to clipboard

NPE when generating OpenAPI schema from Groovy classes

Open pditommaso opened this issue 5 years ago • 9 comments

When trying to generate the OpenAPI schema for a Groovy based project the Gradle build stops due the following exception:

aused by: java.lang.NullPointerException
        at io.micronaut.ast.groovy.visitor.GroovyClassElement.getBeanProperties(GroovyClassElement.java:259)
        at io.micronaut.openapi.visitor.AbstractOpenApiVisitor.populateSchemaProperties(AbstractOpenApiVisitor.java:1280)
        at io.micronaut.openapi.visitor.AbstractOpenApiVisitor.getSchemaDefinition(AbstractOpenApiVisitor.java:1103)
        at io.micronaut.openapi.visitor.AbstractOpenApiVisitor.resolveSchema(AbstractOpenApiVisitor.java:653)
        at io.micronaut.openapi.visitor.AbstractOpenApiVisitor.processPropertyElements(AbstractOpenApiVisitor.java:1301)
        at io.micronaut.openapi.visitor.AbstractOpenApiVisitor.populateSchemaProperties(AbstractOpenApiVisitor.java:1281)
        at io.micronaut.openapi.visitor.AbstractOpenApiVisitor.getSchemaDefinition(AbstractOpenApiVisitor.java:1103)
        at io.micronaut.openapi.visitor.AbstractOpenApiVisitor.resolveSchema(AbstractOpenApiVisitor.java:662)
        at io.micronaut.openapi.visitor.AbstractOpenApiEndpointVisitor.lambda$buildContent$15(AbstractOpenApiEndpointVisitor.java:878)
        at io.micronaut.openapi.visitor.AbstractOpenApiEndpointVisitor.buildContent(AbstractOpenApiEndpointVisitor.java:876)
        at io.micronaut.openapi.visitor.AbstractOpenApiEndpointVisitor.processBody(AbstractOpenApiEndpointVisitor.java:580)
        at io.micronaut.openapi.visitor.AbstractOpenApiEndpointVisitor.processParameter(AbstractOpenApiEndpointVisitor.java:329)
        at io.micronaut.openapi.visitor.AbstractOpenApiEndpointVisitor.processParameters(AbstractOpenApiEndpointVisitor.java:307)
        at io.micronaut.openapi.visitor.AbstractOpenApiEndpointVisitor.visitMethod(AbstractOpenApiEndpointVisitor.java:283)
        at io.micronaut.openapi.visitor.OpenApiControllerVisitor.visitMethod(OpenApiControllerVisitor.java:49)
        at io.micronaut.ast.groovy.visitor.LoadedVisitor.visit(LoadedVisitor.groovy:148)

Checking the corresponding line it seems to be protected against null access

https://github.com/micronaut-projects/micronaut-core/blob/e9378a1adf1873bbb30889b74a5498c6cab89eca/inject-groovy/src/main/groovy/io/micronaut/ast/groovy/visitor/GroovyClassElement.java#L259

Environment Information

  • Operating System: MacOS/Linux
  • Micronaut Version: micronaut-core: 1.3.7, micronaut-openapi: 1.5.2
  • JDK Version: Java 8

Example Application

Unfortunately, the issue is quite difficult to isolate since it happens quite large codebase.

pditommaso avatar Aug 26 '20 13:08 pditommaso

I've been able to reproduce this issue. Apparently it happens in a Groovy multi-project when:

  1. A project defines the classes to be used as part of requests and responses (let's call them domain classes).
  2. Another project adds the former as a dependency and defines the controller classes to generate the corresponding API docs.
  3. One of the domain classes has a field annotated with a "nested" annotation (an annotation that takes other annotations in its values), for example: @JsonSubTypes([@JsonSubTypes.Type(value = Cat, name = "cat")]).

This sample project reproduces the issue: https://github.com/tcrespog/mn-multi-openapi.

  1. The animal-kingdom project contains the domain classes and the pet-store project adds it as a dependency.
  2. The Pet class contains a @JsonSubtypes annotation with @JsonSubTypes.Type values.
  3. The PetController class has an endpoint involving Pet.
  4. The API docs generation fails when compiling pet-store. It doesn't matter whether the values of @JsonSubTypes.Type are classes of animal-kingdom or others such as Object, if the annotation @JsonSubTypes.Type is present, then the NPE happens.
  5. The error doesn't happen if the controller is written in Java, as seen in the branches java (projects written in Java) and mixed (domain written in Groovy and app written in Java). In addition, it doesn't happen if domain and controller are located in the same project.
  • Micronaut version: 2.1.4
  • Micronaut OpenAPI version: 2.1.1

tcrespog avatar Nov 23 '20 09:11 tcrespog

This seems like a bug in the Groovy AST processing. The problematic item is:

@JsonTypeInfo( use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXTERNAL_PROPERTY, property = "kind")
@JsonSubTypes([
        @JsonSubTypes.Type(value = Dog, name = "dog"),
        @JsonSubTypes.Type(value = Cat, name = "cat")
])
Animal animal

When getting the annotations for the animal node, the second AnnotationNode looks like:

image

Note how the expressions are all null.

@paulk-asert is this enough information for you to understand where the issue could be?

alvarosanchez avatar Nov 26 '20 11:11 alvarosanchez

I can replicate getting the NPE:

...
Caused by: java.lang.NullPointerException
        at org.codehaus.groovy.ast.GroovyCodeVisitor.lambda$visitListOfExpressions$0(GroovyCodeVisitor.java:202)
        at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
        at org.codehaus.groovy.ast.GroovyCodeVisitor.visitListOfExpressions(GroovyCodeVisitor.java:202)
...

Where is the breakpoint for above screenshot? There is a guard that the list is not null but the NPE would be expected if the list contained a null.

paulk-asert avatar Nov 27 '20 13:11 paulk-asert

I think it was at GroovyCodeVisitor, don't remember exactly but can try again.

Notice also that AnnotationNode#toString() throws an exception too.

alvarosanchez avatar Nov 27 '20 14:11 alvarosanchez

Second one could just be intellij trying to display the null

paulk-asert avatar Nov 27 '20 20:11 paulk-asert

The breakpoint is at ClassCodeVisitorSupport

The NPE is actually thrown at GroovyCodeVisitor. The List<? extends Expression> list is [null, null].

Hope this helps.

alvarosanchez avatar Dec 10 '20 16:12 alvarosanchez

@paulk-asert has this been reported in the Groovy Jira? I couldn't find anything.

alvarosanchez avatar Dec 11 '20 15:12 alvarosanchez

I don't believe so. Please raise a Jira.

paulk-asert avatar Dec 22 '20 05:12 paulk-asert

https://issues.apache.org/jira/browse/GROOVY-9871

alvarosanchez avatar Dec 22 '20 10:12 alvarosanchez