diff --git a/api/src/main/java/jakarta/data/Limit.java b/api/src/main/java/jakarta/data/Limit.java index 1617284fe..5a18cb875 100644 --- a/api/src/main/java/jakarta/data/Limit.java +++ b/api/src/main/java/jakarta/data/Limit.java @@ -34,7 +34,7 @@ * *
  * @Find
- * Product[] namedLike(@By(_Product.NAME) @Is(Like.class) String namePattern,
+ * Product[] namedLike(@By(_Product.NAME) @IgnoreCase @Is(Like.class) String namePattern,
  *                     Limit limit,
  *                     Sort<?>... sorts);
  *
diff --git a/api/src/main/java/jakarta/data/constraint/Constraint.java b/api/src/main/java/jakarta/data/constraint/Constraint.java
index c038d6cb6..d31101e11 100644
--- a/api/src/main/java/jakarta/data/constraint/Constraint.java
+++ b/api/src/main/java/jakarta/data/constraint/Constraint.java
@@ -44,8 +44,8 @@
  * 
  * @Find
  * List<Car> withinYears(@By(_Car.YEAR) Between<Integer> year,
- *                       @By(_Car.MAKE) Like makePattern,
- *                       @By(_Car.MODEL) Like modelPattern,
+ *                       @By(_Car.MAKE) @IgnoreCase Like makePattern,
+ *                       @By(_Car.MODEL) @IgnoreCase Like modelPattern,
  *                       Order<Car> sorts);
  *
  * ...
@@ -68,8 +68,8 @@
  * 
  * @Find
  * List<Car> pricedAtMost(@By(_Car.PRICE) @Is(AtMost.class) int maxPrice,
- *                        @By(_Car.MAKE) @Is(Like.class) String makePattern,
- *                        @By(_Car.MODEL) @Is(Like.class) Sting modelPattern,
+ *                        @By(_Car.MAKE) @IgnoreCase @Is(Like.class) String makePattern,
+ *                        @By(_Car.MODEL) @IgnoreCase @Is(Like.class) Sting modelPattern,
  *                        Order<Car> sorts);
  *
  * ...
diff --git a/api/src/main/java/jakarta/data/constraint/EqualTo.java b/api/src/main/java/jakarta/data/constraint/EqualTo.java
index e01c2ab66..60bbbbf62 100644
--- a/api/src/main/java/jakarta/data/constraint/EqualTo.java
+++ b/api/src/main/java/jakarta/data/constraint/EqualTo.java
@@ -36,16 +36,16 @@
  *
  * 
  * @Find
- * List<Car> fromManufacturer(@By(_Car.MAKE) EqualTo<String> manufacturer);
+ * List<Car> fromManufacturer(@By(_Car.MAKE) @IgnoreCase EqualTo<String> manufacturer);
  *
  * @Find
- * List<Car> ofMakeAndModel(@By(_Car.MAKE) @Is(EqualTo.class) String manufacturer,
- *                          @By(_Car.MODEL) @Is(EqualTo.class) String model,
+ * List<Car> ofMakeAndModel(@By(_Car.MAKE) @IgnoreCase @Is(EqualTo.class) String manufacturer,
+ *                          @By(_Car.MODEL) @IgnoreCase @Is(EqualTo.class) String model,
  *                          Order<Car> sorts);
  *
  * @Find
- * List<Car> ofMakeAndModelAndYear(@By(_Car.MAKE) String manufacturer,
- *                                 @By(_Car.MODEL) String model,
+ * List<Car> ofMakeAndModelAndYear(@By(_Car.MAKE) @IgnoreCase String manufacturer,
+ *                                 @By(_Car.MODEL) @IgnoreCase String model,
  *                                 @By(_Car.YEAR) int modelYear,
  *                                 Order<Car> sorts);
  * ...
diff --git a/api/src/main/java/jakarta/data/constraint/Like.java b/api/src/main/java/jakarta/data/constraint/Like.java
index 76e1372fc..0c8b0d488 100644
--- a/api/src/main/java/jakarta/data/constraint/Like.java
+++ b/api/src/main/java/jakarta/data/constraint/Like.java
@@ -41,11 +41,12 @@
  * List<Car> matchVIN(@By(_Car.VIN) Like vinPattern);
  *
  * @Find // requires the -parameters compiler option to preserve parameter names
- * List<Car> makeAndModel(Like make, Like model);
+ * List<Car> makeAndModel(@IgnoreCase Like make,
+ *                        @IgnoreCase Like model);
  *
  * @Find
- * List<Car> search(@By(_Car.MAKE) @Is(Like.class) String makePattern,
- *                  @By(_Car.MODEL) @Is(Like.class) String modelPattern,
+ * List<Car> search(@By(_Car.MAKE) @IgnoreCase @Is(Like.class) String makePattern,
+ *                  @By(_Car.MODEL) @IgnoreCase @Is(Like.class) String modelPattern,
  *                  Order<Car> sorts);
  *
  * ...
diff --git a/api/src/main/java/jakarta/data/constraint/NotEqualTo.java b/api/src/main/java/jakarta/data/constraint/NotEqualTo.java
index e8e81980d..30da7777c 100644
--- a/api/src/main/java/jakarta/data/constraint/NotEqualTo.java
+++ b/api/src/main/java/jakarta/data/constraint/NotEqualTo.java
@@ -37,8 +37,8 @@
  * List<Car> excludingManufacturer(@By(_Car.MAKE) NotEqualTo<String> excludedManufacturer);
  *
  * @Find
- * List<Car> ofMakeNotModel(@By(_Car.MAKE) @Is(EqualTo.class) String manufacturer,
- *                          @By(_Car.MODEL) @Is(NotEqualTo.class) String excludedModel,
+ * List<Car> ofMakeNotModel(@By(_Car.MAKE) @IgnoreCase @Is(EqualTo.class) String manufacturer,
+ *                          @By(_Car.MODEL) @IgnoreCase @Is(NotEqualTo.class) String excludedModel,
  *                          Order<Car> sorts);
  * ...
  *
diff --git a/api/src/main/java/jakarta/data/constraint/NotLike.java b/api/src/main/java/jakarta/data/constraint/NotLike.java
index 134187eb4..c022ab6a4 100644
--- a/api/src/main/java/jakarta/data/constraint/NotLike.java
+++ b/api/src/main/java/jakarta/data/constraint/NotLike.java
@@ -38,11 +38,11 @@
  *
  * 
  * @Find
- * List<Car> matchVIN(@By(_Car.VIN) NotLike pattern);
+ * List<Car> matchVIN(@By(_Car.VIN) @IgnoreCase NotLike pattern);
  *
  * @Find
- * List<Car> ofMakeNotModel(@By(_Car.MAKE) String manufacturer,
- *                          @By(_Car.MODEL) @Is(NotLike.class) String excludePattern,
+ * List<Car> ofMakeNotModel(@By(_Car.MAKE) @IgnoreCase String manufacturer,
+ *                          @By(_Car.MODEL) @IgnoreCase @Is(NotLike.class) String excludePattern,
  *                          Order<Car> sorts);
  *
  * ...
diff --git a/api/src/main/java/jakarta/data/page/Page.java b/api/src/main/java/jakarta/data/page/Page.java
index 03c18aa6f..3964d1208 100644
--- a/api/src/main/java/jakarta/data/page/Page.java
+++ b/api/src/main/java/jakarta/data/page/Page.java
@@ -30,8 +30,8 @@
  *
  * 
  * @Find
- * Page<Vehicle> search(@By("make") String make,
- *                      @By("model") String model,
+ * Page<Vehicle> search(@By("make") @IgnoreCase String make,
+ *                      @By("model") @IgnoreCase String model,
  *                      @By("year") int designYear,
  *                      PageRequest pageRequest,
  *                      Order<Vehicle> order);
diff --git a/api/src/main/java/jakarta/data/repository/By.java b/api/src/main/java/jakarta/data/repository/By.java
index 5472e1622..e951b23ac 100644
--- a/api/src/main/java/jakarta/data/repository/By.java
+++ b/api/src/main/java/jakarta/data/repository/By.java
@@ -52,11 +52,11 @@
  *     Person findById(@By(ID) String id); // maps to Person.ssn
  *
  *     @Find
- *     List<Person> findNamed(@By("firstName") String first,
- *                            @By("lastName") String last);
+ *     List<Person> findNamed(@By("firstName") @IgnoreCase String first,
+ *                            @By("lastName") @IgnoreCase String last);
  *
  *     @Find
- *     List<Person> findByCity(@By("address.city") String city);
+ *     List<Person> findByCity(@By("address.city") @IgnoreCase String city);
  * }
  * 
* @@ -76,11 +76,11 @@ * Person findById(String ssn); * * @Find - * List<Person> findNamed(String firstName, - * String lastname); + * List<Person> findNamed(@IgnoreCase String firstName, + * @IgnoreCase String lastname); * * @Find - * List<Person> findByCity(String address_city); + * List<Person> findByCity(@IgnoreCase String address_city); * } *
*/ diff --git a/api/src/main/java/jakarta/data/repository/Find.java b/api/src/main/java/jakarta/data/repository/Find.java index d664f7c4b..33320c767 100644 --- a/api/src/main/java/jakarta/data/repository/Find.java +++ b/api/src/main/java/jakarta/data/repository/Find.java @@ -79,7 +79,7 @@ * @Repository * interface Garage { * @Find - * List<Car> getCarsWithModel(@By("model") String model); + * List<Car> getCarsWithModel(@By("model") @IgnoreCase String model); * } *
*

The {@code @Find} annotation indicates that the {@code getCarsWithModel(model)} diff --git a/api/src/main/java/jakarta/data/repository/IgnoreCase.java b/api/src/main/java/jakarta/data/repository/IgnoreCase.java new file mode 100644 index 000000000..352cd4261 --- /dev/null +++ b/api/src/main/java/jakarta/data/repository/IgnoreCase.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2025 Contributors to the Eclipse Foundation + * + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package jakarta.data.repository; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import jakarta.data.constraint.AtLeast; +import jakarta.data.constraint.AtMost; +import jakarta.data.constraint.Between; +import jakarta.data.constraint.EqualTo; +import jakarta.data.constraint.GreaterThan; +import jakarta.data.constraint.LessThan; +import jakarta.data.constraint.Like; +import jakarta.data.constraint.NotBetween; +import jakarta.data.constraint.NotEqualTo; +import jakarta.data.constraint.NotLike; + +/** + *

Annotates a parameter of a repository {@link Find} or {@link Delete} + * method, to compare an entity attribute ignoring case.

+ * + *

The parameter must correspond to a {@link String}-typed entity attribute + * and must either be an implicit equality constraint or one of the following + * constraints, indicated by the method parameter's type or its {@link Is @Is} + * annotation. + * + *

    + *
  • {@link AtLeast}
  • + *
  • {@link AtMost}
  • + *
  • {@link Between} (not available for {@code @Is})
  • + *
  • {@link EqualTo}
  • + *
  • {@link GreaterThan}
  • + *
  • {@link LessThan}
  • + *
  • {@link Like}
  • + *
  • {@link NotBetween} (not available for {@code @Is})
  • + *
  • {@link NotEqualTo}
  • + *
  • {@link NotLike}
  • + *
+ * + *

For example,

+ * + *
+ * @Repository
+ * public interface People extends BasicRepository<Person, Long> {
+ *
+ *     // List of Person entities where the lastName attribute matches a
+ *     // literal value, ignoring case.
+ *     // Requires the -parameters compile option.
+ *     @Find
+ *     List<Person> ofSurname(@IgnoreCase String lastName);
+ *
+ *     // List of Person entities where the lastName attribute matches a
+ *     // pattern, ignoring case.
+ *     @Find
+ *     @OrderBy(_Person.LASTNAME)
+ *     @OrderBy(_Person.FIRSTNAME)
+ *     List<Person> surnamed(@By(_Person.LASTNAME) @IgnoreCase Like pattern);
+ *
+ *     // List of Person entities where the lastName attribute, is alphabetized
+ *     // within the first parameter up to but not including the second
+ *     // parameter, ignoring case.
+ *     @Find
+ *     @OrderBy(_Person.LASTNAME)
+ *     @OrderBy(_Person.FIRSTNAME)
+ *     List<Person> withinSurnameRange(
+ *         @By(_Person.LASTNAME) @IgnoreCase @Is(AtLeast.class) String beginAt,
+ *         @By(_Person.LASTNAME) @IgnoreCase @Is(LessThan.class) String endBefore);
+ * }
+ *
+ * ...
+ *
+ * smiths = people.ofSurname("smith");
+ * aNames = people.surnamed(Like.pattern("A%"));
+ * surnamesAToE = people.withinSurnameRange("A", "F");
+ * 
+ */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.PARAMETER) +public @interface IgnoreCase { +} diff --git a/api/src/main/java/jakarta/data/repository/Is.java b/api/src/main/java/jakarta/data/repository/Is.java index 3d8abea58..74d851422 100644 --- a/api/src/main/java/jakarta/data/repository/Is.java +++ b/api/src/main/java/jakarta/data/repository/Is.java @@ -59,7 +59,7 @@ * * // Find a page of Product entities where the name field matches a pattern. * @Find - * Page<Product> search(@By(_Product.NAME) @Is(Like.class) String pattern, + * Page<Product> search(@By(_Product.NAME) @IgnoreCase @Is(Like.class) String pattern, * PageRequest pagination, * Order<Product> order); * diff --git a/api/src/main/java/jakarta/data/repository/OrderBy.java b/api/src/main/java/jakarta/data/repository/OrderBy.java index a6458e4d9..e419b8052 100644 --- a/api/src/main/java/jakarta/data/repository/OrderBy.java +++ b/api/src/main/java/jakarta/data/repository/OrderBy.java @@ -119,7 +119,7 @@ *
      * @Find
      * @OrderBy("age")
-     * Stream<Person> withLastName(@By("lastName") String surname);
+     * Stream<Person> withLastName(@By("lastName") @IgnoreCase String surname);
      * 
* * @return entity attribute name. diff --git a/api/src/main/java/jakarta/data/repository/Repository.java b/api/src/main/java/jakarta/data/repository/Repository.java index 1c68fc539..282b47364 100644 --- a/api/src/main/java/jakarta/data/repository/Repository.java +++ b/api/src/main/java/jakarta/data/repository/Repository.java @@ -40,7 +40,7 @@ * * @Find * @OrderBy("price") - * List<Product> namedLike(@By("name") @Is(Like.class) String namePattern); + * List<Product> namedLike(@By("name") @IgnoreCase @Is(Like.class) String namePattern); * * @Query("UPDATE Product SET price = price - (price * ?1) WHERE price * ?1 <= ?2") * int putOnSale(float rateOfDiscount, float maxDiscount); diff --git a/api/src/main/java/jakarta/data/restrict/Restriction.java b/api/src/main/java/jakarta/data/restrict/Restriction.java index 255ce9276..64978d02b 100644 --- a/api/src/main/java/jakarta/data/restrict/Restriction.java +++ b/api/src/main/java/jakarta/data/restrict/Restriction.java @@ -46,8 +46,8 @@ * public interface Cars extends CrudRepository<Car, String> { * * @Find - * List<Car> search(@By(_Car.MAKE) String manufacturer, - * @By(_Car.MODEL) String model, + * List<Car> search(@By(_Car.MAKE) @IgnoreCase String manufacturer, + * @By(_Car.MODEL) @IgnoreCase String model, * Restriction<Car> restriction, * Order<Car>... sort); * } diff --git a/api/src/main/java/module-info.java b/api/src/main/java/module-info.java index 021de152f..0e750b0d1 100644 --- a/api/src/main/java/module-info.java +++ b/api/src/main/java/module-info.java @@ -86,7 +86,7 @@ * * @Find * List<Product> search( - * @By(_Product.NAME) @Is(Like.class) String namePattern, + * @By(_Product.NAME) @IgnoreCase @Is(Like.class) String namePattern, * Restriction<Product> restriction, * Order<Product> sortBy); * @@ -383,7 +383,7 @@ * * @Find * @OrderBy("price") - * Product[] named(String name); + * Product[] named(@IgnoreCase String name); *
* *
  • The parameter is a {@link Constraint} or a @@ -448,7 +448,7 @@ * *
      * @Find
    - * Stream<Person> livingInCity(String address_city);
    + * Stream<Person> livingInCity(@IgnoreCase String address_city);
      * 
    * *

    JDQL query methods

    @@ -893,7 +893,7 @@ * *
      * @Find
    - * Page<Product> pricedWithin(@By("name") @Is(Like.class) String pattern,
    + * Page<Product> pricedWithin(@By("name") @IgnoreCase @Is(Like.class) String pattern,
      *                            @By("price") @Is(AtLeast.class) float minPrice,
      *                            @By("price") @Is(AtMost.class) float maxPrice,
      *                            PageRequest pageRequest,
    @@ -917,7 +917,7 @@
      *
      * 
      * @Find
    - * Product[] named(@By("name") @Is(Like.class) String pattern,
    + * Product[] named(@By("name") @IgnoreCase @Is(Like.class) String pattern,
      *                 Limit max,
      *                 Order<Product> sortBy);
      *
    @@ -935,7 +935,7 @@
      *
      * 
      * @Find
    - * Product[] namedLike(@By("name") @Is(Like.class) String pattern,
    + * Product[] namedLike(@By("name") @IgnoreCase @Is(Like.class) String pattern,
      *                     Limit max,
      *                     {@code Sort...} sortBy);
      *
    @@ -957,7 +957,7 @@
      *
      * 
      *     @Find
    - *     List<Product> namedLike(@By(_Product.NAME) Like pattern,
    + *     List<Product> namedLike(@By(_Product.NAME) @IgnoreCase Like pattern,
      *                             Restriction<Product> restrict,
      *                             Order<Product> sorts);
      * 
    diff --git a/spec/src/main/asciidoc/repository.asciidoc b/spec/src/main/asciidoc/repository.asciidoc index e13cb09ac..b443ca91c 100644 --- a/spec/src/main/asciidoc/repository.asciidoc +++ b/spec/src/main/asciidoc/repository.asciidoc @@ -412,7 +412,7 @@ For example: @Repository public interface ProductRepository { @Find - List search(@By(_Product.DESCRIPTION) @Is(Like.class) description, + List search(@By(_Product.DESCRIPTION) @IgnoreCase @Is(Like.class) description, Restriction restriction); } ---- @@ -760,8 +760,8 @@ In this example, the application uses `OrderBy` to define a subset of the sort c public interface Products extends CrudRepository { @Find @OrderBy(_Car.VEHICLE_CONDITION) - CursoredPage find(@By(_Car.MAKE) String manufacturer, - @By(_Car.MODEL) String model, + CursoredPage find(@By(_Car.MAKE) @IgnoreCase String manufacturer, + @By(_Car.MODEL) @IgnoreCase String model, PageRequest pageRequest, Order sorts); }