diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 49fd298..061e835 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -13,24 +13,30 @@ jobs: build: runs-on: ubuntu-latest + strategy: + matrix: + java-version: [ 8, 11, 15 ] steps: - uses: actions/checkout@v2 - - name: Set up JDK 1.8 + - name: Set up JDK uses: actions/setup-java@v1 with: - java-version: 1.8 + java-version: ${{ matrix.java-version }} - name: Compile with Maven run: mvn -T 1C clean generate-sources compile --file pom.xml test: runs-on: ubuntu-latest + strategy: + matrix: + java-version: [ 8, 11, 15 ] needs: [build] steps: - uses: actions/checkout@v2 - - name: Set up JDK 1.8 + - name: Set up JDK uses: actions/setup-java@v1 with: - java-version: 1.8 + java-version: ${{ matrix.java-version }} - name: Test with Maven run: mvn -T 1C test-compile test --file pom.xml @@ -39,10 +45,10 @@ jobs: needs: [build, test] steps: - uses: actions/checkout@v2 - - name: Set up JDK 1.8 + - name: Set up JDK 11 uses: actions/setup-java@v1 with: - java-version: 1.8 + java-version: 11 - name: SonarCloud Scan run: mvn clean test jacoco:report org.jacoco:jacoco-maven-plugin:prepare-agent sonar:sonar -Dsonar.projectKey=java-fluent-validator -Dsonar.organization=mvallim -Dsonar.host.url=https://sonarcloud.io -Dsonar.login=$SONAR_TOKEN env: diff --git a/README.md b/README.md index 3c01b83..bc3e734 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,8 @@ Validating data is a common task that occurs throughout any application, especially the business logic layer. As for some quite complex scenarios, often the same or similar validations are scattered everywhere, thus it is hard to reuse code and break the [DRY](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself) rule. +_**Compatible JDK 8, 11 and 15**_ + This library supports **`Kotlin`** aswell ## Sample diff --git a/documentation/1-quick-start.md b/documentation/1-quick-start.md index 066ed73..a17c3fd 100644 --- a/documentation/1-quick-start.md +++ b/documentation/1-quick-start.md @@ -12,7 +12,7 @@ You can pull it from the central Maven repositories: com.github.mvallim java-fluent-validator - 1.9.2 + 1.9.3 ``` diff --git a/pom.xml b/pom.xml index c886ad2..f924fa8 100644 --- a/pom.xml +++ b/pom.xml @@ -1,11 +1,12 @@ + 4.0.0 com.github.mvallim java-fluent-validator - 1.9.3-SNAPSHOT + 1.9.4-SNAPSHOT jar @@ -72,9 +73,9 @@ - org.codehaus.mojo + com.nickwongdev aspectj-maven-plugin - 1.11 + 1.12.6 adviceDidNotMatch=ignore ${java.version} @@ -107,7 +108,7 @@ org.jacoco jacoco-maven-plugin - 0.8.5 + 0.8.6 **/test/** @@ -366,4 +367,4 @@ - \ No newline at end of file + diff --git a/src/main/java/br/com/fluentvalidator/AbstractValidator.java b/src/main/java/br/com/fluentvalidator/AbstractValidator.java index 38e7b8e..e6d5afc 100644 --- a/src/main/java/br/com/fluentvalidator/AbstractValidator.java +++ b/src/main/java/br/com/fluentvalidator/AbstractValidator.java @@ -4,6 +4,7 @@ import java.util.Collections; import java.util.LinkedList; import java.util.List; +import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; import java.util.stream.Collectors; @@ -22,26 +23,49 @@ public abstract class AbstractValidator implements Validator { private final List> rules = new LinkedList<>(); - private final Runnable initialize; + private final Initializer initialize; private String property; private RuleProcessorStrategy ruleProcessor = RuleProcessorStrategy.getDefault(); - protected AbstractValidator() { - this.initialize = new Runnable() { - - private boolean initialized; - - @Override - public synchronized void run() { - if (!initialized) { - rules(); - this.initialized = true; + private static class Initializer { + + private final AtomicReference atomicReference = new AtomicReference<>(Boolean.FALSE); + + private final Validator validator; + + Initializer(final Validator validator) { + this.validator = validator; + } + + /** + * This method cause Race Condition. We are using Compare And Swap (CAS) + *

+ * {@link https://en.wikipedia.org/wiki/Race_condition} + * {@link https://en.wikipedia.org/wiki/Compare-and-swap} + */ + public void init() { + if (isNotInitialized()) { + synchronized (atomicReference) { + if (isNotInitialized()) { // double check if was initialized + validator.rules(); + final Boolean oldValue = atomicReference.get(); + final Boolean newValue = Boolean.TRUE; + atomicReference.compareAndSet(oldValue, newValue); + } } } + } + + private boolean isNotInitialized() { + return Boolean.FALSE.equals(atomicReference.get()); + } - }; + } + + protected AbstractValidator() { + this.initialize = new Initializer<>(this); } /** @@ -114,7 +138,7 @@ public List validate(final Collection instances, final ValidationResul */ @Override public boolean apply(final T instance) { - this.initialize.run(); + this.initialize.init(); ValidationContext.get().setProperty(this.property, instance); return ruleProcessor.process(instance, instance, rules); }