From 96bda0871f123dbf39c423662587f5b174a74359 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Jul 2025 16:15:00 +0000 Subject: [PATCH 1/6] Bump org.apache.maven.plugins:maven-gpg-plugin from 3.2.7 to 3.2.8 Bumps [org.apache.maven.plugins:maven-gpg-plugin](https://github.com/apache/maven-gpg-plugin) from 3.2.7 to 3.2.8. - [Release notes](https://github.com/apache/maven-gpg-plugin/releases) - [Commits](https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-3.2.7...maven-gpg-plugin-3.2.8) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-gpg-plugin dependency-version: 3.2.8 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1f1e72c1..d86d9b6d 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ 3.5.0 3.5.3 2.27 - 3.2.7 + 3.2.8 3.4.2 ${java.version} 1.2.2 From ac3bc6786653b7c1b94add36dd294954ed4c322d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Jul 2025 15:49:45 +0000 Subject: [PATCH 2/6] Bump org.apache.maven.plugins:maven-enforcer-plugin from 3.5.0 to 3.6.0 Bumps [org.apache.maven.plugins:maven-enforcer-plugin](https://github.com/apache/maven-enforcer) from 3.5.0 to 3.6.0. - [Release notes](https://github.com/apache/maven-enforcer/releases) - [Commits](https://github.com/apache/maven-enforcer/compare/enforcer-3.5.0...enforcer-3.6.0) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-enforcer-plugin dependency-version: 3.6.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d86d9b6d..5d42e813 100644 --- a/pom.xml +++ b/pom.xml @@ -54,7 +54,7 @@ 3.6.0 3.14.0 3.1.4 - 3.5.0 + 3.6.0 3.5.3 2.27 3.2.8 From 2403d1adf0ecfc2a7fc6435ecfdc14e5d64da41d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Jul 2025 16:25:07 +0000 Subject: [PATCH 3/6] Bump version.org.junit.jupiter from 5.13.2 to 5.13.3 Bumps `version.org.junit.jupiter` from 5.13.2 to 5.13.3. Updates `org.junit.jupiter:junit-jupiter-api` from 5.13.2 to 5.13.3 - [Release notes](https://github.com/junit-team/junit-framework/releases) - [Commits](https://github.com/junit-team/junit-framework/compare/r5.13.2...r5.13.3) Updates `org.junit.jupiter:junit-jupiter-engine` from 5.13.2 to 5.13.3 - [Release notes](https://github.com/junit-team/junit-framework/releases) - [Commits](https://github.com/junit-team/junit-framework/compare/r5.13.2...r5.13.3) Updates `org.junit.jupiter:junit-jupiter-params` from 5.13.2 to 5.13.3 - [Release notes](https://github.com/junit-team/junit-framework/releases) - [Commits](https://github.com/junit-team/junit-framework/compare/r5.13.2...r5.13.3) --- updated-dependencies: - dependency-name: org.junit.jupiter:junit-jupiter-api dependency-version: 5.13.3 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.junit.jupiter:junit-jupiter-engine dependency-version: 5.13.3 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.junit.jupiter:junit-jupiter-params dependency-version: 5.13.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5d42e813..a1d961ad 100644 --- a/pom.xml +++ b/pom.xml @@ -75,7 +75,7 @@ 3.1.1 1.5.2 3.27.3 - 5.13.2 + 5.13.3 5.18.0 2.0.17 9.0.1.Final From f6caef49ec3cefbd9bf251cfe32e46f46325c5a8 Mon Sep 17 00:00:00 2001 From: fjtirado Date: Thu, 10 Jul 2025 18:31:14 +0200 Subject: [PATCH 4/6] [Fix #634] Refactoring modules Signed-off-by: fjtirado --- api/pom.xml | 70 ++----------------- custom-generator/pom.xml | 6 ++ .../generator/AllAnyOneOfSchemaRule.java | 17 +++-- .../generator/GeneratorUtils.java | 9 --- .../generator/UnevaluatedPropertiesRule.java | 3 +- pom.xml | 2 + serverlessworkflow-annotations/pom.xml | 20 ++++++ .../annotations}/OneOfSetter.java | 2 +- .../annotations}/OneOfValueProvider.java | 2 +- .../serialization/DeserializeHelper.java | 1 + .../serialization/SerializeHelper.java | 4 +- serverlessworkflow-types/pom.xml | 66 +++++++++++++++++ .../src/main/resources/schema/workflow.yaml | 0 13 files changed, 116 insertions(+), 86 deletions(-) create mode 100644 serverlessworkflow-annotations/pom.xml rename {api/src/main/java/io/serverlessworkflow/serialization => serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/annotations}/OneOfSetter.java (95%) rename {api/src/main/java/io/serverlessworkflow/api => serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/annotations}/OneOfValueProvider.java (94%) rename {api => serverlessworkflow-annotations}/src/main/java/io/serverlessworkflow/serialization/DeserializeHelper.java (98%) rename {api => serverlessworkflow-annotations}/src/main/java/io/serverlessworkflow/serialization/SerializeHelper.java (91%) create mode 100644 serverlessworkflow-types/pom.xml rename {api => serverlessworkflow-types}/src/main/resources/schema/workflow.yaml (100%) diff --git a/api/pom.xml b/api/pom.xml index 2b08c827..e2bf61fa 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -14,29 +14,23 @@ - org.slf4j - slf4j-api + io.serverlessworkflow + serverlessworkflow-types + ${project.version} - com.fasterxml.jackson.core - jackson-core + org.slf4j + slf4j-api com.networknt json-schema-validator - - com.fasterxml.jackson.core - jackson-databind - com.fasterxml.jackson.dataformat jackson-dataformat-yaml - - jakarta.validation - jakarta.validation-api - + org.hibernate.validator hibernate-validator @@ -79,54 +73,4 @@ test - - - - - - org.jsonschema2pojo - jsonschema2pojo-maven-plugin - - ${basedir}/src/main/resources/schema - - - yamlschema - io.serverlessworkflow.api.types - ${project.build.directory}/generated-sources/src/main/java - true - true - true - true - false - false - true - true - true - true - ${java.version} - true - true - io.serverlessworkflow.generator.UnreferencedFactory - io.serverlessworkflow.generator.ConstAnnotator - - - - io.serverlessworkflow - serverless-workflow-custom-generator - ${project.version} - - - - - - generate - - generate-sources - - - - - - + diff --git a/custom-generator/pom.xml b/custom-generator/pom.xml index 40bf6b11..55b2215b 100644 --- a/custom-generator/pom.xml +++ b/custom-generator/pom.xml @@ -12,6 +12,12 @@ org.jsonschema2pojo jsonschema2pojo-core + + io.serverlessworkflow + serverlessworkflow-annotations + ${project.version} + + diff --git a/custom-generator/src/main/java/io/serverlessworkflow/generator/AllAnyOneOfSchemaRule.java b/custom-generator/src/main/java/io/serverlessworkflow/generator/AllAnyOneOfSchemaRule.java index 28a611cb..6221a560 100644 --- a/custom-generator/src/main/java/io/serverlessworkflow/generator/AllAnyOneOfSchemaRule.java +++ b/custom-generator/src/main/java/io/serverlessworkflow/generator/AllAnyOneOfSchemaRule.java @@ -33,6 +33,10 @@ import com.sun.codemodel.JPackage; import com.sun.codemodel.JType; import com.sun.codemodel.JVar; +import io.serverlessworkflow.annotations.OneOfSetter; +import io.serverlessworkflow.annotations.OneOfValueProvider; +import io.serverlessworkflow.serialization.DeserializeHelper; +import io.serverlessworkflow.serialization.SerializeHelper; import jakarta.validation.ConstraintViolationException; import java.io.UnsupportedEncodingException; import java.net.URI; @@ -318,10 +322,7 @@ private JDefinedClass populateOneOf( null); definedClass._implements( - definedClass - .owner() - .ref(GeneratorUtils.ONE_OF_VALUE_PROVIDER_INTERFACE_NAME) - .narrow(valueField.type())); + definedClass.owner().ref(OneOfValueProvider.class).narrow(valueField.type())); GeneratorUtils.implementInterface(definedClass, valueField); try { JDefinedClass serializer = generateSerializer(definedClass); @@ -397,9 +398,7 @@ private JDefinedClass generateSerializer(JDefinedClass relatedClass) (method, valueParam, genParam) -> method .body() - .staticInvoke( - definedClass.owner().ref(GeneratorUtils.SERIALIZE_HELPER_NAME), - "serializeOneOf") + .staticInvoke(definedClass.owner().ref(SerializeHelper.class), "serializeOneOf") .arg(genParam) .arg(valueParam)); return definedClass; @@ -418,7 +417,7 @@ private JDefinedClass generateDeserializer( body._return( definedClass .owner() - .ref(GeneratorUtils.DESERIALIZE_HELPER_NAME) + .ref(DeserializeHelper.class) .staticInvoke(methodName) .arg(parserParam) .arg(relatedClass.dotclass()) @@ -460,7 +459,7 @@ private JVar setupMethod( v -> { method.body().assign(JExpr._this().ref(v), methodParam); method - .annotate(definedClass.owner().ref(GeneratorUtils.SETTER_ANNOTATION_NAME)) + .annotate(definedClass.owner().ref(OneOfSetter.class)) .param("value", instanceField.type()); }); return methodParam; diff --git a/custom-generator/src/main/java/io/serverlessworkflow/generator/GeneratorUtils.java b/custom-generator/src/main/java/io/serverlessworkflow/generator/GeneratorUtils.java index e7af60d5..b98bd7be 100644 --- a/custom-generator/src/main/java/io/serverlessworkflow/generator/GeneratorUtils.java +++ b/custom-generator/src/main/java/io/serverlessworkflow/generator/GeneratorUtils.java @@ -32,15 +32,6 @@ public class GeneratorUtils { - public static final String SERIALIZE_HELPER_NAME = - "io.serverlessworkflow.serialization.SerializeHelper"; - public static final String DESERIALIZE_HELPER_NAME = - "io.serverlessworkflow.serialization.DeserializeHelper"; - public static final String ONE_OF_VALUE_PROVIDER_INTERFACE_NAME = - "io.serverlessworkflow.api.OneOfValueProvider"; - public static final String SETTER_ANNOTATION_NAME = - "io.serverlessworkflow.serialization.OneOfSetter"; - @FunctionalInterface public interface SerializerFiller { void accept(JMethod method, JVar valueParam, JVar genParam); diff --git a/custom-generator/src/main/java/io/serverlessworkflow/generator/UnevaluatedPropertiesRule.java b/custom-generator/src/main/java/io/serverlessworkflow/generator/UnevaluatedPropertiesRule.java index 18bdbba6..533db957 100644 --- a/custom-generator/src/main/java/io/serverlessworkflow/generator/UnevaluatedPropertiesRule.java +++ b/custom-generator/src/main/java/io/serverlessworkflow/generator/UnevaluatedPropertiesRule.java @@ -27,6 +27,7 @@ import com.sun.codemodel.JMethod; import com.sun.codemodel.JMod; import com.sun.codemodel.JType; +import io.serverlessworkflow.serialization.DeserializeHelper; import org.jsonschema2pojo.Schema; import org.jsonschema2pojo.rules.AdditionalPropertiesRule; import org.jsonschema2pojo.rules.Rule; @@ -125,7 +126,7 @@ private JDefinedClass generateDeserializer(JDefinedClass relatedClass, JType pro ._return( definedClass .owner() - .ref(GeneratorUtils.DESERIALIZE_HELPER_NAME) + .ref(DeserializeHelper.class) .staticInvoke("deserializeItem") .arg(parserParam) .arg(relatedClass.dotclass()) diff --git a/pom.xml b/pom.xml index a1d961ad..271e10da 100644 --- a/pom.xml +++ b/pom.xml @@ -40,6 +40,8 @@ api custom-generator impl + serverlessworkflow-types + serverlessworkflow-annotations diff --git a/serverlessworkflow-annotations/pom.xml b/serverlessworkflow-annotations/pom.xml new file mode 100644 index 00000000..e37aa671 --- /dev/null +++ b/serverlessworkflow-annotations/pom.xml @@ -0,0 +1,20 @@ + + 4.0.0 + + io.serverlessworkflow + serverlessworkflow-parent + 8.0.0-SNAPSHOT + + Serverless Workflow :: Annotations + serverlessworkflow-annotations + + + com.fasterxml.jackson.core + jackson-databind + + + jakarta.validation + jakarta.validation-api + + + \ No newline at end of file diff --git a/api/src/main/java/io/serverlessworkflow/serialization/OneOfSetter.java b/serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/annotations/OneOfSetter.java similarity index 95% rename from api/src/main/java/io/serverlessworkflow/serialization/OneOfSetter.java rename to serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/annotations/OneOfSetter.java index 098df425..d67f0292 100644 --- a/api/src/main/java/io/serverlessworkflow/serialization/OneOfSetter.java +++ b/serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/annotations/OneOfSetter.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.serverlessworkflow.serialization; +package io.serverlessworkflow.annotations; import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.RetentionPolicy.RUNTIME; diff --git a/api/src/main/java/io/serverlessworkflow/api/OneOfValueProvider.java b/serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/annotations/OneOfValueProvider.java similarity index 94% rename from api/src/main/java/io/serverlessworkflow/api/OneOfValueProvider.java rename to serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/annotations/OneOfValueProvider.java index 9d17b872..d275ff9d 100644 --- a/api/src/main/java/io/serverlessworkflow/api/OneOfValueProvider.java +++ b/serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/annotations/OneOfValueProvider.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.serverlessworkflow.api; +package io.serverlessworkflow.annotations; public interface OneOfValueProvider { T get(); diff --git a/api/src/main/java/io/serverlessworkflow/serialization/DeserializeHelper.java b/serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/serialization/DeserializeHelper.java similarity index 98% rename from api/src/main/java/io/serverlessworkflow/serialization/DeserializeHelper.java rename to serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/serialization/DeserializeHelper.java index cfbd54ca..041474d9 100644 --- a/api/src/main/java/io/serverlessworkflow/serialization/DeserializeHelper.java +++ b/serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/serialization/DeserializeHelper.java @@ -19,6 +19,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.TreeNode; import com.fasterxml.jackson.databind.JsonMappingException; +import io.serverlessworkflow.annotations.OneOfSetter; import jakarta.validation.ConstraintViolationException; import java.io.IOException; import java.lang.reflect.InvocationTargetException; diff --git a/api/src/main/java/io/serverlessworkflow/serialization/SerializeHelper.java b/serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/serialization/SerializeHelper.java similarity index 91% rename from api/src/main/java/io/serverlessworkflow/serialization/SerializeHelper.java rename to serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/serialization/SerializeHelper.java index e074a656..47ab1a5e 100644 --- a/api/src/main/java/io/serverlessworkflow/serialization/SerializeHelper.java +++ b/serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/serialization/SerializeHelper.java @@ -16,11 +16,11 @@ package io.serverlessworkflow.serialization; import com.fasterxml.jackson.core.JsonGenerator; -import io.serverlessworkflow.api.OneOfValueProvider; +import io.serverlessworkflow.annotations.OneOfValueProvider; import java.io.IOException; public class SerializeHelper { - public static void serializeOneOf(JsonGenerator jgen, OneOfValueProvider item) + public static void serializeOneOf(JsonGenerator jgen, OneOfValueProvider item) throws IOException { jgen.writeObject(item.get()); } diff --git a/serverlessworkflow-types/pom.xml b/serverlessworkflow-types/pom.xml new file mode 100644 index 00000000..4fe9f9d2 --- /dev/null +++ b/serverlessworkflow-types/pom.xml @@ -0,0 +1,66 @@ + + 4.0.0 + + io.serverlessworkflow + serverlessworkflow-parent + 8.0.0-SNAPSHOT + + Serverless Workflow :: Types + serverlessworkflow-types + + + io.serverlessworkflow + serverlessworkflow-annotations + ${project.version} + + + + + + org.jsonschema2pojo + jsonschema2pojo-maven-plugin + + ${basedir}/src/main/resources/schema + + + yamlschema + io.serverlessworkflow.api.types + ${project.build.directory}/generated-sources/src/main/java + true + true + true + true + false + false + true + true + true + true + ${java.version} + true + jackson2 + true + io.serverlessworkflow.generator.UnreferencedFactory + io.serverlessworkflow.generator.ConstAnnotator + + + + io.serverlessworkflow + serverless-workflow-custom-generator + ${project.version} + + + + + + generate + + generate-sources + + + + + + \ No newline at end of file diff --git a/api/src/main/resources/schema/workflow.yaml b/serverlessworkflow-types/src/main/resources/schema/workflow.yaml similarity index 100% rename from api/src/main/resources/schema/workflow.yaml rename to serverlessworkflow-types/src/main/resources/schema/workflow.yaml From a7efd235b10f6dec537d450f4bb64cc86f790d21 Mon Sep 17 00:00:00 2001 From: fjtirado Date: Thu, 10 Jul 2025 20:01:27 +0200 Subject: [PATCH 5/6] [Fix #634] Setting up maven plugin Signed-off-by: fjtirado --- api/pom.xml | 47 ++++ .../api/ObjectMapperFactory.java | 6 +- .../generator/AllAnyOneOfSchemaRule.java | 64 +---- ...nstAnnotator.java => CustomAnnotator.java} | 10 +- .../generator/GeneratorUtils.java | 61 +---- .../generator/UnevaluatedPropertiesRule.java | 56 +--- jackson-generator/pom.xml | 80 ++++++ .../generator/jackson/GeneratorUtils.java | 172 +++++++++++++ .../generator/jackson/JacksonMixInPojo.java | 243 ++++++++++++++++++ pom.xml | 2 + serverlessworkflow-annotations/pom.xml | 10 - .../annotations/AdditionalProperties.java | 26 ++ .../annotations/GetterMethod.java | 26 ++ .../serverlessworkflow/annotations/Item.java | 26 ++ .../annotations/ItemKey.java | 26 ++ .../annotations/ItemValue.java | 26 ++ .../serverlessworkflow/annotations/Union.java | 26 ++ serverlessworkflow-serialization/pom.xml | 24 ++ .../serialization/DeserializeHelper.java | 0 .../serialization/SerializeHelper.java | 0 serverlessworkflow-types/pom.xml | 8 +- 21 files changed, 754 insertions(+), 185 deletions(-) rename custom-generator/src/main/java/io/serverlessworkflow/generator/{ConstAnnotator.java => CustomAnnotator.java} (78%) create mode 100644 jackson-generator/pom.xml create mode 100644 jackson-generator/src/main/java/io/serverlessworkflow/generator/jackson/GeneratorUtils.java create mode 100644 jackson-generator/src/main/java/io/serverlessworkflow/generator/jackson/JacksonMixInPojo.java create mode 100644 serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/annotations/AdditionalProperties.java create mode 100644 serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/annotations/GetterMethod.java create mode 100644 serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/annotations/Item.java create mode 100644 serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/annotations/ItemKey.java create mode 100644 serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/annotations/ItemValue.java create mode 100644 serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/annotations/Union.java create mode 100644 serverlessworkflow-serialization/pom.xml rename {serverlessworkflow-annotations => serverlessworkflow-serialization}/src/main/java/io/serverlessworkflow/serialization/DeserializeHelper.java (100%) rename {serverlessworkflow-annotations => serverlessworkflow-serialization}/src/main/java/io/serverlessworkflow/serialization/SerializeHelper.java (100%) diff --git a/api/pom.xml b/api/pom.xml index e2bf61fa..19414b85 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -18,6 +18,11 @@ serverlessworkflow-types ${project.version} + + io.serverlessworkflow + serverlessworkflow-serialization + ${project.version} + org.slf4j slf4j-api @@ -73,4 +78,46 @@ test + + + + + io.serverlessworkflow + jackson-generator + ${project.version} + + + io.serverlessworkflow.api.types + + + + + generate + + generate-sources + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 3.3.0 + + + add-mixin + generate-sources + + add-source + + + + ${project.build.directory}/generated-sources/jacksonmixinpojo + + + + + + + diff --git a/api/src/main/java/io/serverlessworkflow/api/ObjectMapperFactory.java b/api/src/main/java/io/serverlessworkflow/api/ObjectMapperFactory.java index c8211586..78b1e24e 100644 --- a/api/src/main/java/io/serverlessworkflow/api/ObjectMapperFactory.java +++ b/api/src/main/java/io/serverlessworkflow/api/ObjectMapperFactory.java @@ -15,11 +15,13 @@ */ package io.serverlessworkflow.api; +import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator.Feature; +import io.serverlessworkflow.api.types.JacksonMixInModule; import io.serverlessworkflow.serialization.BeanDeserializerModifierWithValidation; import io.serverlessworkflow.serialization.URIDeserializer; import io.serverlessworkflow.serialization.URISerializer; @@ -47,10 +49,12 @@ private static ObjectMapper configure(ObjectMapper mapper) { validationModule.setDeserializerModifier(new BeanDeserializerModifierWithValidation()); return mapper + .setSerializationInclusion(Include.NON_NULL) .configure(SerializationFeature.INDENT_OUTPUT, true) .configure(SerializationFeature.WRITE_EMPTY_JSON_ARRAYS, false) .configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false) - .registerModule(validationModule); + .registerModule(validationModule) + .registerModule(new JacksonMixInModule()); } private ObjectMapperFactory() {} diff --git a/custom-generator/src/main/java/io/serverlessworkflow/generator/AllAnyOneOfSchemaRule.java b/custom-generator/src/main/java/io/serverlessworkflow/generator/AllAnyOneOfSchemaRule.java index 6221a560..32dca0cd 100644 --- a/custom-generator/src/main/java/io/serverlessworkflow/generator/AllAnyOneOfSchemaRule.java +++ b/custom-generator/src/main/java/io/serverlessworkflow/generator/AllAnyOneOfSchemaRule.java @@ -16,8 +16,6 @@ package io.serverlessworkflow.generator; import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.node.ArrayNode; import com.sun.codemodel.JBlock; import com.sun.codemodel.JClass; @@ -35,8 +33,7 @@ import com.sun.codemodel.JVar; import io.serverlessworkflow.annotations.OneOfSetter; import io.serverlessworkflow.annotations.OneOfValueProvider; -import io.serverlessworkflow.serialization.DeserializeHelper; -import io.serverlessworkflow.serialization.SerializeHelper; +import io.serverlessworkflow.annotations.Union; import jakarta.validation.ConstraintViolationException; import java.io.UnsupportedEncodingException; import java.net.URI; @@ -324,21 +321,7 @@ private JDefinedClass populateOneOf( definedClass._implements( definedClass.owner().ref(OneOfValueProvider.class).narrow(valueField.type())); GeneratorUtils.implementInterface(definedClass, valueField); - try { - JDefinedClass serializer = generateSerializer(definedClass); - definedClass.annotate(JsonSerialize.class).param("using", serializer); - } catch (JClassAlreadyExistsException ex) { - // already serialized aware - } - - try { - JDefinedClass deserializer = - generateDeserializer(definedClass, oneOfTypes, "deserializeOneOf"); - definedClass.annotate(JsonDeserialize.class).param("using", deserializer); - } catch (JClassAlreadyExistsException ex) { - // already deserialized aware - } - + definedClass.annotate(Union.class); return wrapAll(parentSchema, definedClass, commonType, oneOfTypes, Optional.of(valueField)); } @@ -389,49 +372,6 @@ private static boolean isStringType(JType type) { return type.name().equals("String"); } - private JDefinedClass generateSerializer(JDefinedClass relatedClass) - throws JClassAlreadyExistsException { - JDefinedClass definedClass = GeneratorUtils.serializerClass(relatedClass); - GeneratorUtils.fillSerializer( - definedClass, - relatedClass, - (method, valueParam, genParam) -> - method - .body() - .staticInvoke(definedClass.owner().ref(SerializeHelper.class), "serializeOneOf") - .arg(genParam) - .arg(valueParam)); - return definedClass; - } - - private JDefinedClass generateDeserializer( - JDefinedClass relatedClass, Collection oneOfTypes, String methodName) - throws JClassAlreadyExistsException { - JDefinedClass definedClass = GeneratorUtils.deserializerClass(relatedClass); - GeneratorUtils.fillDeserializer( - definedClass, - relatedClass, - (method, parserParam) -> { - JBlock body = method.body(); - - body._return( - definedClass - .owner() - .ref(DeserializeHelper.class) - .staticInvoke(methodName) - .arg(parserParam) - .arg(relatedClass.dotclass()) - .arg(list(definedClass, oneOfTypes))); - }); - return definedClass; - } - - private JInvocation list(JDefinedClass definedClass, Collection list) { - JInvocation result = definedClass.owner().ref(List.class).staticInvoke("of"); - list.forEach(c -> result.arg(((JClass) c.getType()).dotclass())); - return result; - } - private void wrapIt( Schema parentSchema, JDefinedClass definedClass, diff --git a/custom-generator/src/main/java/io/serverlessworkflow/generator/ConstAnnotator.java b/custom-generator/src/main/java/io/serverlessworkflow/generator/CustomAnnotator.java similarity index 78% rename from custom-generator/src/main/java/io/serverlessworkflow/generator/ConstAnnotator.java rename to custom-generator/src/main/java/io/serverlessworkflow/generator/CustomAnnotator.java index a893cfb5..657ba3ce 100644 --- a/custom-generator/src/main/java/io/serverlessworkflow/generator/ConstAnnotator.java +++ b/custom-generator/src/main/java/io/serverlessworkflow/generator/CustomAnnotator.java @@ -18,18 +18,24 @@ import com.fasterxml.jackson.databind.JsonNode; import com.sun.codemodel.JDefinedClass; import com.sun.codemodel.JFieldVar; +import io.serverlessworkflow.annotations.AdditionalProperties; import jakarta.validation.constraints.Pattern; import org.jsonschema2pojo.AbstractAnnotator; import org.jsonschema2pojo.GenerationConfig; -public class ConstAnnotator extends AbstractAnnotator { +public class CustomAnnotator extends AbstractAnnotator { private static final String CONST = "const"; - public ConstAnnotator(GenerationConfig generationConfig) { + public CustomAnnotator(GenerationConfig generationConfig) { super(generationConfig); } + @Override + public void additionalPropertiesField(JFieldVar field, JDefinedClass clazz, String propertyName) { + clazz.annotate(AdditionalProperties.class); + } + @Override public void propertyField( JFieldVar field, JDefinedClass clazz, String propertyName, JsonNode propertyNode) { diff --git a/custom-generator/src/main/java/io/serverlessworkflow/generator/GeneratorUtils.java b/custom-generator/src/main/java/io/serverlessworkflow/generator/GeneratorUtils.java index b98bd7be..d330321b 100644 --- a/custom-generator/src/main/java/io/serverlessworkflow/generator/GeneratorUtils.java +++ b/custom-generator/src/main/java/io/serverlessworkflow/generator/GeneratorUtils.java @@ -15,43 +15,15 @@ */ package io.serverlessworkflow.generator; -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonDeserializer; -import com.fasterxml.jackson.databind.JsonSerializer; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.sun.codemodel.JClassAlreadyExistsException; import com.sun.codemodel.JDefinedClass; import com.sun.codemodel.JFieldVar; import com.sun.codemodel.JMethod; import com.sun.codemodel.JMod; -import com.sun.codemodel.JVar; -import java.io.IOException; +import io.serverlessworkflow.annotations.GetterMethod; import org.jsonschema2pojo.util.NameHelper; public class GeneratorUtils { - @FunctionalInterface - public interface SerializerFiller { - void accept(JMethod method, JVar valueParam, JVar genParam); - } - - @FunctionalInterface - public interface DeserializerFiller { - void accept(JMethod method, JVar parserParam); - } - - public static JDefinedClass serializerClass(JDefinedClass relatedClass) - throws JClassAlreadyExistsException { - return createClass(relatedClass, JsonSerializer.class, "Serializer"); - } - - public static JDefinedClass deserializerClass(JDefinedClass relatedClass) - throws JClassAlreadyExistsException { - return createClass(relatedClass, JsonDeserializer.class, "Deserializer"); - } - public static JMethod implementInterface(JDefinedClass definedClass, JFieldVar valueField) { JMethod method = definedClass.method(JMod.PUBLIC, valueField.type(), "get"); method.annotate(Override.class); @@ -67,38 +39,9 @@ public static JMethod getterMethod( instanceField.type(), nameHelper.getGetterName(name, instanceField.type(), null)); method.body()._return(instanceField); + method.annotate(GetterMethod.class); return method; } - public static void fillSerializer( - JDefinedClass definedClass, JDefinedClass relatedClass, SerializerFiller filler) { - JMethod method = definedClass.method(JMod.PUBLIC, void.class, "serialize"); - method.annotate(Override.class); - method._throws(IOException.class); - JVar valueParam = method.param(relatedClass, "value"); - JVar genParam = method.param(JsonGenerator.class, "gen"); - method.param(SerializerProvider.class, "serializers"); - filler.accept(method, valueParam, genParam); - } - - public static void fillDeserializer( - JDefinedClass definedClass, JDefinedClass relatedClass, DeserializerFiller filler) { - JMethod method = definedClass.method(JMod.PUBLIC, relatedClass, "deserialize"); - method.annotate(Override.class); - method._throws(IOException.class); - JVar parserParam = method.param(JsonParser.class, "parser"); - method.param(DeserializationContext.class, "dctx"); - filler.accept(method, parserParam); - } - - private static JDefinedClass createClass( - JDefinedClass relatedClass, Class serializerClass, String suffix) - throws JClassAlreadyExistsException { - JDefinedClass definedClass = - relatedClass._package()._class(JMod.NONE, relatedClass.name() + suffix); - definedClass._extends(definedClass.owner().ref(serializerClass).narrow(relatedClass)); - return definedClass; - } - private GeneratorUtils() {} } diff --git a/custom-generator/src/main/java/io/serverlessworkflow/generator/UnevaluatedPropertiesRule.java b/custom-generator/src/main/java/io/serverlessworkflow/generator/UnevaluatedPropertiesRule.java index 533db957..5388a503 100644 --- a/custom-generator/src/main/java/io/serverlessworkflow/generator/UnevaluatedPropertiesRule.java +++ b/custom-generator/src/main/java/io/serverlessworkflow/generator/UnevaluatedPropertiesRule.java @@ -16,10 +16,6 @@ package io.serverlessworkflow.generator; import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import com.sun.codemodel.JBlock; -import com.sun.codemodel.JClass; import com.sun.codemodel.JClassAlreadyExistsException; import com.sun.codemodel.JDefinedClass; import com.sun.codemodel.JExpr; @@ -27,7 +23,9 @@ import com.sun.codemodel.JMethod; import com.sun.codemodel.JMod; import com.sun.codemodel.JType; -import io.serverlessworkflow.serialization.DeserializeHelper; +import io.serverlessworkflow.annotations.Item; +import io.serverlessworkflow.annotations.ItemKey; +import io.serverlessworkflow.annotations.ItemValue; import org.jsonschema2pojo.Schema; import org.jsonschema2pojo.rules.AdditionalPropertiesRule; import org.jsonschema2pojo.rules.Rule; @@ -100,12 +98,10 @@ private JDefinedClass addKeyValueFields( JMod.PRIVATE, propertyType, nameHelper.getPropertyName(propertyType.name(), null)); JMethod valueMethod = GeneratorUtils.getterMethod(jclass, valueField, nameHelper, propertyType.name()); - jclass - .annotate(JsonSerialize.class) - .param("using", generateSerializer(jclass, nameMethod, valueMethod)); - jclass - .annotate(JsonDeserialize.class) - .param("using", generateDeserializer(jclass, propertyType)); + + jclass.annotate(Item.class); + nameMethod.annotate(ItemKey.class); + valueMethod.annotate(ItemValue.class); JMethod constructor = jclass.constructor(JMod.PUBLIC); constructor .body() @@ -114,44 +110,6 @@ private JDefinedClass addKeyValueFields( return jclass; } - private JDefinedClass generateDeserializer(JDefinedClass relatedClass, JType propertyType) - throws JClassAlreadyExistsException { - JDefinedClass definedClass = GeneratorUtils.deserializerClass(relatedClass); - GeneratorUtils.fillDeserializer( - definedClass, - relatedClass, - (method, parserParam) -> - method - .body() - ._return( - definedClass - .owner() - .ref(DeserializeHelper.class) - .staticInvoke("deserializeItem") - .arg(parserParam) - .arg(relatedClass.dotclass()) - .arg(((JClass) propertyType).dotclass()))); - return definedClass; - } - - private JDefinedClass generateSerializer( - JDefinedClass relatedClass, JMethod nameMethod, JMethod valueMethod) - throws JClassAlreadyExistsException { - JDefinedClass definedClass = GeneratorUtils.serializerClass(relatedClass); - GeneratorUtils.fillSerializer( - definedClass, - relatedClass, - (method, valueParam, genParam) -> { - JBlock body = method.body(); - body.invoke(genParam, "writeStartObject"); - body.invoke(genParam, "writeObjectField") - .arg(valueParam.invoke(nameMethod)) - .arg(valueParam.invoke(valueMethod)); - body.invoke(genParam, "writeEndObject"); - }); - return definedClass; - } - private boolean checkIntValue(JsonNode node, String propName, int value) { return node.has(propName) && node.get(propName).asInt() == value; } diff --git a/jackson-generator/pom.xml b/jackson-generator/pom.xml new file mode 100644 index 00000000..55d2e03c --- /dev/null +++ b/jackson-generator/pom.xml @@ -0,0 +1,80 @@ + + 4.0.0 + maven-plugin + + io.serverlessworkflow + serverlessworkflow-parent + 8.0.0-SNAPSHOT + + jackson-generator + + 3.15.1 + + + + + + org.apache.maven.plugins + maven-plugin-plugin + ${maven-plugin-tools.version} + + jackson-generator + + + + help-mojo + + + helpmojo + + + + + + + + + + + + org.apache.maven.plugins + maven-plugin-report-plugin + ${maven-plugin-tools.version} + + + + + + org.apache.maven + maven-plugin-api + ${version.maven} + provided + + + com.sun.codemodel + codemodel + 2.6 + + + io.github.classgraph + classgraph + 4.8.180 + + + org.apache.maven.plugin-tools + maven-plugin-annotations + ${maven-plugin-tools.version} + provided + + + io.serverlessworkflow + serverlessworkflow-types + ${project.version} + + + io.serverlessworkflow + serverlessworkflow-serialization + ${project.version} + + + \ No newline at end of file diff --git a/jackson-generator/src/main/java/io/serverlessworkflow/generator/jackson/GeneratorUtils.java b/jackson-generator/src/main/java/io/serverlessworkflow/generator/jackson/GeneratorUtils.java new file mode 100644 index 00000000..9463106f --- /dev/null +++ b/jackson-generator/src/main/java/io/serverlessworkflow/generator/jackson/GeneratorUtils.java @@ -0,0 +1,172 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.serverlessworkflow.generator.jackson; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.sun.codemodel.JBlock; +import com.sun.codemodel.JClass; +import com.sun.codemodel.JClassAlreadyExistsException; +import com.sun.codemodel.JDefinedClass; +import com.sun.codemodel.JInvocation; +import com.sun.codemodel.JMethod; +import com.sun.codemodel.JMod; +import com.sun.codemodel.JType; +import com.sun.codemodel.JVar; +import io.serverlessworkflow.serialization.DeserializeHelper; +import io.serverlessworkflow.serialization.SerializeHelper; +import java.io.IOException; +import java.util.Collection; +import java.util.List; + +public class GeneratorUtils { + + @FunctionalInterface + public interface SerializerFiller { + void accept(JMethod method, JVar valueParam, JVar genParam); + } + + @FunctionalInterface + public interface DeserializerFiller { + void accept(JMethod method, JVar parserParam); + } + + public static JDefinedClass serializerClass(JClass relatedClass) + throws JClassAlreadyExistsException { + return createClass(relatedClass, JsonSerializer.class, "Serializer"); + } + + public static JDefinedClass deserializerClass(JClass relatedClass) + throws JClassAlreadyExistsException { + return createClass(relatedClass, JsonDeserializer.class, "Deserializer"); + } + + public static void fillSerializer( + JDefinedClass definedClass, JClass relatedClass, SerializerFiller filler) { + JMethod method = definedClass.method(JMod.PUBLIC, void.class, "serialize"); + method.annotate(Override.class); + method._throws(IOException.class); + JVar valueParam = method.param(relatedClass, "value"); + JVar genParam = method.param(JsonGenerator.class, "gen"); + method.param(SerializerProvider.class, "serializers"); + filler.accept(method, valueParam, genParam); + } + + public static void fillDeserializer( + JDefinedClass definedClass, JClass relatedClass, DeserializerFiller filler) { + JMethod method = definedClass.method(JMod.PUBLIC, relatedClass, "deserialize"); + method.annotate(Override.class); + method._throws(IOException.class); + JVar parserParam = method.param(JsonParser.class, "parser"); + method.param(DeserializationContext.class, "dctx"); + filler.accept(method, parserParam); + } + + private static JDefinedClass createClass( + JClass relatedClass, Class serializerClass, String suffix) + throws JClassAlreadyExistsException { + JDefinedClass definedClass = + relatedClass._package()._class(JMod.NONE, relatedClass.name() + suffix); + definedClass._extends(definedClass.owner().ref(serializerClass).narrow(relatedClass)); + return definedClass; + } + + public static JDefinedClass generateSerializer(JClass relatedClass) + throws JClassAlreadyExistsException { + JDefinedClass definedClass = GeneratorUtils.serializerClass(relatedClass); + GeneratorUtils.fillSerializer( + definedClass, + relatedClass, + (method, valueParam, genParam) -> + method + .body() + .staticInvoke(definedClass.owner().ref(SerializeHelper.class), "serializeOneOf") + .arg(genParam) + .arg(valueParam)); + return definedClass; + } + + public static JDefinedClass generateDeserializer( + JClass relatedClass, Collection oneOfTypes) throws JClassAlreadyExistsException { + JDefinedClass definedClass = GeneratorUtils.deserializerClass(relatedClass); + GeneratorUtils.fillDeserializer( + definedClass, + relatedClass, + (method, parserParam) -> { + JBlock body = method.body(); + + body._return( + definedClass + .owner() + .ref(DeserializeHelper.class) + .staticInvoke("deserializeOneOf") + .arg(parserParam) + .arg(relatedClass.dotclass()) + .arg(list(definedClass, oneOfTypes))); + }); + return definedClass; + } + + public static JDefinedClass generateDeserializer(JClass relatedClass, JType propertyType) + throws JClassAlreadyExistsException { + JDefinedClass definedClass = GeneratorUtils.deserializerClass(relatedClass); + GeneratorUtils.fillDeserializer( + definedClass, + relatedClass, + (method, parserParam) -> + method + .body() + ._return( + definedClass + .owner() + .ref(DeserializeHelper.class) + .staticInvoke("deserializeItem") + .arg(parserParam) + .arg(relatedClass.dotclass()) + .arg(((JClass) propertyType).dotclass()))); + return definedClass; + } + + public static JDefinedClass generateSerializer( + JClass relatedClass, String keyMethod, String valueMethod) + throws JClassAlreadyExistsException { + JDefinedClass definedClass = GeneratorUtils.serializerClass(relatedClass); + GeneratorUtils.fillSerializer( + definedClass, + relatedClass, + (method, valueParam, genParam) -> { + JBlock body = method.body(); + body.invoke(genParam, "writeStartObject"); + body.invoke(genParam, "writeObjectField") + .arg(valueParam.invoke(keyMethod)) + .arg(valueParam.invoke(valueMethod)); + body.invoke(genParam, "writeEndObject"); + }); + return definedClass; + } + + private static JInvocation list(JDefinedClass definedClass, Collection list) { + JInvocation result = definedClass.owner().ref(List.class).staticInvoke("of"); + list.forEach(c -> result.arg(c.dotclass())); + return result; + } + + private GeneratorUtils() {} +} diff --git a/jackson-generator/src/main/java/io/serverlessworkflow/generator/jackson/JacksonMixInPojo.java b/jackson-generator/src/main/java/io/serverlessworkflow/generator/jackson/JacksonMixInPojo.java new file mode 100644 index 00000000..16df2a6a --- /dev/null +++ b/jackson-generator/src/main/java/io/serverlessworkflow/generator/jackson/JacksonMixInPojo.java @@ -0,0 +1,243 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.serverlessworkflow.generator.jackson; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.databind.Module.SetupContext; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.sun.codemodel.JClass; +import com.sun.codemodel.JClassAlreadyExistsException; +import com.sun.codemodel.JCodeModel; +import com.sun.codemodel.JDefinedClass; +import com.sun.codemodel.JExpr; +import com.sun.codemodel.JExpression; +import com.sun.codemodel.JMethod; +import com.sun.codemodel.JMod; +import com.sun.codemodel.JPackage; +import io.github.classgraph.ClassGraph; +import io.github.classgraph.ClassInfo; +import io.github.classgraph.ClassRefTypeSignature; +import io.github.classgraph.MethodInfo; +import io.github.classgraph.ScanResult; +import io.github.classgraph.TypeArgument; +import io.github.classgraph.TypeSignature; +import io.serverlessworkflow.annotations.AdditionalProperties; +import io.serverlessworkflow.annotations.GetterMethod; +import io.serverlessworkflow.annotations.Item; +import io.serverlessworkflow.annotations.ItemKey; +import io.serverlessworkflow.annotations.ItemValue; +import io.serverlessworkflow.annotations.Union; +import java.io.File; +import java.io.IOException; +import java.io.PrintStream; +import java.lang.annotation.Annotation; +import java.nio.file.Files; +import java.util.Collection; +import java.util.LinkedHashSet; +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.plugins.annotations.ResolutionScope; + +@Mojo( + name = "generate", + defaultPhase = LifecyclePhase.GENERATE_SOURCES, + requiresDependencyResolution = ResolutionScope.COMPILE, + threadSafe = true) +public class JacksonMixInPojo extends AbstractMojo { + + @Parameter( + property = "jacksonmixinpojo.outputDirectory", + defaultValue = "${project.build.directory}/generated-sources/jacksonmixinpojo") + private File outputDirectory; + + /** + * Package name used for generated Java classes (for types where a fully qualified name has not + * been supplied in the schema using the 'javaType' property). + * + * @since 0.1.0 + */ + @Parameter(property = "jsonschema2pojo.targetPackage") + private String targetPackage = ""; + + private static final String MIXIN_METHOD = "setMixInAnnotation"; + private static final String ADD_PROPERTIES_METHOD = "getAdditionalProperties"; + private static final String SETUP_METHOD = "setupModule"; + private JCodeModel codeModel; + private JPackage rootPackage; + private JMethod setupMethod; + + @FunctionalInterface + interface AnnotationProcessor { + void accept(ClassInfo classInfo, JDefinedClass definedClass) + throws JClassAlreadyExistsException; + } + + @Override + public void execute() throws MojoExecutionException, MojoFailureException { + + try (ScanResult result = + new ClassGraph() + .enableAnnotationInfo() + .enableMethodInfo() + .acceptPackages(targetPackage) + .scan()) { + codeModel = new JCodeModel(); + rootPackage = codeModel._package(targetPackage); + setupMethod = + rootPackage + ._class("JacksonMixInModule") + ._extends(SimpleModule.class) + .method(JMod.PUBLIC, codeModel.VOID, SETUP_METHOD); + processAnnotatedClasses(result, Union.class, this::buildUnionMixIn); + processAnnotatedClasses(result, AdditionalProperties.class, this::buildAdditionalPropsMixIn); + processAnnotatedClasses(result, Item.class, this::buildItemMixIn); + processAnnotatedClasses(result.getAllEnums(), this::buildEnumMixIn); + setupMethod + .body() + .invoke(JExpr._super(), SETUP_METHOD) + .arg(setupMethod.param(SetupContext.class, "context")); + Files.createDirectories(outputDirectory.toPath()); + codeModel.build(outputDirectory, (PrintStream) null); + } catch (JClassAlreadyExistsException | IOException e) { + getLog().error(e); + } + } + + private void processAnnotatedClasses( + Iterable classesInfo, AnnotationProcessor processor) + throws JClassAlreadyExistsException { + for (ClassInfo classInfo : classesInfo) { + setupMethod + .body() + .invoke(JExpr._super(), MIXIN_METHOD) + .arg(JExpr.dotclass(codeModel.ref(classInfo.getName()))) + .arg(processAnnotatedClass(classInfo, processor)); + } + } + + private void processAnnotatedClasses( + ScanResult result, Class annotation, AnnotationProcessor processor) + throws JClassAlreadyExistsException { + processAnnotatedClasses(result.getClassesWithAnnotation(annotation), processor); + } + + private JExpression processAnnotatedClass(ClassInfo classInfo, AnnotationProcessor processor) + throws JClassAlreadyExistsException { + JDefinedClass result = createMixInClass(classInfo); + processor.accept(classInfo, result); + return JExpr.dotclass(result); + } + + private void buildAdditionalPropsMixIn( + ClassInfo addPropsClassInfo, JDefinedClass addPropsMixClass) { + JClass mapStringObject = + getReturnType(addPropsClassInfo.getMethodInfo().getSingleMethod(ADD_PROPERTIES_METHOD)); + JClass objectType = mapStringObject.getTypeParameters().get(1); + addPropsMixClass + .method(JMod.ABSTRACT, mapStringObject, ADD_PROPERTIES_METHOD) + .annotate(JsonAnyGetter.class); + addPropsMixClass + .field(JMod.NONE, mapStringObject, "additionalProperties") + .annotate(JsonIgnore.class); + JMethod setter = + addPropsMixClass.method(JMod.ABSTRACT, codeModel.VOID, "setAdditionalProperty"); + setter.param(String.class, "name"); + setter.param(objectType, "value"); + setter.annotate(JsonAnySetter.class); + } + + private void buildItemMixIn(ClassInfo classInfo, JDefinedClass mixClass) + throws JClassAlreadyExistsException { + JClass relClass = codeModel.ref(classInfo.getName()); + MethodInfo keyMethod = + classInfo.getMethodInfo().filter(m -> m.hasAnnotation(ItemKey.class)).get(0); + MethodInfo valueMethod = + classInfo.getMethodInfo().filter(m -> m.hasAnnotation(ItemValue.class)).get(0); + mixClass + .annotate(JsonSerialize.class) + .param( + "using", + GeneratorUtils.generateSerializer( + relClass, keyMethod.getName(), valueMethod.getName())); + mixClass + .annotate(JsonDeserialize.class) + .param("using", GeneratorUtils.generateDeserializer(relClass, getReturnType(valueMethod))); + } + + private void buildUnionMixIn(ClassInfo unionClassInfo, JDefinedClass unionMixClass) + throws JClassAlreadyExistsException { + JClass unionClass = codeModel.ref(unionClassInfo.getName()); + unionMixClass + .annotate(JsonSerialize.class) + .param("using", GeneratorUtils.generateSerializer(unionClass)); + unionMixClass + .annotate(JsonDeserialize.class) + .param( + "using", + GeneratorUtils.generateDeserializer(unionClass, getUnionClasses(unionClassInfo))); + } + + private void buildEnumMixIn(ClassInfo classInfo, JDefinedClass mixClass) + throws JClassAlreadyExistsException { + mixClass.method(JMod.ABSTRACT, String.class, "value").annotate(JsonValue.class); + + JMethod staticMethod = + mixClass.method(JMod.STATIC, codeModel.ref(classInfo.getName()), "fromValue"); + staticMethod.param(String.class, "value"); + staticMethod.annotate(JsonCreator.class); + staticMethod.body()._return(JExpr._null()); + } + + private JDefinedClass createMixInClass(ClassInfo classInfo) throws JClassAlreadyExistsException { + return rootPackage._class(JMod.ABSTRACT, classInfo.getSimpleName() + "MixIn"); + } + + private Collection getUnionClasses(ClassInfo unionClassInfo) { + Collection result = new LinkedHashSet(); + unionClassInfo + .getMethodInfo() + .filter(f -> f.hasAnnotation(GetterMethod.class)) + .forEach(m -> result.add(getReturnType(m))); + return result; + } + + private JClass getReturnType(MethodInfo info) { + return getReturnType(info.getTypeSignatureOrTypeDescriptor().getResultType()); + } + + private JClass getReturnType(ClassRefTypeSignature refTypeSignature) { + JClass result = codeModel.ref(refTypeSignature.getFullyQualifiedClassName()); + for (TypeArgument t : refTypeSignature.getTypeArguments()) + result = result.narrow(getReturnType(t.getTypeSignature())); + return result; + } + + private JClass getReturnType(TypeSignature t) { + return t instanceof ClassRefTypeSignature refTypeSignature + ? getReturnType(refTypeSignature) + : codeModel.ref(t.toString()); + } +} diff --git a/pom.xml b/pom.xml index 271e10da..a187fbfe 100644 --- a/pom.xml +++ b/pom.xml @@ -42,6 +42,8 @@ impl serverlessworkflow-types serverlessworkflow-annotations + jackson-generator + serverlessworkflow-serialization diff --git a/serverlessworkflow-annotations/pom.xml b/serverlessworkflow-annotations/pom.xml index e37aa671..6e583ab9 100644 --- a/serverlessworkflow-annotations/pom.xml +++ b/serverlessworkflow-annotations/pom.xml @@ -7,14 +7,4 @@ Serverless Workflow :: Annotations serverlessworkflow-annotations - - - com.fasterxml.jackson.core - jackson-databind - - - jakarta.validation - jakarta.validation-api - - \ No newline at end of file diff --git a/serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/annotations/AdditionalProperties.java b/serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/annotations/AdditionalProperties.java new file mode 100644 index 00000000..69a3b023 --- /dev/null +++ b/serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/annotations/AdditionalProperties.java @@ -0,0 +1,26 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.serverlessworkflow.annotations; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Retention(RUNTIME) +@Target(TYPE) +public @interface AdditionalProperties {} diff --git a/serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/annotations/GetterMethod.java b/serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/annotations/GetterMethod.java new file mode 100644 index 00000000..1906f20b --- /dev/null +++ b/serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/annotations/GetterMethod.java @@ -0,0 +1,26 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.serverlessworkflow.annotations; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Retention(RUNTIME) +@Target(METHOD) +public @interface GetterMethod {} diff --git a/serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/annotations/Item.java b/serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/annotations/Item.java new file mode 100644 index 00000000..f42a86d5 --- /dev/null +++ b/serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/annotations/Item.java @@ -0,0 +1,26 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.serverlessworkflow.annotations; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Retention(RUNTIME) +@Target(TYPE) +public @interface Item {} diff --git a/serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/annotations/ItemKey.java b/serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/annotations/ItemKey.java new file mode 100644 index 00000000..ea75094d --- /dev/null +++ b/serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/annotations/ItemKey.java @@ -0,0 +1,26 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.serverlessworkflow.annotations; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Retention(RUNTIME) +@Target(METHOD) +public @interface ItemKey {} diff --git a/serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/annotations/ItemValue.java b/serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/annotations/ItemValue.java new file mode 100644 index 00000000..2aaf09e6 --- /dev/null +++ b/serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/annotations/ItemValue.java @@ -0,0 +1,26 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.serverlessworkflow.annotations; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Retention(RUNTIME) +@Target(METHOD) +public @interface ItemValue {} diff --git a/serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/annotations/Union.java b/serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/annotations/Union.java new file mode 100644 index 00000000..e9d3f2a8 --- /dev/null +++ b/serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/annotations/Union.java @@ -0,0 +1,26 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.serverlessworkflow.annotations; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Retention(RUNTIME) +@Target(ElementType.TYPE) +public @interface Union {} diff --git a/serverlessworkflow-serialization/pom.xml b/serverlessworkflow-serialization/pom.xml new file mode 100644 index 00000000..55787c00 --- /dev/null +++ b/serverlessworkflow-serialization/pom.xml @@ -0,0 +1,24 @@ + + 4.0.0 + + io.serverlessworkflow + serverlessworkflow-parent + 8.0.0-SNAPSHOT + + serverlessworkflow-serialization + + + io.serverlessworkflow + serverlessworkflow-annotations + ${project.version} + + + com.fasterxml.jackson.core + jackson-databind + + + jakarta.validation + jakarta.validation-api + + + \ No newline at end of file diff --git a/serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/serialization/DeserializeHelper.java b/serverlessworkflow-serialization/src/main/java/io/serverlessworkflow/serialization/DeserializeHelper.java similarity index 100% rename from serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/serialization/DeserializeHelper.java rename to serverlessworkflow-serialization/src/main/java/io/serverlessworkflow/serialization/DeserializeHelper.java diff --git a/serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/serialization/SerializeHelper.java b/serverlessworkflow-serialization/src/main/java/io/serverlessworkflow/serialization/SerializeHelper.java similarity index 100% rename from serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/serialization/SerializeHelper.java rename to serverlessworkflow-serialization/src/main/java/io/serverlessworkflow/serialization/SerializeHelper.java diff --git a/serverlessworkflow-types/pom.xml b/serverlessworkflow-types/pom.xml index 4fe9f9d2..90aa8996 100644 --- a/serverlessworkflow-types/pom.xml +++ b/serverlessworkflow-types/pom.xml @@ -13,6 +13,10 @@ serverlessworkflow-annotations ${project.version} + + jakarta.validation + jakarta.validation-api + @@ -40,10 +44,10 @@ true ${java.version} true - jackson2 + none true io.serverlessworkflow.generator.UnreferencedFactory - io.serverlessworkflow.generator.ConstAnnotator + io.serverlessworkflow.generator.CustomAnnotator From 7f62ffd880a8aa8628264b476c4f0ef86747c6d3 Mon Sep 17 00:00:00 2001 From: fjtirado Date: Mon, 14 Jul 2025 11:26:54 +0200 Subject: [PATCH 6/6] [Fix #634] Preserving union class order Signed-off-by: fjtirado --- .../generator/AllAnyOneOfSchemaRule.java | 5 ++-- .../generator/GeneratorUtils.java | 2 -- .../generator/jackson/JacksonMixInPojo.java | 18 +++++++------ .../annotations/GetterMethod.java | 26 ------------------- .../serverlessworkflow/annotations/Union.java | 4 ++- 5 files changed, 16 insertions(+), 39 deletions(-) delete mode 100644 serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/annotations/GetterMethod.java diff --git a/custom-generator/src/main/java/io/serverlessworkflow/generator/AllAnyOneOfSchemaRule.java b/custom-generator/src/main/java/io/serverlessworkflow/generator/AllAnyOneOfSchemaRule.java index 32dca0cd..a9823ce6 100644 --- a/custom-generator/src/main/java/io/serverlessworkflow/generator/AllAnyOneOfSchemaRule.java +++ b/custom-generator/src/main/java/io/serverlessworkflow/generator/AllAnyOneOfSchemaRule.java @@ -17,6 +17,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; +import com.sun.codemodel.JAnnotationArrayMember; import com.sun.codemodel.JBlock; import com.sun.codemodel.JClass; import com.sun.codemodel.JClassAlreadyExistsException; @@ -317,11 +318,11 @@ private JDefinedClass populateOneOf( commonType.orElse(definedClass.owner().ref(Object.class)), ruleFactory.getNameHelper().getPropertyName("value", null), null); - definedClass._implements( definedClass.owner().ref(OneOfValueProvider.class).narrow(valueField.type())); GeneratorUtils.implementInterface(definedClass, valueField); - definedClass.annotate(Union.class); + JAnnotationArrayMember unionAnnotation = definedClass.annotate(Union.class).paramArray("value"); + oneOfTypes.forEach(t -> unionAnnotation.param(t.getType())); return wrapAll(parentSchema, definedClass, commonType, oneOfTypes, Optional.of(valueField)); } diff --git a/custom-generator/src/main/java/io/serverlessworkflow/generator/GeneratorUtils.java b/custom-generator/src/main/java/io/serverlessworkflow/generator/GeneratorUtils.java index d330321b..abcf40eb 100644 --- a/custom-generator/src/main/java/io/serverlessworkflow/generator/GeneratorUtils.java +++ b/custom-generator/src/main/java/io/serverlessworkflow/generator/GeneratorUtils.java @@ -19,7 +19,6 @@ import com.sun.codemodel.JFieldVar; import com.sun.codemodel.JMethod; import com.sun.codemodel.JMod; -import io.serverlessworkflow.annotations.GetterMethod; import org.jsonschema2pojo.util.NameHelper; public class GeneratorUtils { @@ -39,7 +38,6 @@ public static JMethod getterMethod( instanceField.type(), nameHelper.getGetterName(name, instanceField.type(), null)); method.body()._return(instanceField); - method.annotate(GetterMethod.class); return method; } diff --git a/jackson-generator/src/main/java/io/serverlessworkflow/generator/jackson/JacksonMixInPojo.java b/jackson-generator/src/main/java/io/serverlessworkflow/generator/jackson/JacksonMixInPojo.java index 16df2a6a..b80238ed 100644 --- a/jackson-generator/src/main/java/io/serverlessworkflow/generator/jackson/JacksonMixInPojo.java +++ b/jackson-generator/src/main/java/io/serverlessworkflow/generator/jackson/JacksonMixInPojo.java @@ -33,6 +33,8 @@ import com.sun.codemodel.JMethod; import com.sun.codemodel.JMod; import com.sun.codemodel.JPackage; +import io.github.classgraph.AnnotationClassRef; +import io.github.classgraph.AnnotationInfo; import io.github.classgraph.ClassGraph; import io.github.classgraph.ClassInfo; import io.github.classgraph.ClassRefTypeSignature; @@ -41,7 +43,6 @@ import io.github.classgraph.TypeArgument; import io.github.classgraph.TypeSignature; import io.serverlessworkflow.annotations.AdditionalProperties; -import io.serverlessworkflow.annotations.GetterMethod; import io.serverlessworkflow.annotations.Item; import io.serverlessworkflow.annotations.ItemKey; import io.serverlessworkflow.annotations.ItemValue; @@ -52,7 +53,8 @@ import java.lang.annotation.Annotation; import java.nio.file.Files; import java.util.Collection; -import java.util.LinkedHashSet; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; @@ -216,12 +218,12 @@ private JDefinedClass createMixInClass(ClassInfo classInfo) throws JClassAlready } private Collection getUnionClasses(ClassInfo unionClassInfo) { - Collection result = new LinkedHashSet(); - unionClassInfo - .getMethodInfo() - .filter(f -> f.hasAnnotation(GetterMethod.class)) - .forEach(m -> result.add(getReturnType(m))); - return result; + AnnotationInfo info = unionClassInfo.getAnnotationInfoRepeatable(Union.class).get(0); + Object[] unionClasses = (Object[]) info.getParameterValues().getValue("value"); + return Stream.of(unionClasses) + .map(AnnotationClassRef.class::cast) + .map(ref -> codeModel.ref(ref.getName())) + .collect(Collectors.toList()); } private JClass getReturnType(MethodInfo info) { diff --git a/serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/annotations/GetterMethod.java b/serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/annotations/GetterMethod.java deleted file mode 100644 index 1906f20b..00000000 --- a/serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/annotations/GetterMethod.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.annotations; - -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -@Retention(RUNTIME) -@Target(METHOD) -public @interface GetterMethod {} diff --git a/serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/annotations/Union.java b/serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/annotations/Union.java index e9d3f2a8..e6cc4ecb 100644 --- a/serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/annotations/Union.java +++ b/serverlessworkflow-annotations/src/main/java/io/serverlessworkflow/annotations/Union.java @@ -23,4 +23,6 @@ @Retention(RUNTIME) @Target(ElementType.TYPE) -public @interface Union {} +public @interface Union { + Class[] value(); +} pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy