diff --git a/CHANGELOG.md b/CHANGELOG.md index a0488d5c64d..cde348ad678 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ #### Improvements * Remove `setIntVal`, `setStrVal`, `setKind` setters from `IntOrString` class to avoid invalid combinations +* Fix #3852: Deserializing kamelets fails with UnrecognizedPropertyException * Fix #3889 : remove piped stream for file download * Fix #1285: removed references to manually calling registerCustomKind * Fix #3334: adding basic support for server side apply. Use patch(PatchContext.of(PatchType.SERVER_SIDE_APPLY), service), or new PatchContext.Builder().withPatchType(PatchType.SERVER_SIDE_APPLY).withForce(true).build() to override conflicts. diff --git a/extensions/camel-k/generator-v1alpha1/cmd/generate/generate.go b/extensions/camel-k/generator-v1alpha1/cmd/generate/generate.go index f962a9cf598..2b32cc811b1 100644 --- a/extensions/camel-k/generator-v1alpha1/cmd/generate/generate.go +++ b/extensions/camel-k/generator-v1alpha1/cmd/generate/generate.go @@ -44,7 +44,6 @@ func main() { // types that are manually defined in the model providedTypes := []schemagen.ProvidedType{ - {GoType: reflect.TypeOf(v1alpha1.JSONSchemaProps{}), JavaClass: "io.fabric8.kubernetes.api.model.apiextensions.v1.JSONSchemaProps"}, {GoType: reflect.TypeOf(v1.Flow{}), JavaClass: "com.fasterxml.jackson.databind.JsonNode"}, {GoType: reflect.TypeOf(v1.TraitConfiguration{}), JavaClass: "com.fasterxml.jackson.databind.JsonNode"}, } @@ -81,6 +80,7 @@ func main() { reflect.TypeOf(apis.VolatileTime{}): "java.lang.String", reflect.TypeOf(runtime.RawExtension{}): "java.util.Map", reflect.TypeOf(v1.Template{}): "java.util.Map", + reflect.TypeOf(v1alpha1.JSON{}): "com.fasterxml.jackson.databind.JsonNode", } json := schemagen.GenerateSchema("http://fabric8.io/camel-k/v1alpha1/CamelKSchema#", crdLists, providedPackages, manualTypeMap, packageMapping, mappingSchema, providedTypes, constraints, "io.fabric8") diff --git a/extensions/camel-k/model-v1alpha1/pom.xml b/extensions/camel-k/model-v1alpha1/pom.xml index 9af43cb4864..75a43b1b142 100644 --- a/extensions/camel-k/model-v1alpha1/pom.xml +++ b/extensions/camel-k/model-v1alpha1/pom.xml @@ -131,9 +131,6 @@ - diff --git a/extensions/camel-k/model-v1alpha1/src/main/resources/schema/camel-k-schema-v1alpha1.json b/extensions/camel-k/model-v1alpha1/src/main/resources/schema/camel-k-schema-v1alpha1.json index 9e232ff56b9..ad87a82940a 100644 --- a/extensions/camel-k/model-v1alpha1/src/main/resources/schema/camel-k-schema-v1alpha1.json +++ b/extensions/camel-k/model-v1alpha1/src/main/resources/schema/camel-k-schema-v1alpha1.json @@ -54,7 +54,8 @@ "type": "string" }, "schema": { - "existingJavaType": "io.fabric8.kubernetes.api.model.apiextensions.v1.JSONSchemaProps" + "$ref": "#/definitions/github_com_apache_camel-k_pkg_apis_camel_v1alpha1_JSONSchemaProps", + "existingJavaType": "io.fabric8.camelk.v1alpha1.JSONSchemaProps" } }, "javaType": "io.fabric8.camelk.v1alpha1.EventTypeSpec", @@ -62,6 +63,158 @@ "io.fabric8.kubernetes.api.model.KubernetesResource" ] }, + "github_com_apache_camel-k_pkg_apis_camel_v1alpha1_ExternalDocumentation": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "javaType": "io.fabric8.camelk.v1alpha1.ExternalDocumentation", + "javaInterfaces": [ + "io.fabric8.kubernetes.api.model.KubernetesResource" + ] + }, + "github_com_apache_camel-k_pkg_apis_camel_v1alpha1_JSONSchemaProp": { + "type": "object", + "properties": { + "default": { + "existingJavaType": "com.fasterxml.jackson.databind.JsonNode" + }, + "description": { + "type": "string" + }, + "enum": { + "type": "array", + "javaOmitEmpty": true, + "items": { + "existingJavaType": "com.fasterxml.jackson.databind.JsonNode" + } + }, + "example": { + "existingJavaType": "com.fasterxml.jackson.databind.JsonNode" + }, + "exclusiveMaximum": { + "type": "boolean" + }, + "exclusiveMinimum": { + "type": "boolean" + }, + "format": { + "type": "string" + }, + "id": { + "type": "string" + }, + "maxItems": { + "type": "integer", + "existingJavaType": "Long" + }, + "maxLength": { + "type": "integer", + "existingJavaType": "Long" + }, + "maxProperties": { + "type": "integer", + "existingJavaType": "Long" + }, + "maximum": { + "type": "string", + "existingJavaType": "String" + }, + "minItems": { + "type": "integer", + "existingJavaType": "Long" + }, + "minLength": { + "type": "integer", + "existingJavaType": "Long" + }, + "minProperties": { + "type": "integer", + "existingJavaType": "Long" + }, + "minimum": { + "type": "string", + "existingJavaType": "String" + }, + "multipleOf": { + "type": "string", + "existingJavaType": "String" + }, + "nullable": { + "type": "boolean" + }, + "pattern": { + "type": "string" + }, + "title": { + "type": "string" + }, + "type": { + "type": "string" + }, + "uniqueItems": { + "type": "boolean" + }, + "x-descriptors": { + "type": "array", + "javaOmitEmpty": true, + "items": { + "type": "string" + } + } + }, + "javaType": "io.fabric8.camelk.v1alpha1.JSONSchemaProp", + "javaInterfaces": [ + "io.fabric8.kubernetes.api.model.KubernetesResource" + ] + }, + "github_com_apache_camel-k_pkg_apis_camel_v1alpha1_JSONSchemaProps": { + "type": "object", + "properties": { + "$schema": { + "type": "string" + }, + "description": { + "type": "string" + }, + "example": { + "existingJavaType": "com.fasterxml.jackson.databind.JsonNode" + }, + "externalDocs": { + "$ref": "#/definitions/github_com_apache_camel-k_pkg_apis_camel_v1alpha1_ExternalDocumentation", + "existingJavaType": "io.fabric8.camelk.v1alpha1.ExternalDocumentation" + }, + "id": { + "type": "string" + }, + "properties": { + "type": "object", + "existingJavaType": "java.util.Map\u003cString,io.fabric8.camelk.v1alpha1.JSONSchemaProp\u003e" + }, + "required": { + "type": "array", + "javaOmitEmpty": true, + "items": { + "type": "string" + } + }, + "title": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "javaType": "io.fabric8.camelk.v1alpha1.JSONSchemaProps", + "javaInterfaces": [ + "io.fabric8.kubernetes.api.model.KubernetesResource" + ] + }, "github_com_apache_camel-k_pkg_apis_camel_v1alpha1_Kamelet": { "type": "object", "properties": { @@ -324,7 +477,8 @@ "existingJavaType": "io.fabric8.camelk.v1alpha1.AuthorizationSpec" }, "definition": { - "existingJavaType": "io.fabric8.kubernetes.api.model.apiextensions.v1.JSONSchemaProps" + "$ref": "#/definitions/github_com_apache_camel-k_pkg_apis_camel_v1alpha1_JSONSchemaProps", + "existingJavaType": "io.fabric8.camelk.v1alpha1.JSONSchemaProps" }, "dependencies": { "type": "array", @@ -407,6 +561,18 @@ "$ref": "#/definitions/github_com_apache_camel-k_pkg_apis_camel_v1alpha1_EventTypeSpec", "existingJavaType": "io.fabric8.camelk.v1alpha1.EventTypeSpec" }, + "github_com_apache_camel-k_pkg_apis_camel_v1alpha1_ExternalDocumentation": { + "$ref": "#/definitions/github_com_apache_camel-k_pkg_apis_camel_v1alpha1_ExternalDocumentation", + "existingJavaType": "io.fabric8.camelk.v1alpha1.ExternalDocumentation" + }, + "github_com_apache_camel-k_pkg_apis_camel_v1alpha1_JSONSchemaProp": { + "$ref": "#/definitions/github_com_apache_camel-k_pkg_apis_camel_v1alpha1_JSONSchemaProp", + "existingJavaType": "io.fabric8.camelk.v1alpha1.JSONSchemaProp" + }, + "github_com_apache_camel-k_pkg_apis_camel_v1alpha1_JSONSchemaProps": { + "$ref": "#/definitions/github_com_apache_camel-k_pkg_apis_camel_v1alpha1_JSONSchemaProps", + "existingJavaType": "io.fabric8.camelk.v1alpha1.JSONSchemaProps" + }, "github_com_apache_camel-k_pkg_apis_camel_v1alpha1_Kamelet": { "$ref": "#/definitions/github_com_apache_camel-k_pkg_apis_camel_v1alpha1_Kamelet", "existingJavaType": "io.fabric8.camelk.v1alpha1.Kamelet" diff --git a/extensions/camel-k/model-v1alpha1/src/test/java/io/fabric8/camelk/KameletModelTest.java b/extensions/camel-k/model-v1alpha1/src/test/java/io/fabric8/camelk/KameletModelTest.java index 23bbc62a04d..12498dd2be4 100644 --- a/extensions/camel-k/model-v1alpha1/src/test/java/io/fabric8/camelk/KameletModelTest.java +++ b/extensions/camel-k/model-v1alpha1/src/test/java/io/fabric8/camelk/KameletModelTest.java @@ -17,12 +17,12 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.Test; - +import io.fabric8.camelk.v1alpha1.JSONSchemaPropsBuilder; import io.fabric8.camelk.v1alpha1.Kamelet; import io.fabric8.camelk.v1alpha1.KameletBuilder; -import io.fabric8.kubernetes.api.model.apiextensions.v1.JSONSchemaPropsBuilder; +import org.junit.jupiter.api.Test; +import java.util.Collections; import java.util.Scanner; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -33,17 +33,17 @@ class KameletModelTest { @Test - void shouldCreateKamelet() { + void shouldCreateKamelet() { Kamelet kamelet = new KameletBuilder() - .withNewMetadata() - .withName("my-kamelet") - .endMetadata() - .withNewSpec() - .withDefinition(new JSONSchemaPropsBuilder() - // blah blah - .build()) - .endSpec() - .build(); + .withNewMetadata() + .withName("my-kamelet") + .endMetadata() + .withNewSpec() + .withDefinition(new JSONSchemaPropsBuilder() + // blah blah + .build()) + .endSpec() + .build(); assertNotNull(kamelet); assertEquals("my-kamelet", kamelet.getMetadata().getName()); @@ -54,8 +54,8 @@ void shouldDeserializeValidYamlIntoObject() throws JsonProcessingException { final ObjectMapper mapper = new ObjectMapper(); // Given String originalJson = new Scanner(getClass().getResourceAsStream("/valid-kamelet.json")) - .useDelimiter("\\A") - .next(); + .useDelimiter("\\A") + .next(); // When final Kamelet kamelet = mapper.readValue(originalJson, Kamelet.class); @@ -72,5 +72,29 @@ void shouldDeserializeValidYamlIntoObject() throws JsonProcessingException { assertTrue(kamelet.getSpec().getTemplate().containsKey("beans")); assertTrue(kamelet.getSpec().getTemplate().containsKey("from")); } -} + @Test + void shouldDeserializeValidYamlContainingCamelJSONSchemaProps() throws JsonProcessingException { + final ObjectMapper mapper = new ObjectMapper(); + // Given + String originalJson = new Scanner(getClass().getResourceAsStream("/valid-kamelet-x-descriptors.json")) + .useDelimiter("\\A") + .next(); + + // When + final Kamelet kamelet = mapper.readValue(originalJson, Kamelet.class); + final String serializedJson = mapper.writeValueAsString(kamelet); + final Kamelet kameletFromSerializedJson = mapper.readValue(serializedJson, Kamelet.class); + + // Then + assertNotNull(kamelet); + assertNotNull(serializedJson); + assertNotNull(kameletFromSerializedJson); + assertEquals(kamelet.getMetadata().getName(), kameletFromSerializedJson.getMetadata().getName()); + assertNotNull(kamelet.getSpec().getDefinition()); + assertNotNull(kamelet.getSpec().getDefinition().getProperties()); + assertNotNull(kamelet.getSpec().getDefinition().getProperties().get("validate")); + assertEquals(Collections.singletonList("urn:alm:descriptor:com.tectonic.ui:checkbox"), + kamelet.getSpec().getDefinition().getProperties().get("validate").getxDescriptors()); + } +} diff --git a/extensions/camel-k/model-v1alpha1/src/test/resources/valid-kamelet-x-descriptors.json b/extensions/camel-k/model-v1alpha1/src/test/resources/valid-kamelet-x-descriptors.json new file mode 100644 index 00000000000..64f52b981a1 --- /dev/null +++ b/extensions/camel-k/model-v1alpha1/src/test/resources/valid-kamelet-x-descriptors.json @@ -0,0 +1,92 @@ +{ + "apiVersion": "camel.apache.org/v1alpha1", + "kind": "Kamelet", + "metadata": { + "name": "foo-deserialize-action", + "annotations": { + "camel.apache.org/kamelet.support.level": "Preview", + "camel.apache.org/catalog.version": "main-SNAPSHOT", + "camel.apache.org/provider": "Apache Software Foundation", + "camel.apache.org/kamelet.group": "Actions" + }, + "labels": { + "camel.apache.org/kamelet.type": "action" + } + }, + "spec": { + "definition": { + "title": "Foo Deserialize Action", + "description": "Deserialize payload to Foo", + "type": "object", + "required": [ + "schema" + ], + "properties": { + "schema": { + "title": "Schema", + "description": "The Foo schema to use during serialization (as single-line, using JSON format)", + "type": "string", + "example": "{\"type\": \"record\", \"namespace\": \"com.example\", \"name\": \"FullName\", \"fields\": [{\"name\": \"first\", \"type\": \"string\"},{\"name\": \"last\", \"type\": \"string\"}]}" + }, + "validate": { + "title": "Validate", + "description": "Indicates if the content must be validated against the schema", + "type": "boolean", + "default": true, + "x-descriptors": [ + "urn:alm:descriptor:com.tectonic.ui:checkbox" + ] + } + } + }, + "dependencies": [ + "github:apache.camel-kamelets:camel-kamelets-utils:main-SNAPSHOT", + "camel:kamelet", + "camel:core", + "camel:jackson-foo" + ], + "template": { + "from": { + "uri": "kamelet:source", + "steps": [ + { + "set-property": { + "name": "schema", + "constant": "{{schema}}" + } + }, + { + "set-property": { + "name": "validate", + "constant": "{{validate}}" + } + }, + { + "unmarshal": { + "foo": { + "library": "Jackson", + "unmarshalType": "com.fasterxml.jackson.databind.JsonNode", + "schemaResolver": "#class:org.apache.camel.kamelets.utils.serialization.InflightFooSchemaResolver" + } + } + }, + { + "remove-property": { + "name": "schema" + } + }, + { + "remove-property": { + "name": "validate" + } + }, + { + "remove-header": { + "name": "Content-Type" + } + } + ] + } + } + } +}