diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 0000000..99000a4
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,14 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+Please provide a code example or even better a test to reproduce the bug.
diff --git a/.github/ISSUE_TEMPLATE/other-issue.md b/.github/ISSUE_TEMPLATE/other-issue.md
new file mode 100644
index 0000000..774bf32
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/other-issue.md
@@ -0,0 +1,10 @@
+---
+name: Other issue
+about: Generic issue
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+If you have a general question or seeking advice how to use something please create a new topic in our GitHub discussions forum: https://github.com/graphql-java/graphql-java/discussions. Thanks.
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..10ef831
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,10 @@
+version: 2
+updates:
+ - package-ecosystem: "gradle"
+ directory: "/"
+ schedule:
+ interval: "weekly"
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "weekly"
diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml
new file mode 100644
index 0000000..9c8d3b9
--- /dev/null
+++ b/.github/workflows/master.yml
@@ -0,0 +1,26 @@
+name: Master Build and Publish
+# For master push: Builds and publishes the development version to bintray/maven
+on:
+ push:
+ branches:
+ - master
+jobs:
+ buildAndPublish:
+ runs-on: ubuntu-latest
+ env:
+ MAVEN_CENTRAL_USER: ${{ secrets.MAVEN_CENTRAL_USER }}
+ MAVEN_CENTRAL_PASSWORD: ${{ secrets.MAVEN_CENTRAL_PASSWORD }}
+ MAVEN_CENTRAL_USER_NEW: ${{ secrets.MAVEN_CENTRAL_USER_NEW }}
+ MAVEN_CENTRAL_PASSWORD_NEW: ${{ secrets.MAVEN_CENTRAL_PASSWORD_NEW }}
+ MAVEN_CENTRAL_PGP_KEY: ${{ secrets.MAVEN_CENTRAL_PGP_KEY }}
+
+ steps:
+ - uses: actions/checkout@v5
+ - uses: gradle/actions/wrapper-validation@v5
+ - name: Set up JDK 11
+ uses: actions/setup-java@v4
+ with:
+ java-version: '11'
+ distribution: 'corretto'
+ - name: build test and publish
+ run: ./gradlew assemble && ./gradlew check --info && ./gradlew publishToSonatype closeAndReleaseSonatypeStagingRepository -x check --info --stacktrace
diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml
new file mode 100644
index 0000000..a841559
--- /dev/null
+++ b/.github/workflows/pull_request.yml
@@ -0,0 +1,22 @@
+name: Pull Request Build
+# For pull requests: builds and test
+on:
+ push:
+ branches:
+ - '!master'
+ pull_request:
+ branches:
+ - master
+jobs:
+ buildAndTest:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v5
+ - uses: gradle/actions/wrapper-validation@v5
+ - name: Set up JDK 11
+ uses: actions/setup-java@v4
+ with:
+ java-version: '11'
+ distribution: 'corretto'
+ - name: build and test
+ run: ./gradlew assemble && ./gradlew check --info --stacktrace
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 0000000..43f0035
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,30 @@
+name: Manual Release Build
+# Release builds
+on:
+ workflow_dispatch:
+ inputs:
+ version:
+ description: 'the version to be released'
+ required: true
+
+jobs:
+ buildAndPublish:
+ runs-on: ubuntu-latest
+ env:
+ MAVEN_CENTRAL_PGP_KEY: ${{ secrets.MAVEN_CENTRAL_PGP_KEY }}
+ MAVEN_CENTRAL_USER: ${{ secrets.MAVEN_CENTRAL_USER }}
+ MAVEN_CENTRAL_PASSWORD: ${{ secrets.MAVEN_CENTRAL_PASSWORD }}
+ MAVEN_CENTRAL_USER_NEW: ${{ secrets.MAVEN_CENTRAL_USER_NEW }}
+ MAVEN_CENTRAL_PASSWORD_NEW: ${{ secrets.MAVEN_CENTRAL_PASSWORD_NEW }}
+ RELEASE_VERSION: ${{ github.event.inputs.version }}
+
+ steps:
+ - uses: actions/checkout@v5
+ - uses: gradle/actions/wrapper-validation@v5
+ - name: Set up JDK 11
+ uses: actions/setup-java@v4
+ with:
+ java-version: '11'
+ distribution: 'corretto'
+ - name: build test and publish
+ run: ./gradlew assemble && ./gradlew check --info && ./gradlew publishToSonatype closeAndReleaseSonatypeStagingRepository -x check --info --stacktrace
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index ce92ecb..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,21 +0,0 @@
-dist: trusty
-language: java
-sudo: false
-
-jdk:
- - oraclejdk8
-
-addons:
- apt:
- packages:
- - oracle-java8-installer
-
-notifications:
- email: false
-
-branches:
- only:
- - master
-
-script:
-- ./gradlew clean test
diff --git a/README.md b/README.md
index 504ae12..1cc532b 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,10 @@
# Extended Validation for graphql-java
-[](https://api.travis-ci.org/graphql-java/graphql-java-extended-validation.svg?branch=master)
-[ ](https://bintray.com/graphql-java/graphql-java/graphql-java-extended-validation/_latestVersion)
-[](https://github.com/graphql-java/graphql-java-extended-validation/blob/master/LICENSE)
+[](https://github.com/graphql-java/graphql-java-extended-validation/actions/workflows/master.yml)
+[](https://maven-badges.herokuapp.com/maven-central/com.graphql-java/graphql-java-extended-validation/)
+[](https://maven-badges.herokuapp.com/maven-central/com.graphql-java/graphql-java-extended-validation/)
+[](https://github.com/graphql-java/graphql-java-extended-validation/blob/master/LICENSE.md)
@@ -17,26 +18,27 @@ This library provides extended validation of fields and field arguments for [gra
com.graphql-java
graphql-java-extended-validation
- 16.0.0
- pom
+ 24.0
```
```groovy
-compile 'com.graphql-java:graphql-java-extended-validation:16.0.0'
+implementation 'com.graphql-java:graphql-java-extended-validation:24.0'
```
> Note:
>
-> use 0.0.3 or below for graphql-java 13.x and below
+> use 24.0 or above for graphql-java 24.x and above
>
-> use 14.0.1 or above for graphql-java 14.x and above
+> use 22.0 or above for graphql-java 22.x and above
>
-> use 15.0.1 or above for graphql-java 15.x and above
->
-> use 16.0.0 or above for graphql-java 16.x and above
+> use 21.0 or above for graphql-java 21.x and above
+>
+> use 20.0 for graphql-java 20.x and above
+>
+> use 20.0-hibernate-validator-6.2.0.Final for graphql-java 20.x and SpringBoot 2.x support
-Its currently available from JCenter repo and Maven central.
+The library is currently available on Maven Central.
# SDL @Directive constraints
@@ -131,14 +133,13 @@ Like javax.validation, this library ships with some default error message templa
# I18n Locale Support
The validation library aims to offer Internationalisation (18N) of the error messages. When the validation rules
-run they are passed in a `java.util.Locale`. A `ResourceBundleMessageInterpolator` can then be used to build up messages
+run they are passed in a `java.util.Locale`. A `ResourceBundleMessageInterpolator` can then be used to build up messages
that come from I18N bundles.
-A `Locale` should be created per graphql execution. However at the time of writing graphql-java does not
-pass in a `Locale` per request `ExecutionInput` . A PR exists to fix this and it will be released in v14.0. This
-library will then be updated to to take advantage of this.
+A `Locale` should be created per graphql execution, and can be passed to `ExecutionInput`. More i18n is being added to graphql-java
+and later this library will then be updated to to take advantage of i18n.
-In the mean time you can work around this by having the `context`, `source` or `root` implement `graphql.validation.locale.LocaleProvider` and
+In the meantime you can work around this by having the `context`, `source` or `root` implement `graphql.validation.locale.LocaleProvider` and
the library will extract a `Locale` from that.
# Schema Directive Wiring
@@ -258,7 +259,7 @@ The boolean value must be false.
- Example : `updateDriver( isDrunk : Boolean @AssertFalse) : DriverDetails`
-- Applies to : `Boolean`
+- Applies to : `Boolean`, `Lists`
- SDL : `directive @AssertFalse(message : String = "graphql.validation.AssertFalse.message") on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION`
@@ -271,7 +272,7 @@ The boolean value must be true.
- Example : `driveCar( hasLicence : Boolean @AssertTrue) : DriverDetails`
-- Applies to : `Boolean`
+- Applies to : `Boolean`, `Lists`
- SDL : `directive @AssertTrue(message : String = "graphql.validation.AssertTrue.message") on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION`
@@ -284,7 +285,7 @@ The element must be a number whose value must be less than or equal to the speci
- Example : `driveCar( bloodAlcoholLevel : Float @DecimalMax(value : "0.05") : DriverDetails`
-- Applies to : `String`, `Byte`, `Short`, `Int`, `Long`, `BigDecimal`, `BigInteger`, `Float`
+- Applies to : `String`, `Byte`, `Short`, `Int`, `Long`, `BigDecimal`, `BigInteger`, `Float`, `Lists`
- SDL : `directive @DecimalMax(value : String!, inclusive : Boolean! = true, message : String = "graphql.validation.DecimalMax.message") on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION`
@@ -297,7 +298,7 @@ The element must be a number whose value must be greater than or equal to the sp
- Example : `driveCar( carHorsePower : Float @DecimalMin(value : "300.50") : DriverDetails`
-- Applies to : `String`, `Byte`, `Short`, `Int`, `Long`, `BigDecimal`, `BigInteger`, `Float`
+- Applies to : `String`, `Byte`, `Short`, `Int`, `Long`, `BigDecimal`, `BigInteger`, `Float`, `Lists`
- SDL : `directive @DecimalMin(value : String!, inclusive : Boolean! = true, message : String = "graphql.validation.DecimalMin.message") on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION`
@@ -310,9 +311,9 @@ The element must be a number inside the specified `integer` and `fraction` range
- Example : `buyCar( carCost : Float @Digits(integer : 5, fraction : 2) : DriverDetails`
-- Applies to : `String`, `Byte`, `Short`, `Int`, `Long`, `BigDecimal`, `BigInteger`, `Float`
+- Applies to : `String`, `Byte`, `Short`, `Int`, `Long`, `BigDecimal`, `BigInteger`, `Float`, `Lists`
-- SDL : `directive @Digits(integer : Int!, fraction : Int!, message : String = "graphql.validation.Digits.message") on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION`
+- SDL : `directive @Digits(integer : Int!, fraction : Int, message : String = "graphql.validation.Digits.message") on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION`
- Message : `graphql.validation.Digits.message`
@@ -337,7 +338,7 @@ The element must be a number whose value must be less than or equal to the speci
- Example : `driveCar( horsePower : Float @Max(value : 1000) : DriverDetails`
-- Applies to : `Byte`, `Short`, `Int`, `Long`, `BigDecimal`, `BigInteger`, `Float`
+- Applies to : `Byte`, `Short`, `Int`, `Long`, `BigDecimal`, `BigInteger`, `Float`, `Lists`
- SDL : `directive @Max(value : Int! = 2147483647, message : String = "graphql.validation.Max.message") on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION`
@@ -350,7 +351,7 @@ The element must be a number whose value must be greater than or equal to the sp
- Example : `driveCar( age : Int @Min(value : 18) : DriverDetails`
-- Applies to : `Byte`, `Short`, `Int`, `Long`, `BigDecimal`, `BigInteger`, `Float`
+- Applies to : `Byte`, `Short`, `Int`, `Long`, `BigDecimal`, `BigInteger`, `Float`, `Lists`
- SDL : `directive @Min(value : Int! = 0, message : String = "graphql.validation.Min.message") on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION`
@@ -363,7 +364,7 @@ The element must be a negative number.
- Example : `driveCar( lostLicencePoints : Int @Negative) : DriverDetails`
-- Applies to : `Byte`, `Short`, `Int`, `Long`, `BigDecimal`, `BigInteger`, `Float`
+- Applies to : `Byte`, `Short`, `Int`, `Long`, `BigDecimal`, `BigInteger`, `Float`, `Lists`
- SDL : `directive @Negative(message : String = "graphql.validation.Negative.message") on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION`
@@ -376,7 +377,7 @@ The element must be a negative number or zero.
- Example : `driveCar( lostLicencePoints : Int @NegativeOrZero) : DriverDetails`
-- Applies to : `Byte`, `Short`, `Int`, `Long`, `BigDecimal`, `BigInteger`, `Float`
+- Applies to : `Byte`, `Short`, `Int`, `Long`, `BigDecimal`, `BigInteger`, `Float`, `Lists`
- SDL : `directive @NegativeOrZero(message : String = "graphql.validation.NegativeOrZero.message") on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION`
@@ -389,7 +390,7 @@ The String must contain at least one non-whitespace character, according to Java
- Example : `updateAccident( accidentNotes : String @NotBlank) : DriverDetails`
-- Applies to : `String`, `ID`
+- Applies to : `String`, `ID`, `Lists`
- SDL : `directive @NotBlank(message : String = "graphql.validation.NotBlank.message") on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION`
@@ -398,16 +399,28 @@ The String must contain at least one non-whitespace character, according to Java
### @NotEmpty
-The element must have a non zero size.
+The element must have a non-zero size.
-- Example : `updateAccident( accidentNotes : [Notes]! @NotEmpty) : DriverDetails`
+- Example : `updateAccident( accidentNotes : String! @NotEmpty) : DriverDetails`
-- Applies to : `String`, `ID`, `Lists`, `Input Objects`
+- Applies to : `String`, `ID`, `Lists`
- SDL : `directive @NotEmpty(message : String = "graphql.validation.NotEmpty.message") on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION`
- Message : `graphql.validation.NotEmpty.message`
+### @ContainerNotEmpty
+
+The list or input object must have a non-zero size.
+
+- Example : `updateAccident( accidentNotes : [Notes]! @ContainerNotEmpty) : DriverDetails`
+
+- Applies to : `Lists`, `Input Objects`
+
+- SDL : `directive @ContainerNotEmpty(message : String = "graphql.validation.ContainerNotEmpty.message") on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION`
+
+- Message : `graphql.validation.ContainerNotEmpty.message`
+
### @Pattern
@@ -428,7 +441,7 @@ The element must be a positive number.
- Example : `driver( licencePoints : Int @Positive) : DriverDetails`
-- Applies to : `Byte`, `Short`, `Int`, `Long`, `BigDecimal`, `BigInteger`, `Float`
+- Applies to : `Byte`, `Short`, `Int`, `Long`, `BigDecimal`, `BigInteger`, `Float`, `Lists`
- SDL : `directive @Positive(message : String = "graphql.validation.Positive.message") on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION`
@@ -441,7 +454,7 @@ The element must be a positive number or zero.
- Example : `driver( licencePoints : Int @PositiveOrZero) : DriverDetails`
-- Applies to : `Byte`, `Short`, `Int`, `Long`, `BigDecimal`, `BigInteger`, `Float`
+- Applies to : `Byte`, `Short`, `Int`, `Long`, `BigDecimal`, `BigInteger`, `Float`, `Lists`
- SDL : `directive @PositiveOrZero(message : String = "graphql.validation.PositiveOrZero.message") on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION`
@@ -454,7 +467,7 @@ The element range must be between the specified `min` and `max` boundaries (incl
- Example : `driver( milesTravelled : Int @Range( min : 1000, max : 100000)) : DriverDetails`
-- Applies to : `String`, `Byte`, `Short`, `Int`, `Long`, `BigDecimal`, `BigInteger`, `Float`
+- Applies to : `String`, `Byte`, `Short`, `Int`, `Long`, `BigDecimal`, `BigInteger`, `Float`, `Lists`
- SDL : `directive @Range(min : Int = 0, max : Int = 2147483647, message : String = "graphql.validation.Range.message") on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION`
@@ -463,14 +476,26 @@ The element range must be between the specified `min` and `max` boundaries (incl
### @Size
-The element size must be between the specified `min` and `max` boundaries (inclusive).
+The string's size must be between the specified `min` and `max` boundaries (inclusive).
- Example : `updateDrivingNotes( drivingNote : String @Size( min : 1000, max : 100000)) : DriverDetails`
-- Applies to : `String`, `ID`, `Lists`, `Input Objects`
+- Applies to : `String`, `ID`, `Lists`
- SDL : `directive @Size(min : Int = 0, max : Int = 2147483647, message : String = "graphql.validation.Size.message") on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION`
- Message : `graphql.validation.Size.message`
+### @ContainerSize
+
+The list's or input object's size must be between the specified `min` and `max` boundaries (inclusive).
+
+- Example : `updateDrivingNotes( drivingNote : [String!]! @ContainerSize( min : 10, max : 20)) : DriverDetails`
+
+- Applies to : `Lists`, `Input Objects`
+
+- SDL : `directive @ContainerSize(min : Int = 0, max : Int = 2147483647, message : String = "graphql.validation.ContainerSize.message") on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION`
+
+- Message : `graphql.validation.ContainerSize.message`
+
diff --git a/build.gradle b/build.gradle
index 62b04c3..d1d94fb 100644
--- a/build.gradle
+++ b/build.gradle
@@ -2,14 +2,14 @@ import java.text.SimpleDateFormat
plugins {
- id "com.jfrog.bintray" version "1.8.5"
+ id 'java'
+ id 'groovy'
+ id 'java-library'
+ id 'maven-publish'
+ id 'signing'
+ id "io.github.gradle-nexus.publish-plugin" version "2.0.0"
}
-apply plugin: 'java'
-apply plugin: 'groovy'
-apply plugin: 'maven-publish'
-apply plugin: 'com.jfrog.bintray'
-
def getDevelopmentVersion() {
def output = new StringBuilder()
def error = new StringBuilder()
@@ -20,35 +20,33 @@ def getDevelopmentVersion() {
println "git hash is empty: error: ${error.toString()}"
throw new IllegalStateException("git hash could not be determined")
}
- new SimpleDateFormat('yyyy-MM-dd\'T\'HH-mm-ss').format(new Date()) + "-" + gitHash
+ "0.0.0-" + new SimpleDateFormat('yyyy-MM-dd\'T\'HH-mm-ss').format(new Date()) + "-" + gitHash
}
-
-def releaseVersion = System.properties.RELEASE_VERSION
-println "Building version = " + releaseVersion
+def releaseVersion = System.env.RELEASE_VERSION
version = releaseVersion ? releaseVersion : getDevelopmentVersion()
+println "Building version = " + version
group = 'com.graphql-java'
-sourceCompatibility = 1.8
-targetCompatibility = 1.8
+java {
+ toolchain {
+ languageVersion = JavaLanguageVersion.of(11)
+ }
+}
repositories {
mavenCentral()
- maven { url "http://dl.bintray.com/andimarek/graphql-java" }
+ mavenLocal()
}
-
dependencies {
- compile "com.graphql-java:graphql-java:16.1"
- compile 'org.slf4j:slf4j-api:1.7.30'
- compile "jakarta.validation:jakarta.validation-api:2.0.2"
- compile "org.hibernate.validator:hibernate-validator:6.1.6.Final"
- compile "jakarta.el:jakarta.el-api:3.0.3"
- compile "org.glassfish:jakarta.el:3.0.3"
-
- testCompile 'org.slf4j:slf4j-simple:1.7.30'
- testCompile 'org.spockframework:spock-core:1.3-groovy-2.5'
- testCompile 'org.codehaus.groovy:groovy-all:2.5.11'
+ api "com.graphql-java:graphql-java:24.3"
+ api "com.graphql-java:graphql-java-extended-scalars:24.0"
+ api "org.hibernate.validator:hibernate-validator:7.0.1.Final"
+ api "org.glassfish:jakarta.el:4.0.2"
+
+ testImplementation 'org.spockframework:spock-core:2.3-groovy-3.0'
+ testImplementation 'org.codehaus.groovy:groovy-all:3.0.25'
}
task sourcesJar(type: Jar, dependsOn: classes) {
@@ -66,6 +64,12 @@ artifacts {
archives javadocJar
}
+test {
+ testLogging {
+ exceptionFormat = 'full'
+ }
+}
+
publishing {
publications {
maven(MavenPublication) {
@@ -81,7 +85,7 @@ publishing {
asNode().children().last() + {
resolveStrategy = Closure.DELEGATE_FIRST
name 'graphql-java-extended-validation'
- description 'A library fo extended validation for graphql-java'
+ description 'A library of extended validation for graphql-java'
url 'https://github.com/graphql-java/graphql-java-extended-validation'
inceptionYear '2019'
@@ -112,24 +116,25 @@ publishing {
}
}
-bintray {
- user = System.getenv('BINTRAY_USER')
- key = System.getenv('BINTRAY_API_KEY')
- publications = ['maven']
- publish = true
- pkg {
- userOrg = 'graphql-java'
- repo = 'graphql-java'
- name = "graphql-java-extended-validation"
- desc = 'A library fo extended validation for graphql-java'
- licenses = ['MIT']
- vcsUrl = 'https://github.com/graphql-java/graphql-java-extended-validation.git'
- version {
- released = new Date()
- vcsTag = project.version
- gpg {
- sign = true
- }
- }
+nexusPublishing {
+ repositories {
+ sonatype {
+ username = System.env.MAVEN_CENTRAL_USER_NEW
+ password = System.env.MAVEN_CENTRAL_PASSWORD_NEW
+ // https://central.sonatype.org/publish/publish-portal-ossrh-staging-api/#configuration
+ nexusUrl.set(uri("https://ossrh-staging-api.central.sonatype.com/service/local/"))
+ // GraphQL Java does not publish snapshots, but adding this URL for completeness
+ snapshotRepositoryUrl.set(uri("https://central.sonatype.com/repository/maven-snapshots/")) }
}
}
+
+signing {
+ def signingKey = System.env.MAVEN_CENTRAL_PGP_KEY
+ useInMemoryPgpKeys(signingKey, "")
+ sign publishing.publications
+}
+
+// all publish tasks depend on the build task
+tasks.withType(PublishToMavenRepository) {
+ dependsOn build
+}
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 29953ea..7454180 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index ee69dd6..db9a6b8 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index cccdd3d..744e882 100755
--- a/gradlew
+++ b/gradlew
@@ -1,5 +1,21 @@
#!/usr/bin/env sh
+#
+# Copyright 2015 the original author or 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
+#
+# https://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.
+#
+
##############################################################################
##
## Gradle start up script for UN*X
@@ -28,7 +44,7 @@ APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS=""
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
@@ -56,7 +72,7 @@ case "`uname`" in
Darwin* )
darwin=true
;;
- MINGW* )
+ MSYS* | MINGW* )
msys=true
;;
NONSTOP* )
@@ -66,6 +82,7 @@ esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
@@ -109,10 +126,11 @@ if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
-# For Cygwin, switch paths to Windows format before running java
-if $cygwin ; then
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
@@ -138,19 +156,19 @@ if $cygwin ; then
else
eval `echo args$i`="\"$arg\""
fi
- i=$((i+1))
+ i=`expr $i + 1`
done
case $i in
- (0) set -- ;;
- (1) set -- "$args0" ;;
- (2) set -- "$args0" "$args1" ;;
- (3) set -- "$args0" "$args1" "$args2" ;;
- (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
- (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
- (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
- (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
- (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
- (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
@@ -159,14 +177,9 @@ save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
-APP_ARGS=$(save "$@")
+APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
-# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
-if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
- cd "$(dirname "$0")"
-fi
-
exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
index f955316..ac1b06f 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -1,84 +1,89 @@
-@if "%DEBUG%" == "" @echo off
-@rem ##########################################################################
-@rem
-@rem Gradle startup script for Windows
-@rem
-@rem ##########################################################################
-
-@rem Set local scope for the variables with windows NT shell
-if "%OS%"=="Windows_NT" setlocal
-
-set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
-set APP_BASE_NAME=%~n0
-set APP_HOME=%DIRNAME%
-
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS=
-
-@rem Find java.exe
-if defined JAVA_HOME goto findJavaFromJavaHome
-
-set JAVA_EXE=java.exe
-%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
-
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:findJavaFromJavaHome
-set JAVA_HOME=%JAVA_HOME:"=%
-set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-
-if exist "%JAVA_EXE%" goto init
-
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:init
-@rem Get command-line arguments, handling Windows variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-
-:execute
-@rem Setup the command line
-
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
-
-@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
-
-:end
-@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
-
-:fail
-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
-rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
-
-:mainEnd
-if "%OS%"=="Windows_NT" endlocal
-
-:omega
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/src/main/java/graphql/validation/constraints/AbstractDirectiveConstraint.java b/src/main/java/graphql/validation/constraints/AbstractDirectiveConstraint.java
index 698d589..3cfd0e9 100644
--- a/src/main/java/graphql/validation/constraints/AbstractDirectiveConstraint.java
+++ b/src/main/java/graphql/validation/constraints/AbstractDirectiveConstraint.java
@@ -4,8 +4,9 @@
import graphql.GraphQLError;
import graphql.PublicSpi;
import graphql.Scalars;
+import graphql.schema.GraphQLAppliedDirective;
+import graphql.schema.GraphQLAppliedDirectiveArgument;
import graphql.schema.GraphQLArgument;
-import graphql.schema.GraphQLDirective;
import graphql.schema.GraphQLFieldDefinition;
import graphql.schema.GraphQLFieldsContainer;
import graphql.schema.GraphQLInputObjectType;
@@ -20,11 +21,13 @@
import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import static graphql.schema.GraphQLTypeUtil.isList;
import static graphql.validation.rules.ValidationEnvironment.ValidatedElement.FIELD;
@@ -70,10 +73,18 @@ public boolean appliesTo(GraphQLArgument argument, GraphQLFieldDefinition fieldD
boolean hasNamedDirective = directive.getName().equals(this.getName());
if (hasNamedDirective) {
inputType = Util.unwrapNonNull(inputType);
- boolean appliesToType = appliesToType(inputType);
+
+ boolean appliesToType;
+ if (appliesToListElements()) {
+ appliesToType = appliesToType((GraphQLInputType) GraphQLTypeUtil.unwrapAll(inputType));
+ } else {
+ appliesToType = appliesToType(inputType);
+ }
+
if (appliesToType) {
return true;
}
+
// if they have a @Directive on there BUT it can't handle that type
// then is a really bad situation
String argType = GraphQLTypeUtil.simplePrint(inputType);
@@ -88,7 +99,6 @@ public boolean appliesTo(GraphQLArgument argument, GraphQLFieldDefinition fieldD
* A derived class will be called to indicate whether this input type applies to the constraint
*
* @param inputType the input type
- *
* @return true if the constraint can handle that type
*/
abstract protected boolean appliesToType(GraphQLInputType inputType);
@@ -97,22 +107,20 @@ public boolean appliesTo(GraphQLArgument argument, GraphQLFieldDefinition fieldD
* This is called to perform the constraint validation
*
* @param validationEnvironment the validation environment
- *
* @return a list of errors or an empty one if there are no errors
*/
abstract protected List runConstraint(ValidationEnvironment validationEnvironment);
- @SuppressWarnings("unchecked")
@Override
public List runValidation(ValidationEnvironment validationEnvironment) {
+ Object validatedValue = validationEnvironment.getValidatedValue();
// output fields are special
if (validationEnvironment.getValidatedElement() == FIELD) {
- return runFieldValidationImpl(validationEnvironment);
+ return runValidationImpl(validationEnvironment);
}
- Object validatedValue = validationEnvironment.getValidatedValue();
//
// all the directives validation code does NOT care for NULL ness since the graphql engine covers that.
// eg a @NonNull validation directive makes no sense in graphql like it might in Java
@@ -124,50 +132,60 @@ public List runValidation(ValidationEnvironment validationEnvironm
GraphQLInputType inputType = Util.unwrapNonNull(validationEnvironment.getValidatedType());
validationEnvironment = validationEnvironment.transform(b -> b.validatedType(inputType));
- return runValidationImpl(validationEnvironment, inputType, validatedValue);
+ return runValidationImpl(validationEnvironment);
}
- private List runFieldValidationImpl(ValidationEnvironment validationEnvironment) {
- return runConstraintOnDirectives(validationEnvironment);
- }
-
- @SuppressWarnings("unchecked")
- private List runValidationImpl(ValidationEnvironment validationEnvironment, GraphQLInputType inputType, Object validatedValue) {
+ private List runValidationImpl(ValidationEnvironment validationEnvironment) {
return runConstraintOnDirectives(validationEnvironment);
}
private List runConstraintOnDirectives(ValidationEnvironment validationEnvironment) {
List errors = new ArrayList<>();
- List directives = validationEnvironment.getDirectives();
- directives = Util.sort(directives, GraphQLDirective::getName);
+ List directives = validationEnvironment.getDirectives();
+ directives = Util.sort(directives, GraphQLAppliedDirective::getName);
- for (GraphQLDirective directive : directives) {
+ for (GraphQLAppliedDirective directive : directives) {
// we get called for arguments and input field and field types which can have multiple directive constraints on them and hence no just for this one
boolean isOurDirective = directive.getName().equals(this.getName());
if (!isOurDirective) {
continue;
}
- validationEnvironment = validationEnvironment.transform(b -> b.context(GraphQLDirective.class, directive));
+ validationEnvironment = validationEnvironment.transform(b -> b.context(GraphQLAppliedDirective.class, directive));
//
// now run the directive rule with this directive instance
- List ruleErrors = this.runConstraint(validationEnvironment);
+ List ruleErrors = this.runConstrainOnPossibleListElements(validationEnvironment);
errors.addAll(ruleErrors);
}
+
return errors;
}
+ private List runConstrainOnPossibleListElements(ValidationEnvironment validationEnvironment) {
+ if (appliesToListElements()) {
+ final GraphQLListElementValidator validator = new GraphQLListElementValidator();
+ return validator.runConstraintOnListElements(validationEnvironment, this::runConstraint);
+ }
+
+ return runConstraint(validationEnvironment);
+ }
+
+ protected abstract boolean appliesToListElements();
+
+
+ protected boolean isOneOfTheseTypes(GraphQLInputType inputType, GraphQLScalarType... scalarTypes) {
+ return isOneOfTheseTypes(inputType, Arrays.asList(scalarTypes));
+ }
/**
* Returns true of the input type is one of the specified scalar types, regardless of non null ness
*
* @param inputType the type to check
* @param scalarTypes the array of scalar types
- *
* @return true if its one of them
*/
- protected boolean isOneOfTheseTypes(GraphQLInputType inputType, GraphQLScalarType... scalarTypes) {
+ protected boolean isOneOfTheseTypes(GraphQLInputType inputType, Collection scalarTypes) {
GraphQLInputType type = Util.unwrapNonNull(inputType);
if (type instanceof GraphQLNamedInputType) {
final GraphQLNamedInputType unwrappedType = (GraphQLNamedInputType) type;
@@ -181,47 +199,45 @@ protected boolean isOneOfTheseTypes(GraphQLInputType inputType, GraphQLScalarTyp
}
/**
- * Returns an integer argument from a directive (or its default) and throws an assertion of the argument is null
+ * Returns an integer argument from a directive (or its default) and throws an assertion if the argument is null
*
* @param directive the directive to check
* @param argName the argument name
- *
* @return a non null value
*/
- protected int getIntArg(GraphQLDirective directive, String argName) {
- GraphQLArgument argument = directive.getArgument(argName);
- if (argument == null) {
- return assertExpectedArgType(argName, "Int");
- }
- Number value = (Number) argument.getValue();
- if (value == null) {
- value = (Number) argument.getDefaultValue();
- if (value == null) {
- return assertExpectedArgType(argName, "Int");
- }
- }
- return value.intValue();
+ protected int getIntArg(GraphQLAppliedDirective directive, String argName) {
+ return getIntArgOpt(directive, argName)
+ .orElseGet(() -> assertExpectedArgType(argName, "Int"));
}
/**
- * Returns an String argument from a directive (or its default) and throws an assertion of the argument is null
+ * Returns an optional integer argument from a directive (or its default), or empty Optional if the argument is null.
*
* @param directive the directive to check
* @param argName the argument name
+ * @return an optional null value
+ */
+ protected Optional getIntArgOpt(GraphQLAppliedDirective directive, String argName) {
+ return Optional.ofNullable(directive.getArgument(argName))
+ .map(GraphQLAppliedDirectiveArgument::getValue)
+ .map(Number::intValue);
+ }
+
+ /**
+ * Returns an String argument from a directive (or its default) and throws an assertion of the argument is null
*
+ * @param directive the directive to check
+ * @param argName the argument name
* @return a non null value
*/
- protected String getStrArg(GraphQLDirective directive, String argName) {
- GraphQLArgument argument = directive.getArgument(argName);
+ protected String getStrArg(GraphQLAppliedDirective directive, String argName) {
+ GraphQLAppliedDirectiveArgument argument = directive.getArgument(argName);
if (argument == null) {
return assertExpectedArgType(argName, "String");
}
- String value = (String) argument.getValue();
+ String value = argument.getValue();
if (value == null) {
- value = (String) argument.getDefaultValue();
- if (value == null) {
- return assertExpectedArgType(argName, "String");
- }
+ return assertExpectedArgType(argName, "String");
}
return value;
}
@@ -231,20 +247,16 @@ protected String getStrArg(GraphQLDirective directive, String argName) {
*
* @param directive the directive to check
* @param argName the argument name
- *
* @return a non null value
*/
- protected boolean getBoolArg(GraphQLDirective directive, String argName) {
- GraphQLArgument argument = directive.getArgument(argName);
+ protected boolean getBoolArg(GraphQLAppliedDirective directive, String argName) {
+ GraphQLAppliedDirectiveArgument argument = directive.getArgument(argName);
if (argument == null) {
return assertExpectedArgType(argName, "Boolean");
}
Object value = argument.getValue();
if (value == null) {
- value = argument.getDefaultValue();
- if (value == null) {
- return assertExpectedArgType(argName, "Boolean");
- }
+ return assertExpectedArgType(argName, "Boolean");
}
return Boolean.parseBoolean(String.valueOf(value));
}
@@ -254,17 +266,13 @@ protected boolean getBoolArg(GraphQLDirective directive, String argName) {
* called "graphql.validation.{name}.message"
*
* @param directive the directive to check
- *
* @return a non null value
*/
- protected String getMessageTemplate(GraphQLDirective directive) {
+ protected String getMessageTemplate(GraphQLAppliedDirective directive) {
String msg = null;
- GraphQLArgument arg = directive.getArgument("message");
+ GraphQLAppliedDirectiveArgument arg = directive.getArgument("message");
if (arg != null) {
- msg = (String) arg.getValue();
- if (msg == null) {
- msg = (String) arg.getDefaultValue();
- }
+ msg = arg.getValue();
}
if (msg == null) {
msg = "graphql.validation." + getName() + ".message";
@@ -278,7 +286,6 @@ protected String getMessageTemplate(GraphQLDirective directive) {
* @param validatedValue the value being validated
* @param validationEnvironment the validation environment
* @param args must be an key / value array with String keys as the even params and values as then odd params
- *
* @return a map of message parameters
*/
protected Map mkMessageParams(Object validatedValue, ValidationEnvironment validationEnvironment, Object... args) {
@@ -298,34 +305,54 @@ protected Map mkMessageParams(Object validatedValue, ValidationE
* @param validationEnvironment the current validation environment
* @param directive the directive being run
* @param msgParams the map of parameters
- *
* @return a list of a single error
*/
- protected List mkError(ValidationEnvironment validationEnvironment, GraphQLDirective directive, Map msgParams) {
+ protected List mkError(ValidationEnvironment validationEnvironment, GraphQLAppliedDirective directive, Map msgParams) {
String messageTemplate = getMessageTemplate(directive);
GraphQLError error = validationEnvironment.getInterpolator().interpolate(messageTemplate, msgParams, validationEnvironment);
return singletonList(error);
}
+ protected List mkError(ValidationEnvironment validationEnvironment, Object... messageParameters) {
+ GraphQLAppliedDirective directive = validationEnvironment.getContextObject(GraphQLAppliedDirective.class);
+ String messageTemplate = getMessageTemplate(directive);
+ Object validatedValue = validationEnvironment.getValidatedValue();
+ GraphQLError error = validationEnvironment.getInterpolator().interpolate(messageTemplate, mkMessageParams(validatedValue, validationEnvironment, messageParameters), validationEnvironment);
+ return singletonList(error);
+ }
+
/**
- * Return true if the type is a String or ID or List type or {@link graphql.schema.GraphQLInputObjectType}, regardless of non null ness
+ * Return true if the type is a String or ID or List type, regardless of non null ness
*
* @param inputType the type to check
+ * @return true if one of the above
+ */
+ protected boolean isStringOrIDOrList(GraphQLInputType inputType) {
+ return isStringOrID(inputType) ||
+ isList(inputType);
+ }
+
+ /**
+ * Return true if the type is a String or ID or List type or {@link graphql.schema.GraphQLInputObjectType}, regardless of non null ness
*
+ * @param inputType the type to check
* @return true if one of the above
*/
protected boolean isStringOrIDOrListOrMap(GraphQLInputType inputType) {
- GraphQLInputType unwrappedType = Util.unwrapOneAndAllNonNull(inputType);
return isStringOrID(inputType) ||
isList(inputType) ||
- (unwrappedType instanceof GraphQLInputObjectType);
+ isMap(inputType);
+ }
+
+ protected boolean isMap(GraphQLInputType inputType) {
+ GraphQLInputType unwrappedType = Util.unwrapOneAndAllNonNull(inputType);
+ return (unwrappedType instanceof GraphQLInputObjectType);
}
/**
* Return true if the type is a String or ID
*
* @param inputType the type to check
- *
* @return true if one of the above
*/
protected boolean isStringOrID(GraphQLInputType inputType) {
@@ -337,7 +364,6 @@ protected boolean isStringOrID(GraphQLInputType inputType) {
* Casts the object as a Map with an assertion of it is not one
*
* @param value the object to turn into a map
- *
* @return a Map
*/
@SuppressWarnings("ConstantConditions")
@@ -350,7 +376,6 @@ protected Map asMap(Object value) {
* Makes the object a BigDecimal with an assertion if we have no conversion of it
*
* @param value the object to turn into a BigDecimal
- *
* @return a BigDecimal
*/
protected BigDecimal asBigDecimal(Object value) throws NumberFormatException {
@@ -375,7 +400,6 @@ protected BigDecimal asBigDecimal(Object value) throws NumberFormatException {
* Makes the object a boolean with an assertion if we have no conversion of it
*
* @param value the boolean object
- *
* @return a boolean
*/
protected boolean asBoolean(Object value) {
@@ -394,7 +418,6 @@ protected boolean asBoolean(Object value) {
*
* @param inputType the input type
* @param value the value
- *
* @return the length of a String or Map or List
*/
protected int getStringOrIDOrObjectOrMapLength(GraphQLInputType inputType, Object value) {
diff --git a/src/main/java/graphql/validation/constraints/DirectiveConstraints.java b/src/main/java/graphql/validation/constraints/DirectiveConstraints.java
index 7c91471..a775d41 100644
--- a/src/main/java/graphql/validation/constraints/DirectiveConstraints.java
+++ b/src/main/java/graphql/validation/constraints/DirectiveConstraints.java
@@ -7,6 +7,8 @@
import graphql.schema.idl.TypeDefinitionRegistry;
import graphql.validation.constraints.standard.AssertFalseConstraint;
import graphql.validation.constraints.standard.AssertTrueConstraint;
+import graphql.validation.constraints.standard.ContainerNotEmptyConstraint;
+import graphql.validation.constraints.standard.ContainerSizeConstraint;
import graphql.validation.constraints.standard.DecimalMaxConstraint;
import graphql.validation.constraints.standard.DecimalMinConstraint;
import graphql.validation.constraints.standard.DigitsConstraint;
@@ -61,7 +63,10 @@ public class DirectiveConstraints {
new PositiveOrZeroConstraint(),
new PositiveConstraint(),
new RangeConstraint(),
- new SizeConstraint()
+ new SizeConstraint(),
+ new ContainerSizeConstraint(),
+ new ContainerNotEmptyConstraint()
+
);
private final Map constraints;
diff --git a/src/main/java/graphql/validation/constraints/Documentation.java b/src/main/java/graphql/validation/constraints/Documentation.java
index 355dba0..d1c746a 100644
--- a/src/main/java/graphql/validation/constraints/Documentation.java
+++ b/src/main/java/graphql/validation/constraints/Documentation.java
@@ -1,10 +1,11 @@
package graphql.validation.constraints;
+import graphql.schema.GraphQLNamedType;
import graphql.schema.idl.SchemaParser;
import graphql.schema.idl.TypeDefinitionRegistry;
-
import java.util.Arrays;
import java.util.List;
+import java.util.stream.Collectors;
public class Documentation {
@@ -80,14 +81,23 @@ public Builder messageTemplate(String messageTemplate) {
return this;
}
+ public Builder applicableTypes(List extends GraphQLNamedType> applicableTypes) {
+ this.applicableTypeNames = applicableTypes.stream().map(GraphQLNamedType::getName).collect(Collectors.toList());
+ return this;
+ }
+
+ public Builder applicableTypes(GraphQLNamedType... applicableTypes) {
+ return applicableTypes(Arrays.asList(applicableTypes));
+ }
+
+
public Builder applicableTypeNames(List applicableTypeNames) {
this.applicableTypeNames = applicableTypeNames;
return this;
}
public Builder applicableTypeNames(String... applicableTypeNames) {
- this.applicableTypeNames = Arrays.asList(applicableTypeNames);
- return this;
+ return applicableTypeNames(Arrays.asList(applicableTypeNames));
}
public Documentation build() {
diff --git a/src/main/java/graphql/validation/constraints/GraphQLListElementValidator.java b/src/main/java/graphql/validation/constraints/GraphQLListElementValidator.java
new file mode 100644
index 0000000..662e1bb
--- /dev/null
+++ b/src/main/java/graphql/validation/constraints/GraphQLListElementValidator.java
@@ -0,0 +1,41 @@
+package graphql.validation.constraints;
+
+import graphql.GraphQLError;
+import graphql.schema.GraphQLInputType;
+import graphql.schema.GraphQLTypeUtil;
+import graphql.validation.rules.ValidationEnvironment;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public class GraphQLListElementValidator {
+ public boolean appliesToType(GraphQLInputType inputType, Function appliesToTypeOrListElement) {
+ if (GraphQLTypeUtil.isList(inputType)) {
+ return appliesToTypeOrListElement.apply((GraphQLInputType) GraphQLTypeUtil.unwrapAll(inputType));
+ }
+
+ return appliesToTypeOrListElement.apply(inputType);
+ }
+
+ public List runConstraintOnListElements(ValidationEnvironment validationEnvironment, Function> runConstraintOnElement) {
+ Object validatedValue = validationEnvironment.getValidatedValue();
+
+ if (validatedValue instanceof Collection>) {
+ final AtomicInteger index = new AtomicInteger(0);
+ return ((Collection>) validatedValue)
+ .stream()
+ .flatMap((item) -> item == null ? Stream.empty() : runConstraintOnElement.apply(validationEnvironment.transform((environment) -> {
+ environment
+ .validatedValue(item)
+ .validatedPath(validationEnvironment.getValidatedPath().segment(index.getAndIncrement()))
+ .validatedType((GraphQLInputType) GraphQLTypeUtil.unwrapAll(validationEnvironment.getValidatedType()));
+ })).stream())
+ .collect(Collectors.toList());
+ }
+
+ return runConstraintOnElement.apply(validationEnvironment);
+ }
+}
diff --git a/src/main/java/graphql/validation/constraints/GraphQLScalars.java b/src/main/java/graphql/validation/constraints/GraphQLScalars.java
new file mode 100644
index 0000000..b8dfb69
--- /dev/null
+++ b/src/main/java/graphql/validation/constraints/GraphQLScalars.java
@@ -0,0 +1,26 @@
+package graphql.validation.constraints;
+
+import graphql.Scalars;
+import graphql.scalars.ExtendedScalars;
+import graphql.schema.GraphQLScalarType;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public class GraphQLScalars {
+ public static final List GRAPHQL_NUMBER_TYPES = Arrays.asList(
+ Scalars.GraphQLInt,
+ Scalars.GraphQLFloat,
+ ExtendedScalars.GraphQLByte,
+ ExtendedScalars.GraphQLShort,
+ ExtendedScalars.GraphQLLong,
+ ExtendedScalars.GraphQLBigDecimal,
+ ExtendedScalars.GraphQLBigInteger
+ );
+
+ public static final List GRAPHQL_NUMBER_AND_STRING_TYPES = Stream.concat(
+ Stream.of(Scalars.GraphQLString, Scalars.GraphQLID),
+ GraphQLScalars.GRAPHQL_NUMBER_TYPES.stream()
+ ).collect(Collectors.toList());
+}
diff --git a/src/main/java/graphql/validation/constraints/standard/AbstractAssertConstraint.java b/src/main/java/graphql/validation/constraints/standard/AbstractAssertConstraint.java
index 9f5ddc7..fadd286 100644
--- a/src/main/java/graphql/validation/constraints/standard/AbstractAssertConstraint.java
+++ b/src/main/java/graphql/validation/constraints/standard/AbstractAssertConstraint.java
@@ -1,49 +1,40 @@
package graphql.validation.constraints.standard;
import graphql.GraphQLError;
-import graphql.schema.GraphQLDirective;
import graphql.schema.GraphQLInputType;
import graphql.validation.constraints.AbstractDirectiveConstraint;
import graphql.validation.rules.ValidationEnvironment;
-
import java.util.Collections;
import java.util.List;
-
import static graphql.Scalars.GraphQLBoolean;
abstract class AbstractAssertConstraint extends AbstractDirectiveConstraint {
-
public AbstractAssertConstraint(String name) {
super(name);
}
-
@Override
public boolean appliesToType(GraphQLInputType inputType) {
- return isOneOfTheseTypes(inputType,
- GraphQLBoolean
- );
+ return isOneOfTheseTypes(inputType, GraphQLBoolean);
}
@Override
protected List runConstraint(ValidationEnvironment validationEnvironment) {
Object validatedValue = validationEnvironment.getValidatedValue();
- //null values are valid
- if (validatedValue == null) {
- return Collections.emptyList();
- }
-
- GraphQLDirective directive = validationEnvironment.getContextObject(GraphQLDirective.class);
boolean isTrue = asBoolean(validatedValue);
- if (!isOK(isTrue)) {
- return mkError(validationEnvironment, directive, mkMessageParams(validatedValue, validationEnvironment));
+ if (!isOK(isTrue)) {
+ return mkError(validationEnvironment);
}
+
return Collections.emptyList();
}
protected abstract boolean isOK(boolean isTrue);
-
+ @Override
+ protected boolean appliesToListElements() {
+ return true;
+ }
}
diff --git a/src/main/java/graphql/validation/constraints/standard/AbstractDecimalMinMaxConstraint.java b/src/main/java/graphql/validation/constraints/standard/AbstractDecimalMinMaxConstraint.java
index f02688d..1bedd8b 100644
--- a/src/main/java/graphql/validation/constraints/standard/AbstractDecimalMinMaxConstraint.java
+++ b/src/main/java/graphql/validation/constraints/standard/AbstractDecimalMinMaxConstraint.java
@@ -1,8 +1,7 @@
package graphql.validation.constraints.standard;
import graphql.GraphQLError;
-import graphql.Scalars;
-import graphql.schema.GraphQLDirective;
+import graphql.schema.GraphQLAppliedDirective;
import graphql.schema.GraphQLInputType;
import graphql.schema.GraphQLScalarType;
import graphql.validation.constraints.AbstractDirectiveConstraint;
@@ -11,51 +10,28 @@
import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-abstract class AbstractDecimalMinMaxConstraint extends AbstractDirectiveConstraint {
+import static graphql.validation.constraints.GraphQLScalars.GRAPHQL_NUMBER_AND_STRING_TYPES;
+abstract class AbstractDecimalMinMaxConstraint extends AbstractDirectiveConstraint {
public AbstractDecimalMinMaxConstraint(String name) {
super(name);
}
- @Override
- public boolean appliesToType(GraphQLInputType inputType) {
- return isOneOfTheseTypes(inputType,
- Scalars.GraphQLString, // note we allow strings
- Scalars.GraphQLByte,
- Scalars.GraphQLShort,
- Scalars.GraphQLInt,
- Scalars.GraphQLLong,
- Scalars.GraphQLBigDecimal,
- Scalars.GraphQLBigInteger,
- Scalars.GraphQLFloat
- );
+ public List getApplicableTypes() {
+ return GRAPHQL_NUMBER_AND_STRING_TYPES;
}
- public List getApplicableTypeNames() {
- return Stream.of(Scalars.GraphQLString, // note we allow strings
- Scalars.GraphQLByte,
- Scalars.GraphQLShort,
- Scalars.GraphQLInt,
- Scalars.GraphQLLong,
- Scalars.GraphQLBigDecimal,
- Scalars.GraphQLBigInteger,
- Scalars.GraphQLFloat)
- .map(GraphQLScalarType::getName)
- .collect(Collectors.toList());
+ @Override
+ protected boolean appliesToType(GraphQLInputType inputType) {
+ return isOneOfTheseTypes(inputType, GRAPHQL_NUMBER_AND_STRING_TYPES);
}
@Override
protected List runConstraint(ValidationEnvironment validationEnvironment) {
Object validatedValue = validationEnvironment.getValidatedValue();
- //null values are valid
- if (validatedValue == null) {
- return Collections.emptyList();
- }
- GraphQLDirective directive = validationEnvironment.getContextObject(GraphQLDirective.class);
+ GraphQLAppliedDirective directive = validationEnvironment.getContextObject(GraphQLAppliedDirective.class);
String value = getStrArg(directive, "value");
boolean inclusive = getBoolArg(directive, "inclusive");
@@ -65,21 +41,21 @@ protected List runConstraint(ValidationEnvironment validationEnvir
BigDecimal argBD = asBigDecimal(validatedValue);
int comparisonResult = argBD.compareTo(directiveBD);
isOK = isOK(inclusive, comparisonResult);
-
} catch (NumberFormatException nfe) {
isOK = false;
}
if (!isOK) {
- return mkError(validationEnvironment, directive, mkMessageParams(validatedValue, validationEnvironment,
- "value", validatedValue,
- "inclusive", inclusive));
-
+ return mkError(validationEnvironment, "value", value, "inclusive", inclusive);
}
+
return Collections.emptyList();
}
abstract protected boolean isOK(boolean inclusive, int comparisonResult);
-
+ @Override
+ protected boolean appliesToListElements() {
+ return true;
+ }
}
diff --git a/src/main/java/graphql/validation/constraints/standard/AbstractMinMaxConstraint.java b/src/main/java/graphql/validation/constraints/standard/AbstractMinMaxConstraint.java
index 1463e1c..e66cad5 100644
--- a/src/main/java/graphql/validation/constraints/standard/AbstractMinMaxConstraint.java
+++ b/src/main/java/graphql/validation/constraints/standard/AbstractMinMaxConstraint.java
@@ -1,61 +1,36 @@
package graphql.validation.constraints.standard;
import graphql.GraphQLError;
-import graphql.Scalars;
-import graphql.schema.GraphQLDirective;
+import graphql.schema.GraphQLAppliedDirective;
import graphql.schema.GraphQLInputType;
import graphql.schema.GraphQLScalarType;
import graphql.validation.constraints.AbstractDirectiveConstraint;
+import graphql.validation.constraints.GraphQLScalars;
import graphql.validation.rules.ValidationEnvironment;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
-import java.util.stream.Stream;
-
-import static java.util.stream.Collectors.toList;
abstract class AbstractMinMaxConstraint extends AbstractDirectiveConstraint {
-
public AbstractMinMaxConstraint(String name) {
super(name);
}
- @Override
- public boolean appliesToType(GraphQLInputType inputType) {
- return isOneOfTheseTypes(inputType,
- Scalars.GraphQLByte,
- Scalars.GraphQLShort,
- Scalars.GraphQLInt,
- Scalars.GraphQLLong,
- Scalars.GraphQLBigDecimal,
- Scalars.GraphQLBigInteger,
- Scalars.GraphQLFloat
- );
+ public List getApplicableTypes() {
+ return GraphQLScalars.GRAPHQL_NUMBER_TYPES;
}
- public List getApplicableTypeNames() {
- return Stream.of(Scalars.GraphQLByte,
- Scalars.GraphQLShort,
- Scalars.GraphQLInt,
- Scalars.GraphQLLong,
- Scalars.GraphQLBigDecimal,
- Scalars.GraphQLBigInteger,
- Scalars.GraphQLFloat)
- .map(GraphQLScalarType::getName)
- .collect(toList());
- }
+ @Override
+ protected boolean appliesToType(GraphQLInputType inputType) {
+ return isOneOfTheseTypes(inputType, GraphQLScalars.GRAPHQL_NUMBER_TYPES);
+ }
@Override
protected List runConstraint(ValidationEnvironment validationEnvironment) {
Object validatedValue = validationEnvironment.getValidatedValue();
- //null values are valid
- if (validatedValue == null) {
- return Collections.emptyList();
- }
-
- GraphQLDirective directive = validationEnvironment.getContextObject(GraphQLDirective.class);
+ GraphQLAppliedDirective directive = validationEnvironment.getContextObject(GraphQLAppliedDirective.class);
int value = getIntArg(directive, "value");
boolean isOK;
@@ -71,12 +46,16 @@ protected List runConstraint(ValidationEnvironment validationEnvir
if (!isOK) {
- return mkError(validationEnvironment, directive, mkMessageParams(validatedValue, validationEnvironment,
- "value", value));
-
+ return mkError(validationEnvironment, "value", value);
}
+
return Collections.emptyList();
}
abstract protected boolean isOK(int comparisonResult);
+
+ @Override
+ protected boolean appliesToListElements() {
+ return true;
+ }
}
diff --git a/src/main/java/graphql/validation/constraints/standard/AbstractNotEmptyRule.java b/src/main/java/graphql/validation/constraints/standard/AbstractNotEmptyRule.java
new file mode 100644
index 0000000..1ed3adf
--- /dev/null
+++ b/src/main/java/graphql/validation/constraints/standard/AbstractNotEmptyRule.java
@@ -0,0 +1,28 @@
+package graphql.validation.constraints.standard;
+
+import graphql.GraphQLError;
+import graphql.schema.GraphQLInputType;
+import graphql.validation.constraints.AbstractDirectiveConstraint;
+import graphql.validation.rules.ValidationEnvironment;
+import java.util.Collections;
+import java.util.List;
+
+public abstract class AbstractNotEmptyRule extends AbstractDirectiveConstraint {
+ public AbstractNotEmptyRule(String name) {
+ super(name);
+ }
+
+ @Override
+ final protected List runConstraint(ValidationEnvironment validationEnvironment) {
+ Object validatedValue = validationEnvironment.getValidatedValue();
+ GraphQLInputType argumentType = validationEnvironment.getValidatedType();
+
+ int size = getStringOrIDOrObjectOrMapLength(argumentType, validatedValue);
+
+ if (size <= 0) {
+ return mkError(validationEnvironment, "size", size);
+ }
+
+ return Collections.emptyList();
+ }
+}
diff --git a/src/main/java/graphql/validation/constraints/standard/AbstractPositiveNegativeConstraint.java b/src/main/java/graphql/validation/constraints/standard/AbstractPositiveNegativeConstraint.java
index b2a89e3..b6090e8 100644
--- a/src/main/java/graphql/validation/constraints/standard/AbstractPositiveNegativeConstraint.java
+++ b/src/main/java/graphql/validation/constraints/standard/AbstractPositiveNegativeConstraint.java
@@ -1,19 +1,14 @@
package graphql.validation.constraints.standard;
import graphql.GraphQLError;
-import graphql.Scalars;
-import graphql.schema.GraphQLDirective;
import graphql.schema.GraphQLInputType;
import graphql.schema.GraphQLScalarType;
import graphql.validation.constraints.AbstractDirectiveConstraint;
+import graphql.validation.constraints.GraphQLScalars;
import graphql.validation.rules.ValidationEnvironment;
-
import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
-import java.util.stream.Stream;
-
-import static java.util.stream.Collectors.toList;
abstract class AbstractPositiveNegativeConstraint extends AbstractDirectiveConstraint {
@@ -23,39 +18,17 @@ public AbstractPositiveNegativeConstraint(String name) {
@Override
public boolean appliesToType(GraphQLInputType inputType) {
- return isOneOfTheseTypes(inputType,
- Scalars.GraphQLByte,
- Scalars.GraphQLShort,
- Scalars.GraphQLInt,
- Scalars.GraphQLLong,
- Scalars.GraphQLBigDecimal,
- Scalars.GraphQLBigInteger,
- Scalars.GraphQLFloat
- );
+ return isOneOfTheseTypes(inputType, GraphQLScalars.GRAPHQL_NUMBER_TYPES);
}
- public List getApplicableTypeNames() {
- return Stream.of(Scalars.GraphQLByte,
- Scalars.GraphQLShort,
- Scalars.GraphQLInt,
- Scalars.GraphQLLong,
- Scalars.GraphQLBigDecimal,
- Scalars.GraphQLBigInteger,
- Scalars.GraphQLFloat)
- .map(GraphQLScalarType::getName)
- .collect(toList());
+ public List getApplicableTypes() {
+ return GraphQLScalars.GRAPHQL_NUMBER_TYPES;
}
@Override
protected List runConstraint(ValidationEnvironment validationEnvironment) {
Object validatedValue = validationEnvironment.getValidatedValue();
- //null values are valid
- if (validatedValue == null) {
- return Collections.emptyList();
- }
-
- GraphQLDirective directive = validationEnvironment.getContextObject(GraphQLDirective.class);
boolean isOK;
try {
@@ -66,11 +39,16 @@ protected List runConstraint(ValidationEnvironment validationEnvir
}
if (!isOK) {
- return mkError(validationEnvironment, directive, mkMessageParams(validatedValue, validationEnvironment));
+ return mkError(validationEnvironment);
}
return Collections.emptyList();
}
abstract protected boolean isOK(BigDecimal bigDecimal);
+
+ @Override
+ protected boolean appliesToListElements() {
+ return true;
+ }
}
diff --git a/src/main/java/graphql/validation/constraints/standard/AbstractSizeConstraint.java b/src/main/java/graphql/validation/constraints/standard/AbstractSizeConstraint.java
new file mode 100644
index 0000000..7a61e0e
--- /dev/null
+++ b/src/main/java/graphql/validation/constraints/standard/AbstractSizeConstraint.java
@@ -0,0 +1,34 @@
+package graphql.validation.constraints.standard;
+
+import graphql.GraphQLError;
+import graphql.schema.GraphQLAppliedDirective;
+import graphql.schema.GraphQLInputType;
+import graphql.validation.constraints.AbstractDirectiveConstraint;
+import graphql.validation.rules.ValidationEnvironment;
+
+import java.util.Collections;
+import java.util.List;
+
+public abstract class AbstractSizeConstraint extends AbstractDirectiveConstraint {
+ public AbstractSizeConstraint(String name) {
+ super(name);
+ }
+
+ @Override
+ final protected List runConstraint(ValidationEnvironment validationEnvironment) {
+ Object validatedValue = validationEnvironment.getValidatedValue();
+ GraphQLInputType argType = validationEnvironment.getValidatedType();
+
+ GraphQLAppliedDirective directive = validationEnvironment.getContextObject(GraphQLAppliedDirective.class);
+ int min = getIntArg(directive, "min");
+ int max = getIntArg(directive, "max");
+
+ int size = getStringOrIDOrObjectOrMapLength(argType, validatedValue);
+
+ if (size < min || size > max) {
+ return mkError(validationEnvironment, "min", min, "max", max, "size", size);
+ }
+
+ return Collections.emptyList();
+ }
+}
diff --git a/src/main/java/graphql/validation/constraints/standard/AssertFalseConstraint.java b/src/main/java/graphql/validation/constraints/standard/AssertFalseConstraint.java
index 5f5fb01..392b0ee 100644
--- a/src/main/java/graphql/validation/constraints/standard/AssertFalseConstraint.java
+++ b/src/main/java/graphql/validation/constraints/standard/AssertFalseConstraint.java
@@ -14,13 +14,9 @@ public AssertFalseConstraint() {
public Documentation getDocumentation() {
return Documentation.newDocumentation()
.messageTemplate(getMessageTemplate())
-
.description("The boolean value must be false.")
-
.example("updateDriver( isDrunk : Boolean @AssertFalse) : DriverDetails")
-
- .applicableTypeNames(GraphQLBoolean.getName())
-
+ .applicableTypes(GraphQLBoolean)
.directiveSDL("directive @AssertFalse(message : String = \"%s\") " +
"on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION",
getMessageTemplate())
diff --git a/src/main/java/graphql/validation/constraints/standard/AssertTrueConstraint.java b/src/main/java/graphql/validation/constraints/standard/AssertTrueConstraint.java
index 69a81fb..fa33d40 100644
--- a/src/main/java/graphql/validation/constraints/standard/AssertTrueConstraint.java
+++ b/src/main/java/graphql/validation/constraints/standard/AssertTrueConstraint.java
@@ -14,13 +14,9 @@ public AssertTrueConstraint() {
public Documentation getDocumentation() {
return Documentation.newDocumentation()
.messageTemplate(getMessageTemplate())
-
.description("The boolean value must be true.")
-
.example("driveCar( hasLicence : Boolean @AssertTrue) : DriverDetails")
-
- .applicableTypeNames(GraphQLBoolean.getName())
-
+ .applicableTypes(GraphQLBoolean)
.directiveSDL("directive @AssertTrue(message : String = \"%s\") " +
"on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION",
getMessageTemplate())
diff --git a/src/main/java/graphql/validation/constraints/standard/ContainerNotEmptyConstraint.java b/src/main/java/graphql/validation/constraints/standard/ContainerNotEmptyConstraint.java
new file mode 100644
index 0000000..e5c4fa0
--- /dev/null
+++ b/src/main/java/graphql/validation/constraints/standard/ContainerNotEmptyConstraint.java
@@ -0,0 +1,34 @@
+package graphql.validation.constraints.standard;
+
+import graphql.schema.GraphQLInputType;
+import graphql.validation.constraints.Documentation;
+import static graphql.schema.GraphQLTypeUtil.isList;
+
+public class ContainerNotEmptyConstraint extends AbstractNotEmptyRule {
+ public ContainerNotEmptyConstraint() {
+ super("ContainerNotEmpty");
+ }
+
+ @Override
+ public Documentation getDocumentation() {
+ return Documentation.newDocumentation()
+ .messageTemplate(getMessageTemplate())
+ .description("The container must have a non-zero size")
+ .example("updateAccident( accidentNotes : [Notes]! @ContainerNotEmpty) : DriverDetails")
+ .applicableTypeNames("Lists", "Input Objects")
+ .directiveSDL("directive @ContainerNotEmpty(message : String = \"%s\") " +
+ "on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION",
+ getMessageTemplate())
+ .build();
+ }
+
+ @Override
+ public boolean appliesToType(GraphQLInputType inputType) {
+ return isList(inputType) || isMap(inputType);
+ }
+
+ @Override
+ protected boolean appliesToListElements() {
+ return false;
+ }
+}
diff --git a/src/main/java/graphql/validation/constraints/standard/ContainerSizeConstraint.java b/src/main/java/graphql/validation/constraints/standard/ContainerSizeConstraint.java
new file mode 100644
index 0000000..775221b
--- /dev/null
+++ b/src/main/java/graphql/validation/constraints/standard/ContainerSizeConstraint.java
@@ -0,0 +1,35 @@
+package graphql.validation.constraints.standard;
+
+import graphql.schema.GraphQLInputType;
+import graphql.validation.constraints.Documentation;
+import static graphql.schema.GraphQLTypeUtil.isList;
+
+public class ContainerSizeConstraint extends AbstractSizeConstraint {
+ public ContainerSizeConstraint() {
+ super("ContainerSize");
+ }
+
+ @Override
+ public Documentation getDocumentation() {
+ return Documentation.newDocumentation()
+ .messageTemplate(getMessageTemplate())
+ .description("The element size must be between the specified `min` and `max` boundaries (inclusive).")
+ .example("updateDrivingNotes( drivingNote : String @ContainerSize( min : 1000, max : 100000)) : DriverDetails")
+ .applicableTypeNames("Lists", "Input Objects")
+ .directiveSDL("directive @ContainerSize(min : Int = 0, max : Int = %d, message : String = \"%s\") " +
+ "on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION",
+ Integer.MAX_VALUE, getMessageTemplate())
+ .build();
+ }
+
+
+ @Override
+ public boolean appliesToType(GraphQLInputType inputType) {
+ return isList(inputType) || isMap(inputType);
+ }
+
+ @Override
+ protected boolean appliesToListElements() {
+ return false;
+ }
+}
diff --git a/src/main/java/graphql/validation/constraints/standard/DecimalMaxConstraint.java b/src/main/java/graphql/validation/constraints/standard/DecimalMaxConstraint.java
index fc2cd58..e06440e 100644
--- a/src/main/java/graphql/validation/constraints/standard/DecimalMaxConstraint.java
+++ b/src/main/java/graphql/validation/constraints/standard/DecimalMaxConstraint.java
@@ -12,13 +12,9 @@ public DecimalMaxConstraint() {
public Documentation getDocumentation() {
return Documentation.newDocumentation()
.messageTemplate(getMessageTemplate())
-
.description("The element must be a number whose value must be less than or equal to the specified maximum.")
-
.example("driveCar( bloodAlcoholLevel : Float @DecimalMax(value : \"0.05\") : DriverDetails")
-
- .applicableTypeNames(getApplicableTypeNames())
-
+ .applicableTypes(getApplicableTypes())
.directiveSDL("directive @DecimalMax(value : String!, inclusive : Boolean! = true, message : String = \"%s\") " +
"on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION",
getMessageTemplate())
diff --git a/src/main/java/graphql/validation/constraints/standard/DecimalMinConstraint.java b/src/main/java/graphql/validation/constraints/standard/DecimalMinConstraint.java
index aeb6a00..895f1cf 100644
--- a/src/main/java/graphql/validation/constraints/standard/DecimalMinConstraint.java
+++ b/src/main/java/graphql/validation/constraints/standard/DecimalMinConstraint.java
@@ -12,13 +12,9 @@ public DecimalMinConstraint() {
public Documentation getDocumentation() {
return Documentation.newDocumentation()
.messageTemplate(getMessageTemplate())
-
.description("The element must be a number whose value must be greater than or equal to the specified minimum.")
-
.example("driveCar( carHorsePower : Float @DecimalMin(value : \"300.50\") : DriverDetails")
-
- .applicableTypeNames(getApplicableTypeNames())
-
+ .applicableTypes(getApplicableTypes())
.directiveSDL("directive @DecimalMin(value : String!, inclusive : Boolean! = true, message : String = \"%s\") " +
"on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION",
getMessageTemplate())
diff --git a/src/main/java/graphql/validation/constraints/standard/DigitsConstraint.java b/src/main/java/graphql/validation/constraints/standard/DigitsConstraint.java
index 11da22b..a8f963e 100644
--- a/src/main/java/graphql/validation/constraints/standard/DigitsConstraint.java
+++ b/src/main/java/graphql/validation/constraints/standard/DigitsConstraint.java
@@ -1,10 +1,8 @@
package graphql.validation.constraints.standard;
import graphql.GraphQLError;
-import graphql.Scalars;
-import graphql.schema.GraphQLDirective;
+import graphql.schema.GraphQLAppliedDirective;
import graphql.schema.GraphQLInputType;
-import graphql.schema.GraphQLScalarType;
import graphql.validation.constraints.AbstractDirectiveConstraint;
import graphql.validation.constraints.Documentation;
import graphql.validation.rules.ValidationEnvironment;
@@ -12,12 +10,11 @@
import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
-import java.util.stream.Stream;
+import java.util.Optional;
-import static java.util.stream.Collectors.toList;
+import static graphql.validation.constraints.GraphQLScalars.GRAPHQL_NUMBER_AND_STRING_TYPES;
public class DigitsConstraint extends AbstractDirectiveConstraint {
-
public DigitsConstraint() {
super("Digits");
}
@@ -25,75 +22,66 @@ public DigitsConstraint() {
@Override
public Documentation getDocumentation() {
return Documentation.newDocumentation()
- .messageTemplate(getMessageTemplate())
-
- .description("The element must be a number inside the specified `integer` and `fraction` range.")
-
- .example("buyCar( carCost : Float @Digits(integer : 5, fraction : 2) : DriverDetails")
-
- .applicableTypeNames(Stream.of(Scalars.GraphQLString,
- Scalars.GraphQLByte,
- Scalars.GraphQLShort,
- Scalars.GraphQLInt,
- Scalars.GraphQLLong,
- Scalars.GraphQLBigDecimal,
- Scalars.GraphQLBigInteger,
- Scalars.GraphQLFloat)
- .map(GraphQLScalarType::getName)
- .collect(toList()))
-
- .directiveSDL("directive @Digits(integer : Int!, fraction : Int!, message : String = \"%s\") " +
- "on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION",
- getMessageTemplate())
- .build();
+ .messageTemplate(getMessageTemplate())
+ .description("The element must be a number inside the specified `integer` and optionally inside `fraction` range.")
+ .example("buyCar( carCost : Float @Digits(integer : 5, fraction : 2) : DriverDetails")
+ .applicableTypes(GRAPHQL_NUMBER_AND_STRING_TYPES)
+ .directiveSDL("directive @Digits(integer : Int!, fraction : Int, message : String = \"%s\") " +
+ "on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION",
+ getMessageTemplate())
+ .build();
}
@Override
public boolean appliesToType(GraphQLInputType inputType) {
- return isOneOfTheseTypes(inputType,
- Scalars.GraphQLString,
- Scalars.GraphQLByte,
- Scalars.GraphQLShort,
- Scalars.GraphQLInt,
- Scalars.GraphQLLong,
- Scalars.GraphQLBigDecimal,
- Scalars.GraphQLBigInteger,
- Scalars.GraphQLFloat
- );
+ return isOneOfTheseTypes(inputType, GRAPHQL_NUMBER_AND_STRING_TYPES);
}
@Override
protected List runConstraint(ValidationEnvironment validationEnvironment) {
Object validatedValue = validationEnvironment.getValidatedValue();
- if (validatedValue == null) {
- return Collections.emptyList();
- }
- GraphQLDirective directive = validationEnvironment.getContextObject(GraphQLDirective.class);
+ GraphQLAppliedDirective directive = validationEnvironment.getContextObject(GraphQLAppliedDirective.class);
int maxIntegerLength = getIntArg(directive, "integer");
- int maxFractionLength = getIntArg(directive, "fraction");
+ Optional maxFractionLengthOpt = getIntArgOpt(directive, "fraction");
boolean isOk;
try {
BigDecimal bigNum = asBigDecimal(validatedValue);
- isOk = isOk(bigNum, maxIntegerLength, maxFractionLength);
+ boolean isFractionPartOk = maxFractionLengthOpt
+ .map(maxFractionLength -> isFractionPartOk(bigNum, maxFractionLength))
+ .orElse(true);
+
+ isOk = isFractionPartOk && isIntegerPartOk(bigNum, maxIntegerLength);
} catch (NumberFormatException e) {
isOk = false;
}
if (!isOk) {
- return mkError(validationEnvironment, directive, mkMessageParams(validatedValue, validationEnvironment,
- "integer", maxIntegerLength,
- "fraction", maxFractionLength));
+ return mkError(
+ validationEnvironment,
+ "integer",
+ maxIntegerLength, "fraction",
+ maxFractionLengthOpt.map(Object::toString).orElse("unlimited")
+ );
}
+
return Collections.emptyList();
}
- private boolean isOk(BigDecimal bigNum, int maxIntegerLength, int maxFractionLength) {
- int integerPartLength = bigNum.precision() - bigNum.scale();
- int fractionPartLength = bigNum.scale() < 0 ? 0 : bigNum.scale();
+ private static boolean isIntegerPartOk(BigDecimal bigNum, int maxIntegerLength) {
+ final int integerPartLength = bigNum.precision() - bigNum.scale();
+ return maxIntegerLength >= integerPartLength;
+ }
+
+ private static boolean isFractionPartOk(BigDecimal bigNum, int maxFractionLength) {
+ final int fractionPartLength = Math.max(bigNum.scale(), 0);
+ return maxFractionLength >= fractionPartLength;
+ }
- return maxIntegerLength >= integerPartLength && maxFractionLength >= fractionPartLength;
+ @Override
+ protected boolean appliesToListElements() {
+ return true;
}
}
diff --git a/src/main/java/graphql/validation/constraints/standard/ExpressionConstraint.java b/src/main/java/graphql/validation/constraints/standard/ExpressionConstraint.java
index 484cdfb..3f003ff 100644
--- a/src/main/java/graphql/validation/constraints/standard/ExpressionConstraint.java
+++ b/src/main/java/graphql/validation/constraints/standard/ExpressionConstraint.java
@@ -1,7 +1,7 @@
package graphql.validation.constraints.standard;
import graphql.GraphQLError;
-import graphql.schema.GraphQLDirective;
+import graphql.schema.GraphQLAppliedDirective;
import graphql.schema.GraphQLFieldDefinition;
import graphql.schema.GraphQLFieldsContainer;
import graphql.schema.GraphQLInputType;
@@ -26,16 +26,12 @@ public ExpressionConstraint() {
public Documentation getDocumentation() {
return Documentation.newDocumentation()
.messageTemplate(getMessageTemplate())
-
.description("The provided expression must evaluate to true. " +
"The expression language is Java EL " +
"and expressions MUST resolve to a boolean value, ie. it is valid or not.")
-
.example("drivers( first : Int, after : String!, last : Int, before : String) \n" +
" : DriverConnection @Expression(value : \"${args.containsOneOf('first','last') }\"")
-
.applicableTypeNames("All Types and Scalars")
-
.directiveSDL("directive @Expression(value : String!, message : String = \"%s\") " +
"on FIELD_DEFINITION | ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION",
getMessageTemplate())
@@ -54,21 +50,18 @@ public boolean appliesTo(GraphQLFieldDefinition fieldDefinition, GraphQLFieldsCo
@Override
protected List runConstraint(ValidationEnvironment validationEnvironment) {
- GraphQLDirective directive = validationEnvironment.getContextObject(GraphQLDirective.class);
+ GraphQLAppliedDirective directive = validationEnvironment.getContextObject(GraphQLAppliedDirective.class);
String expression = helpWithCurlyBraces(getStrArg(directive, "value"));
- Object validatedValue = validationEnvironment.getValidatedValue();
-
Map variables = StandardELVariables.standardELVars(validationEnvironment);
ELSupport elSupport = new ELSupport(validationEnvironment.getLocale());
boolean isOK = elSupport.evaluateBoolean(expression, variables);
if (!isOK) {
- return mkError(validationEnvironment, directive, mkMessageParams(validatedValue, validationEnvironment,
- "value", expression));
-
+ return mkError(validationEnvironment,"value", expression);
}
+
return Collections.emptyList();
}
@@ -82,4 +75,9 @@ private String helpWithCurlyBraces(String expression) {
}
return expression;
}
+
+ @Override
+ protected boolean appliesToListElements() {
+ return false;
+ }
}
diff --git a/src/main/java/graphql/validation/constraints/standard/MaxConstraint.java b/src/main/java/graphql/validation/constraints/standard/MaxConstraint.java
index bc21d33..899c70d 100644
--- a/src/main/java/graphql/validation/constraints/standard/MaxConstraint.java
+++ b/src/main/java/graphql/validation/constraints/standard/MaxConstraint.java
@@ -12,13 +12,9 @@ public MaxConstraint() {
public Documentation getDocumentation() {
return Documentation.newDocumentation()
.messageTemplate(getMessageTemplate())
-
.description("The element must be a number whose value must be less than or equal to the specified maximum.")
-
.example("driveCar( horsePower : Float @Max(value : 1000) : DriverDetails")
-
- .applicableTypeNames(getApplicableTypeNames())
-
+ .applicableTypes(getApplicableTypes())
.directiveSDL("directive @Max(value : Int! = %d, message : String = \"%s\") " +
"on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION",
Integer.MAX_VALUE, getMessageTemplate())
diff --git a/src/main/java/graphql/validation/constraints/standard/MinConstraint.java b/src/main/java/graphql/validation/constraints/standard/MinConstraint.java
index 421abf6..ff16edb 100644
--- a/src/main/java/graphql/validation/constraints/standard/MinConstraint.java
+++ b/src/main/java/graphql/validation/constraints/standard/MinConstraint.java
@@ -12,13 +12,9 @@ public MinConstraint() {
public Documentation getDocumentation() {
return Documentation.newDocumentation()
.messageTemplate(getMessageTemplate())
-
.description("The element must be a number whose value must be greater than or equal to the specified minimum.")
-
.example("driveCar( age : Int @Min(value : 18) : DriverDetails")
-
- .applicableTypeNames(getApplicableTypeNames())
-
+ .applicableTypes(getApplicableTypes())
.directiveSDL("directive @Min(value : Int! = 0, message : String = \"%s\") " +
"on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION",
getMessageTemplate())
diff --git a/src/main/java/graphql/validation/constraints/standard/NegativeConstraint.java b/src/main/java/graphql/validation/constraints/standard/NegativeConstraint.java
index f9acd29..e074771 100644
--- a/src/main/java/graphql/validation/constraints/standard/NegativeConstraint.java
+++ b/src/main/java/graphql/validation/constraints/standard/NegativeConstraint.java
@@ -14,13 +14,9 @@ public NegativeConstraint() {
public Documentation getDocumentation() {
return Documentation.newDocumentation()
.messageTemplate(getMessageTemplate())
-
.description("The element must be a negative number.")
-
.example("driveCar( lostLicencePoints : Int @Negative) : DriverDetails")
-
- .applicableTypeNames(getApplicableTypeNames())
-
+ .applicableTypes(getApplicableTypes())
.directiveSDL("directive @Negative(message : String = \"%s\") " +
"on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION",
getMessageTemplate())
diff --git a/src/main/java/graphql/validation/constraints/standard/NegativeOrZeroConstraint.java b/src/main/java/graphql/validation/constraints/standard/NegativeOrZeroConstraint.java
index f61f1c1..4806470 100644
--- a/src/main/java/graphql/validation/constraints/standard/NegativeOrZeroConstraint.java
+++ b/src/main/java/graphql/validation/constraints/standard/NegativeOrZeroConstraint.java
@@ -14,23 +14,17 @@ public NegativeOrZeroConstraint() {
public Documentation getDocumentation() {
return Documentation.newDocumentation()
.messageTemplate(getMessageTemplate())
-
.description("The element must be a negative number or zero.")
-
.example("driveCar( lostLicencePoints : Int @NegativeOrZero) : DriverDetails")
-
- .applicableTypeNames(getApplicableTypeNames())
-
+ .applicableTypes(getApplicableTypes())
.directiveSDL("directive @NegativeOrZero(message : String = \"%s\") " +
"on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION",
getMessageTemplate())
.build();
}
-
@Override
protected boolean isOK(BigDecimal bigDecimal) {
return bigDecimal.compareTo(BigDecimal.ZERO) <= 0;
}
-
}
diff --git a/src/main/java/graphql/validation/constraints/standard/NotBlankRule.java b/src/main/java/graphql/validation/constraints/standard/NotBlankRule.java
index d63da23..3af990d 100644
--- a/src/main/java/graphql/validation/constraints/standard/NotBlankRule.java
+++ b/src/main/java/graphql/validation/constraints/standard/NotBlankRule.java
@@ -2,12 +2,10 @@
import graphql.GraphQLError;
import graphql.Scalars;
-import graphql.schema.GraphQLDirective;
import graphql.schema.GraphQLInputType;
import graphql.validation.constraints.AbstractDirectiveConstraint;
import graphql.validation.constraints.Documentation;
import graphql.validation.rules.ValidationEnvironment;
-
import java.util.Collections;
import java.util.List;
@@ -21,13 +19,9 @@ public NotBlankRule() {
public Documentation getDocumentation() {
return Documentation.newDocumentation()
.messageTemplate(getMessageTemplate())
-
.description("The String must contain at least one non-whitespace character, according to Java's Character.isWhitespace().")
-
.example("updateAccident( accidentNotes : String @NotBlank) : DriverDetails")
-
- .applicableTypeNames(Scalars.GraphQLString.getName(), Scalars.GraphQLID.getName())
-
+ .applicableTypeNames(Scalars.GraphQLString.getName(), Scalars.GraphQLID.getName(), "Lists")
.directiveSDL("directive @NotBlank(message : String = \"%s\") " +
"on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION",
getMessageTemplate())
@@ -36,29 +30,22 @@ public Documentation getDocumentation() {
@Override
public boolean appliesToType(GraphQLInputType inputType) {
- return isStringOrID(inputType);
+ return isStringOrIDOrList(inputType);
}
@Override
protected List runConstraint(ValidationEnvironment validationEnvironment) {
Object validatedValue = validationEnvironment.getValidatedValue();
- GraphQLDirective directive = validationEnvironment.getContextObject(GraphQLDirective.class);
-
- if (validatedValue == null || isBlank(validatedValue)) {
- return mkError(validationEnvironment, directive, mkMessageParams(validatedValue, validationEnvironment));
-
+ if (validatedValue.toString().trim().isEmpty()) {
+ return mkError(validationEnvironment);
}
+
return Collections.emptyList();
}
- private boolean isBlank(Object value) {
- char[] chars = value.toString().toCharArray();
- for (char c : chars) {
- if (!Character.isWhitespace(c)) {
- return false;
- }
- }
+ @Override
+ protected boolean appliesToListElements() {
return true;
}
}
diff --git a/src/main/java/graphql/validation/constraints/standard/NotEmptyRule.java b/src/main/java/graphql/validation/constraints/standard/NotEmptyRule.java
index 06fe5c1..bdb3d0d 100644
--- a/src/main/java/graphql/validation/constraints/standard/NotEmptyRule.java
+++ b/src/main/java/graphql/validation/constraints/standard/NotEmptyRule.java
@@ -1,16 +1,10 @@
package graphql.validation.constraints.standard;
-import graphql.GraphQLError;
import graphql.Scalars;
-import graphql.schema.GraphQLDirective;
import graphql.schema.GraphQLInputType;
-import graphql.validation.constraints.AbstractDirectiveConstraint;
import graphql.validation.constraints.Documentation;
-import graphql.validation.rules.ValidationEnvironment;
-import java.util.Collections;
-import java.util.List;
-public class NotEmptyRule extends AbstractDirectiveConstraint {
+public class NotEmptyRule extends AbstractNotEmptyRule {
public NotEmptyRule() {
super("NotEmpty");
@@ -20,13 +14,9 @@ public NotEmptyRule() {
public Documentation getDocumentation() {
return Documentation.newDocumentation()
.messageTemplate(getMessageTemplate())
-
- .description("The element must have a non zero size.")
-
- .example("updateAccident( accidentNotes : [Notes]! @NotEmpty) : DriverDetails")
-
- .applicableTypeNames(Scalars.GraphQLString.getName(), Scalars.GraphQLID.getName(), "Lists", "Input Objects")
-
+ .description("The element must have a non zero size")
+ .example("updateAccident( accidentNotes : [String!]! @NotEmpty) : DriverDetails")
+ .applicableTypeNames(Scalars.GraphQLString.getName(), Scalars.GraphQLID.getName())
.directiveSDL("directive @NotEmpty(message : String = \"%s\") " +
"on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION",
getMessageTemplate())
@@ -35,24 +25,11 @@ public Documentation getDocumentation() {
@Override
public boolean appliesToType(GraphQLInputType inputType) {
- return isStringOrIDOrListOrMap(inputType);
+ return isStringOrID(inputType);
}
@Override
- protected List runConstraint(ValidationEnvironment validationEnvironment) {
- Object validatedValue = validationEnvironment.getValidatedValue();
- GraphQLInputType argumentType = validationEnvironment.getValidatedType();
-
- GraphQLDirective directive = validationEnvironment.getContextObject(GraphQLDirective.class);
- int size = getStringOrIDOrObjectOrMapLength(argumentType, validatedValue);
-
- if (size <= 0) {
- return mkError(validationEnvironment, directive, mkMessageParams(validatedValue, validationEnvironment,
- "size", size
- ));
- }
- return Collections.emptyList();
+ protected boolean appliesToListElements() {
+ return true;
}
-
-
}
diff --git a/src/main/java/graphql/validation/constraints/standard/PatternConstraint.java b/src/main/java/graphql/validation/constraints/standard/PatternConstraint.java
index 6a73c18..b670bf8 100644
--- a/src/main/java/graphql/validation/constraints/standard/PatternConstraint.java
+++ b/src/main/java/graphql/validation/constraints/standard/PatternConstraint.java
@@ -2,25 +2,23 @@
import graphql.GraphQLError;
import graphql.Scalars;
+import graphql.schema.GraphQLAppliedDirective;
import graphql.schema.GraphQLDirective;
import graphql.schema.GraphQLInputType;
import graphql.validation.constraints.AbstractDirectiveConstraint;
import graphql.validation.constraints.Documentation;
import graphql.validation.rules.ValidationEnvironment;
-
-import java.util.Arrays;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-
import static graphql.schema.GraphQLTypeUtil.isList;
import static java.util.Collections.emptyList;
public class PatternConstraint extends AbstractDirectiveConstraint {
- private final static Map SEEN_PATTERNS = new HashMap<>();
+ private final static ConcurrentMap SEEN_PATTERNS = new ConcurrentHashMap<>();
public PatternConstraint() {
super("Pattern");
@@ -30,13 +28,9 @@ public PatternConstraint() {
public Documentation getDocumentation() {
return Documentation.newDocumentation()
.messageTemplate(getMessageTemplate())
-
.description("The String must match the specified regular expression, which follows the Java regular expression conventions.")
-
.example("updateDriver( licencePlate : String @Pattern(regexp : \"[A-Z][A-Z][A-Z]-[0-9][0-9][0-9]\") : DriverDetails")
-
.applicableTypeNames(Scalars.GraphQLString.getName(), Scalars.GraphQLID.getName(), "Lists")
-
.directiveSDL("directive @Pattern(regexp : String! =\".*\", message : String = \"%s\") " +
"on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION",
getMessageTemplate())
@@ -51,34 +45,19 @@ public boolean appliesToType(GraphQLInputType inputType) {
@Override
protected List runConstraint(ValidationEnvironment validationEnvironment) {
Object validatedValue = validationEnvironment.getValidatedValue();
- GraphQLInputType argumentType = validationEnvironment.getValidatedType();
- if (validatedValue == null) {
- return emptyList();
- }
+ String strValue = String.valueOf(validatedValue);
- List