diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 4760699..f557afb 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -1,6 +1,10 @@ name: Java CI -on: [push] +on: + workflow_dispatch: + push: + pull_request: + branches: [ "master", "develop" ] jobs: build: @@ -8,16 +12,35 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - name: Set up JDK 1.8 - uses: actions/setup-java@v1 + - uses: actions/checkout@v3 + - name: Set up JDK 8 + uses: actions/setup-java@v3 with: - java-version: 1.8 - - name: Build with Maven - run: mvn -B package --file pom.xml - - name: Deploy to Github Package Registry + java-version: '8' + distribution: 'temurin' + server-id: sonatype-nexus-staging # Value of the distributionManagement/repository/id field of the pom.xml + server-username: CI_DEPLOY_USERNAME # env variable for username in deploy + server-password: CI_DEPLOY_PASSWORD # env variable for token in deploy + gpg-private-key: ${{ secrets.CI_GPG_PRIVATE_KEY }} # Value of the GPG private key to import + gpg-passphrase: CI_GPG_PASSPHRASE # env variable for GPG private key passphrase + + + - name: Install, unit test, integration test + run: mvn install -Dmaven.javadoc.skip=true -B -V + + - name: Release to maven central + if: github.ref_name == 'master' && github.event_name != 'pull_request' && github.repository == 'swisspost/jsonschema2pojo-openenum' + run: | + curl -s get.sdkman.io | bash + source "$HOME/.sdkman/bin/sdkman-init.sh" + sdk install groovy 3.0.8 + + chmod +x ./maybe-release.sh + ./maybe-release.sh env: - GITHUB_USERNAME: x-access-token - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: - mvn --settings settings.xml deploy + CI_DEPLOY_USERNAME: ${{ secrets.CI_DEPLOY_USERNAME }} + CI_DEPLOY_PASSWORD: ${{ secrets.CI_DEPLOY_PASSWORD }} + CI_GPG_PASSPHRASE: ${{ secrets.CI_GPG_PASSPHRASE }} + + - name: After release + run: bash <(curl -s https://codecov.io/bash) \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index fc3351e..0000000 --- a/.travis.yml +++ /dev/null @@ -1,22 +0,0 @@ -language: java -dist: trusty -jdk: - - oraclejdk8 -before_install: - - chmod +x maybe-release.sh - # install groovy - - curl -s get.sdkman.io | bash - - source "$HOME/.sdkman/bin/sdkman-init.sh" - - sdk install groovy 3.0.8 - - echo $(groovy --version) -install: - - mvn install -Dmaven.javadoc.skip=true -B -V -before_script: - - git config --global user.email "swisspush@post.ch" - - git config --global user.name "Travis-CI" -script: - - git config credential.helper "store --file=.git/credentials" - - echo "https://${GH_TOKEN}:@github.com" > .git/credentials - - ./maybe-release.sh -after_success: - - bash <(curl -s https://codecov.io/bash) diff --git a/README.md b/README.md index 6a704ec..1a48d78 100644 --- a/README.md +++ b/README.md @@ -4,13 +4,20 @@ Generate enums as relaxed type-safe enum classes supporting unknown values. This allows backward compatibility when JSON schemas get new enum values whereas existing code does not yet know them. +Public constant `declaredValues` allows to iterate on values known at compile time. +Instance method `isDeclaredValue` allows to detect values not yet known at compile time to an application. + The generated code looks like: ```java package org.swisspush.jsonschema2pojo.openenum; +import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; @@ -19,6 +26,11 @@ public class Status { private final static Map values = new HashMap(); public final static Status OPEN = Status.fromString("OPEN"); public final static Status CLOSED = Status.fromString("CLOSED"); + /** + * Set containing all enum values declared at compile time.use it in your application to iterate over declared values. + * + */ + public final static Set declaredValues = Collections.unmodifiableSet(new HashSet(Arrays.asList(Status.OPEN, Status.CLOSED))); private String value; private Status(String value) { @@ -37,6 +49,14 @@ public class Status { return this.value; } + /** + * returns true if this enum is part of the declared values. Use it in your application to detect when values coming from outside of the app are not yet part of the declared values (i.e.: there is a new version of the enum that your application is not yet aware of. + * + */ + public boolean isDeclaredValue() { + return Status.declaredValues.contains(this); + } + } ``` diff --git a/maybe-release.sh b/maybe-release.sh index 276dd9e..601421e 100644 --- a/maybe-release.sh +++ b/maybe-release.sh @@ -1,42 +1,34 @@ #!/bin/bash set -ev -if [ "$TRAVIS_BRANCH" == "master" ] && [ "$TRAVIS_PULL_REQUEST" == "false" ] && [ "$TRAVIS_REPO_SLUG" == "swisspush/jsonschema2pojo-openenum" ] +git fetch +git reset --hard +groovy staging.groovy drop +rc=$? +if [ $rc -ne 0 ] then - git reset --hard - git clean -fd - git checkout master - echo 'Master checked out' - groovy staging.groovy drop + echo 'problem when trying to drop, ignored' +fi +echo 'starting a new nexus repository ...' +OUTPUT=$(groovy staging.groovy start) +echo "repository Id: $OUTPUT" +mvn -B -Prelease jgitflow:release-start jgitflow:release-finish -DrepositoryId=${OUTPUT} +rc=$? +if [ $rc -eq 0 ] +then + groovy staging.groovy close ${OUTPUT} + groovy staging.groovy promote ${OUTPUT} rc=$? if [ $rc -ne 0 ] then - echo 'problem when trying to drop, ignored' - fi - echo 'starting a new nexus repository ...' - OUTPUT=$(groovy staging.groovy start) - echo "repository Id: $OUTPUT" - mvn -B -Prelease jgitflow:release-start jgitflow:release-finish --settings settings.xml -DrepositoryId=${OUTPUT} - rc=$? - if [ $rc -eq 0 ] - then - groovy staging.groovy close ${OUTPUT} - groovy staging.groovy promote ${OUTPUT} - rc=$? - if [ $rc -ne 0 ] - then - echo 'Release failed, cannot promote stage' - exit rc - fi - echo 'Release done, will push' - git tag - git push --tags - git checkout develop - git push origin develop - exit 0 + echo 'Release failed, cannot promote stage' + exit $rc fi - echo 'Release failed' - exit rc -else - echo 'Release skipped' - exit 0 -fi \ No newline at end of file + echo 'Release done, will push' + git tag + git push --tags + git checkout develop + git push origin develop + exit 0 +fi +echo 'Release failed' +exit $rc diff --git a/pom.xml b/pom.xml index 4db6de3..becd93f 100644 --- a/pom.xml +++ b/pom.xml @@ -1,12 +1,10 @@ - + 4.0.0 org.swisspush.jsonschema2pojo jsonschema2pojo-openenum - 0.1.3-SNAPSHOT + 0.1.4-SNAPSHOT jsonschema2pojo-openenum Config Builders for Kafka. A fluent API for configuring kafka clients. https://github.com/swisspush/jsonschema2pojo-openenum @@ -125,6 +123,10 @@ ${session.executionRootDirectory} 230584D7 + + --pinentry-mode + loopback + @@ -226,6 +228,10 @@ ${session.executionRootDirectory} 230584D7 + + --pinentry-mode + loopback + diff --git a/settings.xml b/settings.xml deleted file mode 100644 index 1bb3076..0000000 --- a/settings.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - github - - - - - github - - - central - https://repo1.maven.org/maven2 - - true - - - true - - - - github - GitHub OWNER Apache Maven Packages - https://maven.pkg.github.com/swisspush - - - - - - - - sonatype-nexus-staging - ${env.CI_DEPLOY_USERNAME} - ${env.CI_DEPLOY_PASSWORD} - - - gpg.passphrase - ${env.CI_PGP_PASSWORD} - - - github - ${env.GITHUB_USERNAME} - ${env.GITHUB_TOKEN} - - - diff --git a/src/main/java/org/swisspush/jsonschema2pojo/openenum/OpenEnumRule.java b/src/main/java/org/swisspush/jsonschema2pojo/openenum/OpenEnumRule.java index a77dc64..b5556e7 100644 --- a/src/main/java/org/swisspush/jsonschema2pojo/openenum/OpenEnumRule.java +++ b/src/main/java/org/swisspush/jsonschema2pojo/openenum/OpenEnumRule.java @@ -54,10 +54,11 @@ public JType apply(String nodeName, JsonNode node, JsonNode parent, JClassContai container.owner().ref(String.class); JMethod factoryMethod = addFactoryMethod(_enum, backingType); - addEnumConstants(node.path("enum"), _enum, node.path("javaEnumNames"), backingType, factoryMethod); + List enumConstants = addEnumConstants(node.path("enum"), _enum, node.path("javaEnumNames"), backingType, factoryMethod); + addConstantDeclaredValues(_enum, enumConstants); JFieldVar valueField = addValueField(_enum, backingType); addToString(_enum, valueField); - + addMethodIsDeclaredValue(_enum); return _enum; } @@ -149,8 +150,9 @@ private boolean isString(JType type){ return type.fullName().equals(String.class.getName()); } - private void addEnumConstants(JsonNode node, JDefinedClass _enum, JsonNode customNames, JType type, JMethod factoryMethod) { + private List addEnumConstants(JsonNode node, JDefinedClass _enum, JsonNode customNames, JType type, JMethod factoryMethod) { Collection existingConstantNames = new ArrayList<>(); + List enumConstants = new ArrayList<>(); for (int i = 0; i < node.size(); i++) { JsonNode value = node.path(i); @@ -162,8 +164,50 @@ private void addEnumConstants(JsonNode node, JDefinedClass _enum, JsonNode custo JFieldVar constant = _enum.field(JMod.PUBLIC | JMod.STATIC | JMod.FINAL, _enum, constantName); constant.init(_enum.staticInvoke(factoryMethod).arg(JExpr.lit(value.asText()))); + enumConstants.add(constant); } } + return enumConstants; + } + + /** + * Adds new constant declaredValues, which is a Set containing all enum value constants + * (i.e.: all enum values known at compile time). + * + * @param enumClass + * @param enumConstants + */ + private void addConstantDeclaredValues(JDefinedClass enumClass, List enumConstants) { + JClass fieldType = enumClass.owner().ref(Set.class).narrow(enumClass); + JFieldVar field = enumClass.field(JMod.PUBLIC | JMod.STATIC | JMod.FINAL, fieldType, "declaredValues"); + JClass fieldConcreteType = enumClass.owner().ref(HashSet.class).narrow(enumClass); + + JInvocation arraysAsListInvocation = enumClass.owner().ref(Arrays.class).staticInvoke("asList"); + // Add enum constants to the asListInvocation + for (JFieldVar constant : enumConstants) { + arraysAsListInvocation.arg(enumClass.staticRef(constant)); + } + + // construct HashSet using Arrays.asList() + JInvocation hashSetConstructorInvocation = JExpr._new(fieldConcreteType).arg(arraysAsListInvocation); + + // wrap HashSet into UnmodifiableSet + JInvocation unmodifiableSetInvocation = enumClass.owner().ref(Collections.class).staticInvoke("unmodifiableSet").arg(hashSetConstructorInvocation); + + // Initialize the field to unmodifiable set + field.init(unmodifiableSetInvocation); + + field.javadoc().add("Set containing all enum values declared at compile time."); + field.javadoc().add(" Use it in your application to iterate over declared values."); + } + + private void addMethodIsDeclaredValue(JDefinedClass _enum) { + JMethod method = _enum.method(JMod.PUBLIC, boolean.class, "isDeclaredValue"); + JExpression toReturn = _enum.staticRef("declaredValues").invoke("contains").arg(JExpr._this()); + method.body()._return(toReturn); + + method.javadoc().add("returns true if this enum is part of the declared values."); + method.javadoc().add(" Use it in your application to detect when values coming from outside of the app are not yet part of the declared values (i.e.: there is a new version of the enum that your application is not yet aware of."); } private String getEnumName(String nodeName, JsonNode node, JClassContainer container) { diff --git a/src/test/java/org/swisspush/jsonschema2pojo/openenum/OpenEnumRuleTest.java b/src/test/java/org/swisspush/jsonschema2pojo/openenum/OpenEnumRuleTest.java index 5444146..5d85820 100644 --- a/src/test/java/org/swisspush/jsonschema2pojo/openenum/OpenEnumRuleTest.java +++ b/src/test/java/org/swisspush/jsonschema2pojo/openenum/OpenEnumRuleTest.java @@ -42,8 +42,12 @@ public void testSimpleEnum() throws IOException { "\n" + "package org.swisspush.jsonschema2pojo.openenum;\n" + "\n" + + "import java.util.Arrays;\n" + + "import java.util.Collections;\n" + "import java.util.HashMap;\n" + + "import java.util.HashSet;\n" + "import java.util.Map;\n" + + "import java.util.Set;\n" + "import com.fasterxml.jackson.annotation.JsonCreator;\n" + "import com.fasterxml.jackson.annotation.JsonValue;\n" + "\n" + @@ -52,6 +56,11 @@ public void testSimpleEnum() throws IOException { " private final static Map values = new HashMap();\n" + " public final static Status OPEN = Status.fromString(\"OPEN\");\n" + " public final static Status CLOSED = Status.fromString(\"CLOSED\");\n" + + " /**\n" + + " * Set containing all enum values declared at compile time. Use it in your application to iterate over declared values.\n" + + " * \n" + + " */\n" + + " public final static Set declaredValues = Collections.unmodifiableSet(new HashSet(Arrays.asList(Status.OPEN, Status.CLOSED)));\n" + " private String value;\n" + "\n" + " private Status(String value) {\n" + @@ -70,6 +79,14 @@ public void testSimpleEnum() throws IOException { " return this.value;\n" + " }\n" + "\n" + + " /**\n" + + " * returns true if this enum is part of the declared values. Use it in your application to detect when values coming from outside of the app are not yet part of the declared values (i.e.: there is a new version of the enum that your application is not yet aware of.\n" + + " * \n" + + " */\n" + + " public boolean isDeclaredValue() {\n" + + " return Status.declaredValues.contains(this);\n" + + " }\n" + + "\n" + "}" + "\n"; @@ -98,8 +115,12 @@ public void testLowercaseValues() throws IOException { "\n" + "package org.swisspush.jsonschema2pojo.openenum;\n" + "\n" + + "import java.util.Arrays;\n" + + "import java.util.Collections;\n" + "import java.util.HashMap;\n" + + "import java.util.HashSet;\n" + "import java.util.Map;\n" + + "import java.util.Set;\n" + "import com.fasterxml.jackson.annotation.JsonCreator;\n" + "import com.fasterxml.jackson.annotation.JsonValue;\n" + "\n" + @@ -108,6 +129,11 @@ public void testLowercaseValues() throws IOException { " private final static Map values = new HashMap();\n" + " public final static Status OPEN = Status.fromString(\"open\");\n" + " public final static Status CLOSED = Status.fromString(\"closed\");\n" + + " /**\n" + + " * Set containing all enum values declared at compile time. Use it in your application to iterate over declared values.\n" + + " * \n" + + " */\n" + + " public final static Set declaredValues = Collections.unmodifiableSet(new HashSet(Arrays.asList(Status.OPEN, Status.CLOSED)));\n" + " private String value;\n" + "\n" + " private Status(String value) {\n" + @@ -126,6 +152,14 @@ public void testLowercaseValues() throws IOException { " return this.value;\n" + " }\n" + "\n" + + " /**\n" + + " * returns true if this enum is part of the declared values. Use it in your application to detect when values coming from outside of the app are not yet part of the declared values (i.e.: there is a new version of the enum that your application is not yet aware of.\n" + + " * \n" + + " */\n" + + " public boolean isDeclaredValue() {\n" + + " return Status.declaredValues.contains(this);\n" + + " }\n" + + "\n" + "}" + "\n"; diff --git a/src/test/java/org/swisspush/jsonschema2pojo/openenum/Status.java b/src/test/java/org/swisspush/jsonschema2pojo/openenum/Status.java index fef8492..dff19a2 100644 --- a/src/test/java/org/swisspush/jsonschema2pojo/openenum/Status.java +++ b/src/test/java/org/swisspush/jsonschema2pojo/openenum/Status.java @@ -1,7 +1,7 @@ package org.swisspush.jsonschema2pojo.openenum; -import java.util.HashMap; -import java.util.Map; +import java.util.*; + import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; @@ -10,6 +10,11 @@ public class Status { private final static Map values = new HashMap(); public final static Status OPEN = Status.fromString("OPEN"); public final static Status CLOSED = Status.fromString("CLOSED"); + /** + * Set containing all enum values declared at compile time. Use it in your application to iterate over declared values. + * + */ + public final static Set declaredValues = Collections.unmodifiableSet(new HashSet(Arrays.asList(Status.OPEN, Status.CLOSED))); private String value; private Status(String value) { @@ -28,4 +33,11 @@ public String toString() { return this.value; } + /** + * returns true if this enum is part of the declared values. Use it in your application to detect when values coming from outside of the app are not yet part of the declared values (i.e.: there is a new version of the enum that your application is not yet aware of. + * + */ + public Boolean isDeclaredValue() { + return Status.declaredValues.contains(this); + } } \ No newline at end of file diff --git a/src/test/java/org/swisspush/jsonschema2pojo/openenum/StatusTest.java b/src/test/java/org/swisspush/jsonschema2pojo/openenum/StatusTest.java index 64cfb00..834c463 100644 --- a/src/test/java/org/swisspush/jsonschema2pojo/openenum/StatusTest.java +++ b/src/test/java/org/swisspush/jsonschema2pojo/openenum/StatusTest.java @@ -12,4 +12,31 @@ public void testOpenEnumPattern() { assertNotSame(Status.CLOSED, Status.fromString("OTHER")); assertEquals(Status.OPEN.toString(), "OPEN"); } + + @Test + public void declaredValuesIsNotAffectedByFromStringCalls() { + assertEquals(2, Status.declaredValues.size()); + Status.fromString("OTHER"); + assertEquals(2, Status.declaredValues.size()); + } + + @Test(expected = UnsupportedOperationException.class) + public void declaredValuesIsNotModifiable() { + Status.declaredValues.add(Status.fromString("UNKNOWN")); + } + + @Test + public void iterateDeclaredValues() { + Status.declaredValues.forEach(System.out::println); + } + + @Test + public void isDeclaredValue() { + assertTrue(Status.OPEN.isDeclaredValue()); + assertTrue(Status.CLOSED.isDeclaredValue()); + assertTrue(Status.fromString("OPEN").isDeclaredValue()); + assertTrue(Status.fromString("CLOSED").isDeclaredValue()); + assertFalse(Status.fromString("NOT_DECLARED_VALUE").isDeclaredValue()); + assertFalse(Status.fromString("OTHER").isDeclaredValue()); + } }