Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for bean validation 3 #12

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 20 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
[![Build Status](https://travis-ci.org/vavr-io/vavr-beanvalidation2.png)](https://travis-ci.org/vavr-io/vavr-beanvalidation2)

# Vavr-Beanvalidation 2.0
# Vavr-Beanvalidation

This module provides support for bean validation 2.0 (JSR380). Can be used with any service provider of the bean validation spec
This module provides support for bean validation 2.0 (JSR380) and bean validation 3.0. Can be used with any service
provider of the bean validation spec
e.g. `org.hibernate.validator:hibernate-validator`

Features:
Expand All @@ -17,7 +18,11 @@ as to where violations occurred (index for `Seq`s and key for `Map`s)

# Using the module

Add the dependency to your classpath. For maven:
## Dependencies

Depending on the version of bean validation add one of the dependencies to your classpath. For maven:

### Bean validation 2

```xml
<dependency>
Expand All @@ -27,6 +32,18 @@ Add the dependency to your classpath. For maven:
</dependency>
```

### Bean validation 3

```xml
<dependency>
<groupId>io.vavr</groupId>
<artifactId>vavr-beanvalidation3</artifactId>
<version>0.10.0</version>
</dependency>
```

## Configuration

For the bean validation service provider to pick it up the constraints must be registered.
Add the following to your `validation.xml`:

Expand Down
143 changes: 86 additions & 57 deletions generator/Generator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -29,43 +29,73 @@ val TUPLE_NODE_NAME = "<element>"
val TARGET_MAIN = s"${project.getBasedir()}/src-gen/main/java"
val TARGET_TEST = s"${project.getBasedir()}/src-gen/test/java"
val TARGET_MAIN_RES = s"${project.getBasedir()}/src-gen/main/resources"
val VALIDATION_VERSION = s"${project.getArtifactId()}"
val CHARSET = java.nio.charset.StandardCharsets.UTF_8

val collectionValueExtractors =
"""io.vavr.beanvalidation2.valueextraction.SeqValueExtractor
|io.vavr.beanvalidation2.valueextraction.MapKeyExtractor
|io.vavr.beanvalidation2.valueextraction.MapValueExtractor
|io.vavr.beanvalidation2.valueextraction.MultimapKeyExtractor
|io.vavr.beanvalidation2.valueextraction.MultimapValueExtractor
|io.vavr.beanvalidation2.valueextraction.EitherLeftExtractor
|io.vavr.beanvalidation2.valueextraction.EitherRightExtractor
s"""io.vavr.${getBeanValidationVersionName(VALIDATION_VERSION)}.valueextraction.SeqValueExtractor
|io.vavr.${getBeanValidationVersionName(VALIDATION_VERSION)}.valueextraction.MapKeyExtractor
|io.vavr.${getBeanValidationVersionName(VALIDATION_VERSION)}.valueextraction.MapValueExtractor
|io.vavr.${getBeanValidationVersionName(VALIDATION_VERSION)}.valueextraction.MultimapKeyExtractor
|io.vavr.${getBeanValidationVersionName(VALIDATION_VERSION)}.valueextraction.MultimapValueExtractor
|io.vavr.${getBeanValidationVersionName(VALIDATION_VERSION)}.valueextraction.EitherLeftExtractor
|io.vavr.${getBeanValidationVersionName(VALIDATION_VERSION)}.valueextraction.EitherRightExtractor
|""".stripMargin

// generate extractors
for (t <- 1 to N) genVavrFile("io.vavr.beanvalidation2.valueextraction", s"Tuple${t}Extractor")(genExtractor(t))
for (t <- 1 to N) genVavrFile(
s"io.vavr.${getBeanValidationVersionName(VALIDATION_VERSION)}.valueextraction",
s"Tuple${t}Extractor")(genExtractor(t)
)

// generate service loader file
genFile(TARGET_MAIN_RES, "META-INF/services", "javax.validation.valueextraction.ValueExtractor"){
genFile(TARGET_MAIN_RES, "META-INF/services", getServiceLoaderName(VALIDATION_VERSION)){
collectionValueExtractors + (for {
a <- 1 to N
p <- 1 to a
} yield s"""io.vavr.beanvalidation2.valueextraction.Tuple${a}Extractor$$${getNameForPosition(p)}Extractor""").mkString("\n")
} yield s"""io.vavr.${getBeanValidationVersionName(VALIDATION_VERSION)}.valueextraction.Tuple${a}Extractor$$${getNameForPosition(p)}Extractor""").mkString("\n")
}

def genExtractor(arity: Int): (String, String) => String = (packageName: String, className: String) => { raw"""
import io.vavr.Tuple$arity;

import javax.validation.valueextraction.ExtractedValue;
import javax.validation.valueextraction.ValueExtractor;
def getBeanValidationVersionName(validationVersion: String): String = {
validationVersion match {
case "vavr-beanvalidation2" => "beanvalidation2"
case "vavr-beanvalidation3" => "beanvalidation3"
}
}

def getServiceLoaderName(validationVersion: String): String = {
validationVersion match {
case "vavr-beanvalidation2" => "javax.validation.valueextraction.ValueExtractor"
case "vavr-beanvalidation3" => "jakarta.validation.valueextraction.ValueExtractor"
}
}

public interface $className {
def genExtractor(arity: Int): (String, String) => String = (packageName: String, className: String) => {
val validationImports = genValidationImports(VALIDATION_VERSION);
val extractors = (for (pos <- 1 to arity) yield genExtractorForPosition(arity, pos)).mkString("\n")

raw"""import io.vavr.Tuple$arity;
|
|$validationImports
|
|
|public interface $className {
|$extractors
|}""".stripMargin
}

""" + (for (pos <- 1 to arity) yield genExtractorForPosition(arity, pos)).mkString("\n\n") + """
}"""
def genValidationImports(validationVersion: String): String = {
validationVersion match {
case "vavr-beanvalidation2" =>
"""import javax.validation.valueextraction.ExtractedValue;
|import javax.validation.valueextraction.ValueExtractor;""".stripMargin
case "vavr-beanvalidation3" =>
"""import jakarta.validation.valueextraction.ExtractedValue;
|import jakarta.validation.valueextraction.ValueExtractor;""".stripMargin
}
}

def genExtractorForPosition(arity: Int, pos: Int)= {
def genExtractorForPosition(arity: Int, pos: Int) = {

val tupleClass = s"""Tuple$arity"""
val tupleClassWithWildcardTypeParameter = tupleClass + "<" + (1 to arity).map(_ => "?").mkString(", ") + ">"
Expand All @@ -74,14 +104,12 @@ def genExtractorForPosition(arity: Int, pos: Int)= {
val typeParameter = s"""$tupleClass<${typeParamResult.mkString(", ")}>"""

s"""
class ${getNameForPosition(pos)}Extractor implements ValueExtractor<$typeParameter> {

@Override
public void extractValues($tupleClassWithWildcardTypeParameter originalValue, ValueReceiver receiver) {
receiver.indexedValue("$TUPLE_NODE_NAME", $pos, originalValue._$pos);
}

}"""
| class ${getNameForPosition(pos)}Extractor implements ValueExtractor<$typeParameter> {
| @Override
| public void extractValues($tupleClassWithWildcardTypeParameter originalValue, ValueReceiver receiver) {
| receiver.indexedValue("$TUPLE_NODE_NAME", $pos, originalValue._$pos);
| }
| }""".stripMargin
}

/**
Expand All @@ -92,27 +120,27 @@ def genExtractorForPosition(arity: Int, pos: Int)= {
* @param gen A generator which produces a String.
*/
def genVavrFile(packageName: String, className: String, baseDir: String = TARGET_MAIN)(gen: (String, String) => String, knownSimpleClassNames: List[String] = List()) =
genJavaFile(baseDir, packageName, className)(raw"""
/* __ __ __ __ __ ___
* \ \ / / \ \ / / __/
* \ \/ / /\ \ \/ / /
* \____/__/ \__\____/__/
*
* Copyright 2014-2018 Vavr, http://vavr.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
""")(gen)(CHARSET)
genJavaFile(baseDir, packageName, className)(
raw"""|/* __ __ __ __ __ ___
| * \ \ / / \ \ / / __/
| * \ \/ / /\ \ \/ / /
| * \____/__/ \__\____/__/
| *
| * Copyright 2014-2018 Vavr, http://vavr.io
| *
| * Licensed under the Apache License, Version 2.0 (the "License");
| * you may not use this file except in compliance with the License.
| * You may obtain a copy of the License at
| *
| * http://www.apache.org/licenses/LICENSE-2.0
| *
| * Unless required by applicable law or agreed to in writing, software
| * distributed under the License is distributed on an "AS IS" BASIS,
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
| * See the License for the specific language governing permissions and
| * limitations under the License.
| */""".stripMargin
)(gen)(CHARSET)


/**
Expand All @@ -130,15 +158,16 @@ def genJavaFile(baseDir: String, packageName: String, className: String)(classHe
val fileName = className + ".java"
val classBody = gen.apply(packageName, className)

genFile(baseDir, dirName, fileName)(raw"""
$classHeader
package $packageName;
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*\
G E N E R A T O R C R A F T E D
\*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
$classBody
""")
}
genFile(baseDir, dirName, fileName)(
raw"""$classHeader
|package $packageName;
|/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*\
| G E N E R A T O R C R A F T E D
|\*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
|
|$classBody""".stripMargin
)
}


/**
Expand Down
Loading