From efc7da0d5e2e6fa0befab645134f3b80d5c6478d Mon Sep 17 00:00:00 2001 From: Luciano Vernaschi Date: Tue, 14 Jan 2025 15:42:58 +0100 Subject: [PATCH] fix(engine): don't check for `@JsonCreator` annotation and only take `@JsonValue` into account (#3097) * Skip unbalanced annotations * Fix outdated comment * Exclude JsonCreator from checkings * Rename test --- .../plugins/backbone/JsonValuePlugin.java | 41 +---- .../JsonCreatorNoJsonValueEndpoint.java | 43 +++++ .../JsonValueNoJsonCreatorTest.java | 22 +-- .../jsonvaluenojsoncreator/openapi.json | 148 ++++++++++++++++++ 4 files changed, 206 insertions(+), 48 deletions(-) create mode 100644 packages/java/parser-jvm-plugin-backbone/src/test/java/com/vaadin/hilla/parser/plugins/backbone/jsonvaluenojsoncreator/JsonCreatorNoJsonValueEndpoint.java create mode 100644 packages/java/parser-jvm-plugin-backbone/src/test/resources/com/vaadin/hilla/parser/plugins/backbone/jsonvaluenojsoncreator/openapi.json diff --git a/packages/java/parser-jvm-plugin-backbone/src/main/java/com/vaadin/hilla/parser/plugins/backbone/JsonValuePlugin.java b/packages/java/parser-jvm-plugin-backbone/src/main/java/com/vaadin/hilla/parser/plugins/backbone/JsonValuePlugin.java index e75847ffaa..a4870d685d 100644 --- a/packages/java/parser-jvm-plugin-backbone/src/main/java/com/vaadin/hilla/parser/plugins/backbone/JsonValuePlugin.java +++ b/packages/java/parser-jvm-plugin-backbone/src/main/java/com/vaadin/hilla/parser/plugins/backbone/JsonValuePlugin.java @@ -1,6 +1,5 @@ package com.vaadin.hilla.parser.plugins.backbone; -import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; import com.vaadin.hilla.parser.core.AbstractPlugin; import com.vaadin.hilla.parser.core.Node; @@ -16,11 +15,9 @@ import java.util.HashMap; import java.util.Map; import java.util.Optional; -import java.util.stream.Stream; /** - * Adds support for Jackson's {@code JsonValue} and {@code JsonCreator} - * annotations. + * Adds support for Jackson's {@code JsonValue} annotation. */ public class JsonValuePlugin extends AbstractPlugin { @@ -67,40 +64,8 @@ private Optional> getValueType(Class cls) { } private Optional> findValueType(Class cls) { - // First of all, we check that the `@JsonValue` annotation is - // used on a method of the class. - Stream> candidates = Arrays.stream(cls.getMethods()) + return Arrays.stream(cls.getMethods()) .filter(method -> method.isAnnotationPresent(JsonValue.class)) - .map(Method::getReturnType); - var jsonValue = candidates.findAny(); - - // Then we check that the class has a `@JsonCreator` annotation - // on a method or on a constructor. This is a basic check, we - // could also check that they use the same type. - var jsonCreator = Stream - .concat(Arrays.stream(cls.getMethods()), - Arrays.stream(cls.getConstructors())) - .filter(executable -> executable - .isAnnotationPresent(JsonCreator.class)) - .findAny(); - - // Classes having only one of those annotation are malformed in Hilla as - // they break the generator or, at least, make data transfer impossible, - // so we throw an exception for those. - if (jsonValue.isPresent() ^ jsonCreator.isPresent()) { - throw new MalformedValueTypeException("Class " + cls.getName() - + " has only one of @JsonValue and @JsonCreator." - + " Hilla only supports classes with both annotations."); - } - - return jsonValue; - } - - // this shouldn't be a runtime exception, but `resolve` doesn't allow - // checked exceptions - public static class MalformedValueTypeException extends RuntimeException { - public MalformedValueTypeException(String message) { - super(message); - } + .map(Method::getReturnType).findAny(); } } diff --git a/packages/java/parser-jvm-plugin-backbone/src/test/java/com/vaadin/hilla/parser/plugins/backbone/jsonvaluenojsoncreator/JsonCreatorNoJsonValueEndpoint.java b/packages/java/parser-jvm-plugin-backbone/src/test/java/com/vaadin/hilla/parser/plugins/backbone/jsonvaluenojsoncreator/JsonCreatorNoJsonValueEndpoint.java new file mode 100644 index 0000000000..e22dff5896 --- /dev/null +++ b/packages/java/parser-jvm-plugin-backbone/src/test/java/com/vaadin/hilla/parser/plugins/backbone/jsonvaluenojsoncreator/JsonCreatorNoJsonValueEndpoint.java @@ -0,0 +1,43 @@ +package com.vaadin.hilla.parser.plugins.backbone.jsonvaluenojsoncreator; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +@Endpoint +public class JsonCreatorNoJsonValueEndpoint { + + public static class User { + + private final String name; + private final int age; + + // Default constructor + public User() { + this.name = "Unknown"; + this.age = 0; + } + + // Constructor used during deserialization + @JsonCreator + public User(@JsonProperty("name") String n, + @JsonProperty("age") int a) { + name = n; + age = a; + } + + public String getName() { + return name; + } + + public int getAge() { + return age; + } + } + + public User getUser() { + return new User("John Doe", 42); + } + + public void setUser(User user) { + } +} diff --git a/packages/java/parser-jvm-plugin-backbone/src/test/java/com/vaadin/hilla/parser/plugins/backbone/jsonvaluenojsoncreator/JsonValueNoJsonCreatorTest.java b/packages/java/parser-jvm-plugin-backbone/src/test/java/com/vaadin/hilla/parser/plugins/backbone/jsonvaluenojsoncreator/JsonValueNoJsonCreatorTest.java index 9172981f2d..e3507a0ab8 100644 --- a/packages/java/parser-jvm-plugin-backbone/src/test/java/com/vaadin/hilla/parser/plugins/backbone/jsonvaluenojsoncreator/JsonValueNoJsonCreatorTest.java +++ b/packages/java/parser-jvm-plugin-backbone/src/test/java/com/vaadin/hilla/parser/plugins/backbone/jsonvaluenojsoncreator/JsonValueNoJsonCreatorTest.java @@ -2,25 +2,27 @@ import com.vaadin.hilla.parser.core.Parser; import com.vaadin.hilla.parser.plugins.backbone.BackbonePlugin; -import com.vaadin.hilla.parser.plugins.backbone.JsonValuePlugin.MalformedValueTypeException; import com.vaadin.hilla.parser.plugins.backbone.test.helpers.TestHelper; import org.junit.jupiter.api.Test; +import java.io.IOException; +import java.net.URISyntaxException; import java.util.List; import java.util.Set; -import static org.junit.jupiter.api.Assertions.assertThrows; - public class JsonValueNoJsonCreatorTest { private final TestHelper helper = new TestHelper(getClass()); @Test - public void should_ThrowExceptionWhenOnlyJsonValueIsUsed() { - assertThrows(MalformedValueTypeException.class, () -> { - new Parser().classPath(Set.of(helper.getTargetDir().toString())) - .endpointAnnotations(List.of(Endpoint.class)) - .addPlugin(new BackbonePlugin()) - .execute(List.of(JsonValueNoJsonCreatorEndpoint.class)); - }); + public void should_notChangeOutcomeAccordingToJsonCreator() + throws IOException, URISyntaxException { + var openAPI = new Parser() + .classPath(Set.of(helper.getTargetDir().toString())) + .endpointAnnotations(List.of(Endpoint.class)) + .addPlugin(new BackbonePlugin()) + .execute(List.of(JsonValueNoJsonCreatorEndpoint.class, + JsonCreatorNoJsonValueEndpoint.class)); + + helper.executeParserWithConfig(openAPI); } } diff --git a/packages/java/parser-jvm-plugin-backbone/src/test/resources/com/vaadin/hilla/parser/plugins/backbone/jsonvaluenojsoncreator/openapi.json b/packages/java/parser-jvm-plugin-backbone/src/test/resources/com/vaadin/hilla/parser/plugins/backbone/jsonvaluenojsoncreator/openapi.json new file mode 100644 index 0000000000..2dfaddfa9f --- /dev/null +++ b/packages/java/parser-jvm-plugin-backbone/src/test/resources/com/vaadin/hilla/parser/plugins/backbone/jsonvaluenojsoncreator/openapi.json @@ -0,0 +1,148 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "Hilla Application", + "version": "1.0.0" + }, + "servers": [ + { + "url": "http://localhost:8080/connect", + "description": "Hilla Backend" + } + ], + "tags": [ + { + "name": "JsonValueNoJsonCreatorEndpoint", + "x-class-name": "com.vaadin.hilla.parser.plugins.backbone.jsonvaluenojsoncreator.JsonValueNoJsonCreatorEndpoint" + }, + { + "name": "JsonCreatorNoJsonValueEndpoint", + "x-class-name": "com.vaadin.hilla.parser.plugins.backbone.jsonvaluenojsoncreator.JsonCreatorNoJsonValueEndpoint" + } + ], + "paths": { + "/JsonValueNoJsonCreatorEndpoint/getEmail": { + "post": { + "tags": [ + "JsonValueNoJsonCreatorEndpoint" + ], + "operationId": "JsonValueNoJsonCreatorEndpoint_getEmail_POST", + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "string", + "nullable": true + } + } + } + } + } + } + }, + "/JsonValueNoJsonCreatorEndpoint/setEmail": { + "post": { + "tags": [ + "JsonValueNoJsonCreatorEndpoint" + ], + "operationId": "JsonValueNoJsonCreatorEndpoint_setEmail_POST", + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "type": "string", + "nullable": true + } + } + } + } + } + }, + "responses": { + "200": { + "description": "" + } + } + } + }, + "/JsonCreatorNoJsonValueEndpoint/getUser": { + "post": { + "tags": [ + "JsonCreatorNoJsonValueEndpoint" + ], + "operationId": "JsonCreatorNoJsonValueEndpoint_getUser_POST", + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "nullable": true, + "anyOf": [ + { + "$ref": "#/components/schemas/com.vaadin.hilla.parser.plugins.backbone.jsonvaluenojsoncreator.JsonCreatorNoJsonValueEndpoint$User" + } + ] + } + } + } + } + } + } + }, + "/JsonCreatorNoJsonValueEndpoint/setUser": { + "post": { + "tags": [ + "JsonCreatorNoJsonValueEndpoint" + ], + "operationId": "JsonCreatorNoJsonValueEndpoint_setUser_POST", + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "user": { + "nullable": true, + "anyOf": [ + { + "$ref": "#/components/schemas/com.vaadin.hilla.parser.plugins.backbone.jsonvaluenojsoncreator.JsonCreatorNoJsonValueEndpoint$User" + } + ] + } + } + } + } + } + }, + "responses": { + "200": { + "description": "" + } + } + } + } + }, + "components": { + "schemas": { + "com.vaadin.hilla.parser.plugins.backbone.jsonvaluenojsoncreator.JsonCreatorNoJsonValueEndpoint$User": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true + }, + "age": { + "type": "integer", + "format": "int32" + } + } + } + } + } +}