Skip to content

Commit 1fd98fd

Browse files
committed
feat: migrate to multi-module architecture with Jakarta Validation support
Split project into sift-core and sift-annotations. Added @SiftMatch constraint. Achieved 100% test coverage and resolved all Gradle warnings. Applied strict encapsulation and Apache 2.0 licenses.
1 parent 666bfa6 commit 1fd98fd

File tree

22 files changed

+610
-80
lines changed

22 files changed

+610
-80
lines changed

build.gradle

Lines changed: 4 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,8 @@
1-
plugins {
2-
id 'java-library'
3-
id 'maven-publish'
4-
id 'signing'
5-
}
6-
7-
group = 'com.mirkoddd'
8-
version = '1.0.0'
9-
10-
java {
11-
toolchain {
12-
languageVersion = JavaLanguageVersion.of(17)
13-
}
14-
withJavadocJar()
15-
withSourcesJar()
16-
}
17-
18-
dependencies {
19-
testImplementation 'org.junit.jupiter:junit-jupiter:5.10.2'
20-
}
21-
22-
test {
23-
useJUnitPlatform()
24-
}
25-
26-
publishing {
27-
publications {
28-
mavenJava(MavenPublication) {
29-
from components.java
30-
31-
pom {
32-
name = 'Sift'
33-
description = 'A Fluent Regex Builder for Java based on SOLID principles.'
34-
url = 'https://github.com/mirkoddd/Sift'
35-
36-
licenses {
37-
license {
38-
name = 'The Apache License, Version 2.0'
39-
url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
40-
}
41-
}
42-
43-
developers {
44-
developer {
45-
id = 'mirkoddd'
46-
name = 'Mirko Dimartino'
47-
email = 'mirkoddd@gmail.com'
48-
}
49-
}
50-
51-
scm {
52-
connection = 'scm:git:git://github.com/mirkoddd/Sift.git'
53-
developerConnection = 'scm:git:ssh://github.com:mirkoddd/Sift.git'
54-
url = 'https://github.com/mirkoddd/Sift'
55-
}
56-
}
57-
}
58-
}
1+
allprojects {
2+
group = 'com.mirkoddd'
3+
version = '1.1.0'
594

605
repositories {
61-
maven {
62-
name = "Staging"
63-
url = layout.buildDirectory.dir("repos/bundles")
64-
}
6+
mavenCentral()
657
}
66-
}
67-
68-
signing {
69-
sign publishing.publications.mavenJava
708
}

settings.gradle

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,8 @@
1-
pluginManagement {
2-
repositories {
3-
mavenCentral()
4-
gradlePluginPortal()
5-
}
6-
}
7-
dependencyResolutionManagement {
8-
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
9-
repositories {
10-
mavenCentral()
11-
}
1+
plugins {
2+
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.8.0'
123
}
134

14-
rootProject.name = "Sift"
5+
rootProject.name = 'Sift'
6+
7+
include ':sift-core'
8+
include ':sift-annotations'

sift-annotations/build.gradle

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
plugins {
2+
id 'java-library'
3+
id 'maven-publish'
4+
id 'signing'
5+
}
6+
7+
java {
8+
toolchain {
9+
languageVersion = JavaLanguageVersion.of(17)
10+
}
11+
withJavadocJar()
12+
withSourcesJar()
13+
}
14+
15+
dependencies {
16+
api project(':sift-core')
17+
18+
compileOnly 'jakarta.validation:jakarta.validation-api:3.0.2'
19+
20+
testImplementation 'org.junit.jupiter:junit-jupiter:5.10.2'
21+
testImplementation 'org.hibernate.validator:hibernate-validator:8.0.1.Final'
22+
testImplementation 'org.glassfish:jakarta.el:4.0.2'
23+
24+
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
25+
}
26+
27+
test {
28+
useJUnitPlatform()
29+
}
30+
31+
publishing {
32+
publications {
33+
mavenJava(MavenPublication) {
34+
artifactId = 'sift-annotations'
35+
from components.java
36+
37+
pom {
38+
name = 'Sift Annotations'
39+
description = 'Jakarta Validation annotations powered by Sift Fluent Regex Builder.'
40+
url = 'https://github.com/mirkoddd/Sift'
41+
42+
licenses {
43+
license {
44+
name = 'The Apache License, Version 2.0'
45+
url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
46+
}
47+
}
48+
49+
developers {
50+
developer {
51+
id = 'mirko_ddd'
52+
name = 'Mirko Dimartino'
53+
email = 'mirkoddd@gmail.com'
54+
}
55+
}
56+
57+
scm {
58+
connection = 'scm:git:git://github.com/mirkoddd/Sift.git'
59+
developerConnection = 'scm:git:ssh://github.com:mirkoddd/Sift.git'
60+
url = 'https://github.com/mirkoddd/Sift'
61+
}
62+
}
63+
}
64+
}
65+
66+
repositories {
67+
maven {
68+
name = "Staging"
69+
url = layout.buildDirectory.dir("repos/bundles")
70+
}
71+
}
72+
}
73+
74+
signing {
75+
sign publishing.publications.mavenJava
76+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright 2026 Mirko Dimartino
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.mirkoddd.sift;
17+
18+
import jakarta.validation.Constraint;
19+
import jakarta.validation.Payload;
20+
import java.lang.annotation.Documented;
21+
import java.lang.annotation.ElementType;
22+
import java.lang.annotation.Retention;
23+
import java.lang.annotation.RetentionPolicy;
24+
import java.lang.annotation.Target;
25+
26+
/**
27+
* The annotated {@code CharSequence} must match the regular expression defined
28+
* by the specified {@link SiftRegexProvider}.
29+
* <p>
30+
* {@code null} elements are considered valid. Use standard {@link jakarta.validation.constraints.NotNull}
31+
* annotations alongside {@link SiftMatch} to ensure the value is present.
32+
* @author Mirko Dimartino
33+
* @since 1.1.0
34+
*/
35+
@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD, ElementType.ANNOTATION_TYPE})
36+
@Retention(RetentionPolicy.RUNTIME)
37+
@Constraint(validatedBy = SiftMatchValidator.class)
38+
@Documented
39+
public @interface SiftMatch {
40+
41+
/**
42+
* The class implementing {@link SiftRegexProvider} that contains the {@link SiftBuilder} logic.
43+
* The referenced class must have a public no-args constructor.
44+
*
45+
* @return the provider class
46+
*/
47+
Class<? extends SiftRegexProvider> value();
48+
49+
/**
50+
* @return the error message template
51+
*/
52+
String message() default "The provided value does not match the required Sift pattern";
53+
54+
/**
55+
* @return the groups the constraint belongs to
56+
*/
57+
Class<?>[] groups() default {};
58+
59+
/**
60+
* @return the payload associated to the constraint
61+
*/
62+
Class<? extends Payload>[] payload() default {};
63+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright 2026 Mirko Dimartino
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.mirkoddd.sift;
17+
18+
import jakarta.validation.ConstraintValidator;
19+
import jakarta.validation.ConstraintValidatorContext;
20+
import java.util.regex.Pattern;
21+
22+
/**
23+
* Engine that validates a {@link CharSequence} against a rule defined by a {@link SiftRegexProvider}.
24+
* <p>
25+
* For performance optimization, this validator compiles the regular expression into a
26+
* {@link java.util.regex.Pattern} only once during initialization, rather than on every validation call.
27+
* @author Mirko Dimartino
28+
* @since 1.1.0
29+
*/
30+
public final class SiftMatchValidator implements ConstraintValidator<SiftMatch, CharSequence> {
31+
32+
private Pattern compiledPattern;
33+
34+
@Override
35+
public void initialize(SiftMatch constraintAnnotation) {
36+
try {
37+
SiftRegexProvider provider = constraintAnnotation.value().getDeclaredConstructor().newInstance();
38+
String rawRegex = provider.getRegex();
39+
this.compiledPattern = Pattern.compile(rawRegex);
40+
} catch (Exception e) {
41+
throw new RuntimeException("Failed to initialize SiftRegexProvider: " + constraintAnnotation.value().getName() + ". Ensure it has a public no-args constructor.", e);
42+
}
43+
}
44+
45+
@Override
46+
public boolean isValid(CharSequence value, ConstraintValidatorContext context) {
47+
if (value == null) {
48+
return true;
49+
}
50+
return compiledPattern.matcher(value).matches();
51+
}
52+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright 2026 Mirko Dimartino
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.mirkoddd.sift;
17+
18+
/**
19+
* Contract for defining a custom Regular Expression rule using the Sift Fluent Builder.
20+
* <p>
21+
* Implementations of this interface must provide a no-argument constructor so the
22+
* validation engine can instantiate them via reflection.
23+
* <p>
24+
* <b>Example usage:</b>
25+
* <pre>
26+
* {@code
27+
* public class AlphanumericRule implements SiftRegexProvider {
28+
* @Override
29+
* public String getRegex() {
30+
* return Sift.fromStart()
31+
* .oneOrMore().alphanumeric()
32+
* .shake();
33+
* }
34+
* }
35+
* }
36+
* </pre>
37+
* @author Mirko Dimartino
38+
* @since 1.1.0
39+
*/
40+
public interface SiftRegexProvider {
41+
42+
/**
43+
* Provides the raw Regex string generated by {@link SiftBuilder}.
44+
*
45+
* @return the compiled regex string (typically obtained by calling {@code .shake()})
46+
*/
47+
String getRegex();
48+
}

0 commit comments

Comments
 (0)