From d0ca80e465b82a847a1f414aeb909346b23d4311 Mon Sep 17 00:00:00 2001 From: Jonathan Lukas Date: Wed, 29 May 2024 16:09:04 +0200 Subject: [PATCH] Element Template generation: set notEmpty: false explicitly (#2675) * set notEmpty: false explicitly * added tests (cherry picked from commit 69eb232fa1bb51d005ce9462145f9e5c03a73bad) # Conflicts: # element-template-generator/core/src/main/java/io/camunda/connector/generator/java/processor/FieldProcessor.java # element-template-generator/core/src/main/java/io/camunda/connector/generator/java/processor/TemplatePropertyFieldProcessor.java # element-template-generator/core/src/test/java/io/camunda/connector/generator/java/example/outbound/MyConnectorInput.java --- .../java/annotation/TemplateProperty.java | 3 ++- .../java/processor/FieldProcessor.java | 13 +++++++++- .../JakartaValidationFieldProcessor.java | 4 ++- .../TemplatePropertyFieldProcessor.java | 14 +++++++--- ...tboundClassBasedTemplateGeneratorTest.java | 21 +++++++++++++++ .../example/outbound/MyConnectorInput.java | 26 ++++++++++++++++++- 6 files changed, 74 insertions(+), 7 deletions(-) diff --git a/element-template-generator/core/src/main/java/io/camunda/connector/generator/java/annotation/TemplateProperty.java b/element-template-generator/core/src/main/java/io/camunda/connector/generator/java/annotation/TemplateProperty.java index 4d738dab62..4ffd12c416 100644 --- a/element-template-generator/core/src/main/java/io/camunda/connector/generator/java/annotation/TemplateProperty.java +++ b/element-template-generator/core/src/main/java/io/camunda/connector/generator/java/annotation/TemplateProperty.java @@ -38,6 +38,7 @@ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD, ElementType.RECORD_COMPONENT}) public @interface TemplateProperty { + public static boolean OPTIONAL_DEFAULT = false; /** Custom property ID that can be referenced in conditions */ String id() default ""; @@ -52,7 +53,7 @@ String description() default ""; /** Whether the property should be marked as optional in the element template */ - boolean optional() default false; + boolean optional() default OPTIONAL_DEFAULT; /** * Overrides the property type. By default, the generator will use the field type to determine the diff --git a/element-template-generator/core/src/main/java/io/camunda/connector/generator/java/processor/FieldProcessor.java b/element-template-generator/core/src/main/java/io/camunda/connector/generator/java/processor/FieldProcessor.java index 1e29d457ea..c68240c42f 100644 --- a/element-template-generator/core/src/main/java/io/camunda/connector/generator/java/processor/FieldProcessor.java +++ b/element-template-generator/core/src/main/java/io/camunda/connector/generator/java/processor/FieldProcessor.java @@ -17,9 +17,20 @@ package io.camunda.connector.generator.java.processor; import io.camunda.connector.generator.dsl.PropertyBuilder; +import io.camunda.connector.generator.java.annotation.TemplateProperty; +import io.camunda.connector.generator.java.util.TemplateGenerationContext; import java.lang.reflect.Field; public interface FieldProcessor { - void process(Field field, PropertyBuilder propertyBuilder); + void process( + Field field, PropertyBuilder propertyBuilder, final TemplateGenerationContext context); + + static boolean isOptional(Field field) { + var annotation = field.getAnnotation(TemplateProperty.class); + if (annotation == null) { + return TemplateProperty.OPTIONAL_DEFAULT; + } + return annotation.optional(); + } } diff --git a/element-template-generator/core/src/main/java/io/camunda/connector/generator/java/processor/JakartaValidationFieldProcessor.java b/element-template-generator/core/src/main/java/io/camunda/connector/generator/java/processor/JakartaValidationFieldProcessor.java index 2477dfbb0f..62cd451450 100644 --- a/element-template-generator/core/src/main/java/io/camunda/connector/generator/java/processor/JakartaValidationFieldProcessor.java +++ b/element-template-generator/core/src/main/java/io/camunda/connector/generator/java/processor/JakartaValidationFieldProcessor.java @@ -52,7 +52,9 @@ public void process(Field field, PropertyBuilder propertyBuilder) { constraintsBuilder.pattern( new PropertyConstraints.Pattern(pattern.getLeft(), pattern.getRight())); } - + if (pattern != null && !hasNotEmptyConstraint(field) && FieldProcessor.isOptional(field)) { + constraintsBuilder.notEmpty(false); + } var constraints = constraintsBuilder.build(); if (!isConstraintEmpty(constraints)) { propertyBuilder.constraints(constraints); diff --git a/element-template-generator/core/src/main/java/io/camunda/connector/generator/java/processor/TemplatePropertyFieldProcessor.java b/element-template-generator/core/src/main/java/io/camunda/connector/generator/java/processor/TemplatePropertyFieldProcessor.java index b7a4e66c35..b2ecb6eef7 100644 --- a/element-template-generator/core/src/main/java/io/camunda/connector/generator/java/processor/TemplatePropertyFieldProcessor.java +++ b/element-template-generator/core/src/main/java/io/camunda/connector/generator/java/processor/TemplatePropertyFieldProcessor.java @@ -34,9 +34,14 @@ public void process(Field field, PropertyBuilder builder) { if (annotation == null) { return; } - builder.optional(annotation.optional()); - if (annotation.feel() != FeelMode.disabled && !(builder instanceof DropdownPropertyBuilder)) { - builder.feel(annotation.feel()); + builder.optional(FieldProcessor.isOptional(field)); + + if (!(builder instanceof DropdownPropertyBuilder)) { + if (annotation.feel() == Property.FeelMode.system_default) { + builder.feel(determineDefaultFeelModeBasedOnContext(context)); + } else { + builder.feel(annotation.feel()); + } } if (!annotation.label().isBlank()) { builder.label(annotation.label()); @@ -96,6 +101,9 @@ private PropertyConstraints buildConstraints(TemplateProperty propertyAnnotation builder.minLength(constraintsAnnotation.minLength()); } if (!constraintsAnnotation.pattern().value().isBlank()) { + if (!constraintsAnnotation.notEmpty() && propertyAnnotation.optional()) { + builder.notEmpty(false); + } builder.pattern( new PropertyConstraints.Pattern( constraintsAnnotation.pattern().value(), constraintsAnnotation.pattern().message())); diff --git a/element-template-generator/core/src/test/java/io/camunda/connector/generator/java/OutboundClassBasedTemplateGeneratorTest.java b/element-template-generator/core/src/test/java/io/camunda/connector/generator/java/OutboundClassBasedTemplateGeneratorTest.java index ffe28cc232..4077e793e3 100644 --- a/element-template-generator/core/src/test/java/io/camunda/connector/generator/java/OutboundClassBasedTemplateGeneratorTest.java +++ b/element-template-generator/core/src/test/java/io/camunda/connector/generator/java/OutboundClassBasedTemplateGeneratorTest.java @@ -803,6 +803,27 @@ void validationPresent_notEmpty_objectProperty() { assertThat(notEmptyProperty.getConstraints().minLength()).isNull(); assertThat(notEmptyProperty.getConstraints().maxLength()).isNull(); } + + @Test + void validationPresent_Pattern_optional() { + var template = generator.generate(MyConnectorFunction.MinimallyAnnotated.class).getFirst(); + var mayBeEmptyOrRegexValidated = getPropertyById("mayBeEmptyOrRegexValidated", template); + assertThat(mayBeEmptyOrRegexValidated.getConstraints()).isNotNull(); + assertThat(mayBeEmptyOrRegexValidated.getConstraints().notEmpty()).isFalse(); + assertThat(mayBeEmptyOrRegexValidated.getConstraints().minLength()).isNull(); + assertThat(mayBeEmptyOrRegexValidated.getConstraints().maxLength()).isNull(); + } + + @Test + void validationPresent_Pattern_optional_jakarta() { + var template = generator.generate(MyConnectorFunction.MinimallyAnnotated.class).getFirst(); + var mayBeEmptyOrRegexValidated = + getPropertyById("mayBeEmptyOrRegexValidatedJakartaStyle", template); + assertThat(mayBeEmptyOrRegexValidated.getConstraints()).isNotNull(); + assertThat(mayBeEmptyOrRegexValidated.getConstraints().notEmpty()).isFalse(); + assertThat(mayBeEmptyOrRegexValidated.getConstraints().minLength()).isNull(); + assertThat(mayBeEmptyOrRegexValidated.getConstraints().maxLength()).isNull(); + } } @Nested diff --git a/element-template-generator/core/src/test/java/io/camunda/connector/generator/java/example/outbound/MyConnectorInput.java b/element-template-generator/core/src/test/java/io/camunda/connector/generator/java/example/outbound/MyConnectorInput.java index 54161f00e4..b938701e87 100644 --- a/element-template-generator/core/src/test/java/io/camunda/connector/generator/java/example/outbound/MyConnectorInput.java +++ b/element-template-generator/core/src/test/java/io/camunda/connector/generator/java/example/outbound/MyConnectorInput.java @@ -21,6 +21,7 @@ import io.camunda.connector.generator.java.annotation.TemplateDiscriminatorProperty; import io.camunda.connector.generator.java.annotation.TemplateProperty; import io.camunda.connector.generator.java.annotation.TemplateProperty.PropertyCondition; +import io.camunda.connector.generator.java.annotation.TemplateProperty.PropertyConstraints; import io.camunda.connector.generator.java.annotation.TemplateProperty.PropertyType; import io.camunda.connector.generator.java.annotation.TemplateSubType; import io.camunda.connector.generator.java.example.outbound.MyConnectorInput.AnnotatedSealedType.FirstAnnotatedSubType; @@ -84,7 +85,30 @@ public record MyConnectorInput( @Size(min = Integer.MIN_VALUE, max = 10) String propertyWithMaxSize, @NotEmpty String stringPropertyWithNotEmpty, @NotBlank String stringPropertyWithNotBlank, - @NotNull Object objectPropertyWithNotNull) { + @NotNull Object objectPropertyWithNotNull, + @TemplateProperty( + id = "booleanProperty", + defaultValue = "false", + defaultValueType = DefaultValueType.Boolean) + Boolean booleanProperty, + @TemplateProperty( + id = "dependsOnBooleanPropertyFalse", + condition = @PropertyCondition(property = "booleanProperty", equals = "false")) + String dependsOnBooleanPropertyFalse, + @TemplateProperty( + id = "dependsOnBooleanPropertyTrue", + condition = @PropertyCondition(property = "booleanProperty", equals = "true")) + String dependsOnBooleanPropertyTrue, + @TemplateProperty( + id = "mayBeEmptyOrRegexValidated", + optional = true, + constraints = + @PropertyConstraints( + pattern = @TemplateProperty.Pattern(value = "xxx", message = "Oh no!"))) + String mayBeEmptyOrRegexValidated, + @TemplateProperty(id = "mayBeEmptyOrRegexValidatedJakartaStyle", optional = true) + @Pattern(regexp = "xxx", message = "Oh no!") + String mayBeEmptyOrRegexValidatedJakartaStyle) { sealed interface NonAnnotatedSealedType permits FirstSubType, NestedSealedType, SecondSubType {