Skip to content

Commit

Permalink
Resolve jakarta persistence id and version annotations as nullable by…
Browse files Browse the repository at this point in the history
… default

Fixes: #2809
  • Loading branch information
krissvaa committed Oct 31, 2024
1 parent 2248e82 commit a8d91e7
Show file tree
Hide file tree
Showing 8 changed files with 181 additions and 4 deletions.
5 changes: 5 additions & 0 deletions packages/java/parser-jvm-plugin-nonnull/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,10 @@
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>jakarta.persistence</groupId>
<artifactId>jakarta.persistence-api</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ static class Processor extends ConfigList.Processor<AnnotationMatcher> {
// Package-level annotations have low score
new AnnotationMatcher("org.springframework.lang.NonNullApi",
false, 10),
// Id and Version annotation usually mark nullable fields for CRUD operations.
// Low score allows other annotations to override them.
new AnnotationMatcher("jakarta.persistence.Id", true, 20),
new AnnotationMatcher("jakarta.persistence.Version", true, 20),
// Nullable-like annotations get a higher score. This should
// only matter when they are used in conjunction with
// package-level annotations
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.vaadin.hilla.parser.plugins.nonnull.nullable;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Endpoint {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.vaadin.hilla.parser.plugins.nonnull.nullable;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface EndpointExposed {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.vaadin.hilla.parser.plugins.nonnull.nullable;


import jakarta.persistence.Id;
import jakarta.persistence.Version;

@Endpoint
public class NullableEndpoint {

public NullableFieldModel nullableFieldModel(NullableFieldModel nullableFieldModel) {
return nullableFieldModel;
}

public static class NullableFieldModel {
@Id
public String id;
@Version
public Long version;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.vaadin.hilla.parser.plugins.nonnull.nullable;

import com.vaadin.hilla.parser.core.Parser;
import com.vaadin.hilla.parser.plugins.backbone.BackbonePlugin;
import com.vaadin.hilla.parser.plugins.nonnull.AnnotationMatcher;
import com.vaadin.hilla.parser.plugins.nonnull.NonnullPlugin;
import com.vaadin.hilla.parser.plugins.nonnull.NonnullPluginConfig;
import com.vaadin.hilla.parser.plugins.nonnull.test.helpers.TestHelper;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Set;

public class NullableTest {
private final TestHelper helper = new TestHelper(getClass());

@Test
public void should_ApplyNullableAnnotation()
throws IOException, URISyntaxException {
var plugin = new NonnullPlugin();
plugin.setConfiguration(new NonnullPluginConfig());

var openAPI = new Parser().classLoader(getClass().getClassLoader())
.classPath(Set.of(helper.getTargetDir().toString()))
.endpointAnnotation(Endpoint.class.getName())
.endpointExposedAnnotation(EndpointExposed.class.getName())
.addPlugin(new BackbonePlugin()).addPlugin(plugin).execute();

helper.executeParserWithConfig(openAPI);
}

@Test
public void annotationMatcher_shouldHaveDefaultConstructorAndSetter() {
// to enable maven initialize instances of AnnotationMatcher from
// pom.xml configurations, properly, it should have the default
// constructor and setter methods:
AnnotationMatcher annotationMatcher = new AnnotationMatcher();
annotationMatcher.setName("name");
annotationMatcher.setScore(100);
annotationMatcher.setMakesNullable(true);
Assertions.assertEquals("name", annotationMatcher.getName());
Assertions.assertEquals(100, annotationMatcher.getScore());
Assertions.assertTrue(annotationMatcher.doesMakeNullable());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
{
"openapi" : "3.0.1",
"info" : {
"title" : "Hilla Application",
"version" : "1.0.0"
},
"servers" : [
{
"url" : "http://localhost:8080/connect",
"description" : "Hilla Backend"
}
],
"tags" : [
{
"name" : "NullableEndpoint",
"x-class-name" : "com.vaadin.hilla.parser.plugins.nonnull.nullable.NullableEndpoint"
}
],
"paths" : {
"/NullableEndpoint/nullableFieldModel" : {
"post" : {
"tags" : [
"NullableEndpoint"
],
"operationId" : "NullableEndpoint_nullableFieldModel_POST",
"requestBody" : {
"content" : {
"application/json" : {
"schema" : {
"type" : "object",
"properties" : {
"nullableFieldModel" : {
"nullable" : true,
"anyOf" : [
{
"$ref" : "#/components/schemas/com.vaadin.hilla.parser.plugins.nonnull.nullable.NullableEndpoint$NullableFieldModel"
}
]
}
}
}
}
}
},
"responses" : {
"200" : {
"description" : "",
"content" : {
"application/json" : {
"schema" : {
"nullable" : true,
"anyOf" : [
{
"$ref" : "#/components/schemas/com.vaadin.hilla.parser.plugins.nonnull.nullable.NullableEndpoint$NullableFieldModel"
}
]
}
}
}
}
}
}
}
},
"components" : {
"schemas" : {
"com.vaadin.hilla.parser.plugins.nonnull.nullable.NullableEndpoint$NullableFieldModel" : {
"type" : "object",
"properties" : {
"id" : {
"type" : "string",
"nullable" : true
},
"version" : {
"type" : "integer",
"format" : "int64",
"nullable" : true
}
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,13 @@
import jakarta.persistence.MappedSuperclass;
import jakarta.persistence.Version;

import com.vaadin.hilla.Nullable;

@MappedSuperclass
public class AbstractEntity {
@Id
@Nullable
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Version
@Nullable
private Long version;

public Long getId() {
Expand Down

0 comments on commit a8d91e7

Please sign in to comment.