diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a61b8b89..324cff2e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ you are unable to move to this version of Java then the releases in the 1.x line In addition, we have taken the opportunity to make changes to the library that may break existing code. We have worked to make these changes as minimal as possible. -**Potentially Breaking Changes:** +### Potentially Breaking Changes: - If you use this library with MyBatis' Spring Batch integration, you will need to make changes as we have refactored that support to be more flexible. Please see the @@ -25,7 +25,65 @@ worked to make these changes as minimal as possible. [Extending the Library](https://mybatis.org/mybatis-dynamic-sql/docs/extending.html) page, the change should be limited to changing the private constructor to accept `BasicColumn` rather than `BindableColumn`. -Other important changes: +### Adoption of JSpecify (https://jspecify.dev/) + +Following the lead of many other projects (including The Spring Framework), we have adopted JSpecify to fully +document the null handling properties of this library. JSpecify is now a runtime dependency - as is +recommended practice with JSpecify. + +This change should not impact the running of any existing code, but depending on your usage you may see new IDE or +tooling warnings based on the declared nullability of methods in the library. You may choose to ignore the +warnings and things should continue to function. Of course, we recommend that you do not ignore these warnings! + +In general, the library does not expect that you will pass a null value into any method. There are two exceptions to +this rule: + +1. Some builder methods will accept a null value if the target object will properly handle null values through the + use of java.util.Optional +2. Methods with names that include "WhenPresent" will properly handle null parameters + (for example, "isEqualToWhenPresent") + +As you might expect, standardizing null handling revealed some issues in the library that may impact you. + +Fixing compiler warnings and errors: + +1. We expect that most of the warnings you encounter will be related to passing null values into a where condition. + These warnings should be resolved by changing your code to use the "WhenPresent" versions of methods as those + methods handle null values in a predictable way. +2. Java Classes that extend "AliasableSqlTable" will likely see IDE warnings about non-null type arguments. This can be + resolved by adding a "@NullMarked" annotation to the class or package. This issue does not affect Kotlin classes + that extend "AliasableSqlTable". +3. Similarly, if you have coded any functions for use with your queries, you can resolve most IDE warnings by adding + the "@NullMarked" annotation. +4. If you have coded any Kotlin functions that operate on a generic Java class from the library, then you should + change the type parameter definition to specify a non-nullable type. For example... + + ```kotlin + import org.mybatis.dynamic.sql.SqlColumn + + fun foo(column: SqlColumn) { + } + ``` + + Should change to: + + ```kotlin + import org.mybatis.dynamic.sql.SqlColumn + + fun foo(column: SqlColumn) { + } + ``` + +Runtime behavior changes: + +1. The where conditions (isEqualTo, isLessThan, etc.) can be filtered and result in an "empty" condition - + similar to java.util.Optional. Previously, calling a "value" method of the condition would return null. Now + those methods will throw "NoSuchElementException". This should not impact you in normal usage. +2. We have updated the "ParameterTypeConverter" used in Spring applications to maintain compatibility with Spring's + "Converter" interface. The primary change is that the framework will no longer call a type converter if the + input value is null. This should simplify the coding of converters and foster reuse with existing Spring converters. + +### Other important changes: - The library now requires Java 17 - Deprecated code from prior releases is removed diff --git a/README.md b/README.md index 812dc3b9d..3a536a47a 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,10 @@ The library test cases provide several complete examples of using the library in | Kotlin | Spring JDBC | Example using Kotlin utility classes for Spring JDBC Template | [../examples/kotlin/spring/canonical](src/test/kotlin/examples/kotlin/spring/canonical) | -## Requirements +## Requirements and Dependencies -The library has no dependencies. Version 2.x requires Java 17. Version 1.x requires Java 8. +Version 2.x requires Java 17 and has a required runtime dependency on JSpecify (https://jspecify.dev/). Version 1.x +requires Java 8 and has no required runtime dependencies. + +All versions have support for MyBatis3, Spring Framework, and Kotlin - all those dependencies are optional. The library +should work in those environments as the dependencies will be made available at runtime. diff --git a/pom.xml b/pom.xml index 2ace93179..28fba05ab 100644 --- a/pom.xml +++ b/pom.xml @@ -86,6 +86,11 @@ + + org.jspecify + jspecify + 1.0.0 + org.jetbrains.kotlin kotlin-stdlib-jdk8 diff --git a/src/main/java/org/mybatis/dynamic/sql/AliasableSqlTable.java b/src/main/java/org/mybatis/dynamic/sql/AliasableSqlTable.java index fb0c065bf..915b6a561 100644 --- a/src/main/java/org/mybatis/dynamic/sql/AliasableSqlTable.java +++ b/src/main/java/org/mybatis/dynamic/sql/AliasableSqlTable.java @@ -19,9 +19,11 @@ import java.util.Optional; import java.util.function.Supplier; +import org.jspecify.annotations.Nullable; + public abstract class AliasableSqlTable> extends SqlTable { - private String tableAlias; + private @Nullable String tableAlias; private final Supplier constructor; protected AliasableSqlTable(String tableName, Supplier constructor) { diff --git a/src/main/java/org/mybatis/dynamic/sql/AndOrCriteriaGroup.java b/src/main/java/org/mybatis/dynamic/sql/AndOrCriteriaGroup.java index 45ef362f7..ff630a036 100644 --- a/src/main/java/org/mybatis/dynamic/sql/AndOrCriteriaGroup.java +++ b/src/main/java/org/mybatis/dynamic/sql/AndOrCriteriaGroup.java @@ -21,6 +21,8 @@ import java.util.Objects; import java.util.Optional; +import org.jspecify.annotations.Nullable; + /** * This class represents a criteria group with either an AND or an OR connector. * This class is intentionally NOT derived from SqlCriterion because we only want it to be @@ -32,7 +34,7 @@ */ public class AndOrCriteriaGroup { private final String connector; - private final SqlCriterion initialCriterion; + private final @Nullable SqlCriterion initialCriterion; private final List subCriteria; private AndOrCriteriaGroup(Builder builder) { @@ -54,8 +56,8 @@ public List subCriteria() { } public static class Builder { - private String connector; - private SqlCriterion initialCriterion; + private @Nullable String connector; + private @Nullable SqlCriterion initialCriterion; private final List subCriteria = new ArrayList<>(); public Builder withConnector(String connector) { @@ -63,7 +65,7 @@ public Builder withConnector(String connector) { return this; } - public Builder withInitialCriterion(SqlCriterion initialCriterion) { + public Builder withInitialCriterion(@Nullable SqlCriterion initialCriterion) { this.initialCriterion = initialCriterion; return this; } diff --git a/src/main/java/org/mybatis/dynamic/sql/BindableColumn.java b/src/main/java/org/mybatis/dynamic/sql/BindableColumn.java index 88d146b2c..0fd90b7c8 100644 --- a/src/main/java/org/mybatis/dynamic/sql/BindableColumn.java +++ b/src/main/java/org/mybatis/dynamic/sql/BindableColumn.java @@ -17,6 +17,8 @@ import java.util.Optional; +import org.jspecify.annotations.Nullable; + /** * Describes a column with a known data type. The type is only used by the compiler to assure type safety * when building clauses with conditions. @@ -34,7 +36,7 @@ public interface BindableColumn extends BasicColumn { @Override BindableColumn as(String alias); - default Object convertParameterType(T value) { + default @Nullable Object convertParameterType(T value) { return value; } diff --git a/src/main/java/org/mybatis/dynamic/sql/ColumnAndConditionCriterion.java b/src/main/java/org/mybatis/dynamic/sql/ColumnAndConditionCriterion.java index ca8fc8f3c..646e695c2 100644 --- a/src/main/java/org/mybatis/dynamic/sql/ColumnAndConditionCriterion.java +++ b/src/main/java/org/mybatis/dynamic/sql/ColumnAndConditionCriterion.java @@ -17,6 +17,8 @@ import java.util.Objects; +import org.jspecify.annotations.Nullable; + public class ColumnAndConditionCriterion extends SqlCriterion { private final BindableColumn column; private final VisitableCondition condition; @@ -45,8 +47,8 @@ public static Builder withColumn(BindableColumn column) { } public static class Builder extends AbstractBuilder> { - private BindableColumn column; - private VisitableCondition condition; + private @Nullable BindableColumn column; + private @Nullable VisitableCondition condition; public Builder withColumn(BindableColumn column) { this.column = column; diff --git a/src/main/java/org/mybatis/dynamic/sql/Constant.java b/src/main/java/org/mybatis/dynamic/sql/Constant.java index 0f5f2cff5..90547765f 100644 --- a/src/main/java/org/mybatis/dynamic/sql/Constant.java +++ b/src/main/java/org/mybatis/dynamic/sql/Constant.java @@ -18,19 +18,20 @@ import java.util.Objects; import java.util.Optional; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.FragmentAndParameters; public class Constant implements BindableColumn { - private final String alias; + private final @Nullable String alias; private final String value; private Constant(String value) { this(value, null); } - private Constant(String value, String alias) { + private Constant(String value, @Nullable String alias) { this.value = Objects.requireNonNull(value); this.alias = alias; } diff --git a/src/main/java/org/mybatis/dynamic/sql/CriteriaGroup.java b/src/main/java/org/mybatis/dynamic/sql/CriteriaGroup.java index b82ac296c..476cb6b3f 100644 --- a/src/main/java/org/mybatis/dynamic/sql/CriteriaGroup.java +++ b/src/main/java/org/mybatis/dynamic/sql/CriteriaGroup.java @@ -17,6 +17,8 @@ import java.util.Optional; +import org.jspecify.annotations.Nullable; + /** * This class represents a criteria group without an AND or an OR connector. This is useful * in situations where the initial SqlCriterion in a list should be further grouped @@ -27,7 +29,7 @@ * @since 1.4.0 */ public class CriteriaGroup extends SqlCriterion { - private final SqlCriterion initialCriterion; + private final @Nullable SqlCriterion initialCriterion; protected CriteriaGroup(AbstractGroupBuilder builder) { super(builder); @@ -44,9 +46,9 @@ public R accept(SqlCriterionVisitor visitor) { } public abstract static class AbstractGroupBuilder> extends AbstractBuilder { - private SqlCriterion initialCriterion; + private @Nullable SqlCriterion initialCriterion; - public T withInitialCriterion(SqlCriterion initialCriterion) { + public T withInitialCriterion(@Nullable SqlCriterion initialCriterion) { this.initialCriterion = initialCriterion; return getThis(); } diff --git a/src/main/java/org/mybatis/dynamic/sql/DerivedColumn.java b/src/main/java/org/mybatis/dynamic/sql/DerivedColumn.java index 93294efc2..df19b8d6b 100644 --- a/src/main/java/org/mybatis/dynamic/sql/DerivedColumn.java +++ b/src/main/java/org/mybatis/dynamic/sql/DerivedColumn.java @@ -19,6 +19,7 @@ import java.util.Objects; import java.util.Optional; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.FragmentAndParameters; @@ -34,10 +35,10 @@ */ public class DerivedColumn implements BindableColumn { private final String name; - private final String tableQualifier; - private final String columnAlias; - private final JDBCType jdbcType; - private final String typeHandler; + private final @Nullable String tableQualifier; + private final @Nullable String columnAlias; + private final @Nullable JDBCType jdbcType; + private final @Nullable String typeHandler; protected DerivedColumn(Builder builder) { this.name = Objects.requireNonNull(builder.name); @@ -93,18 +94,18 @@ public static DerivedColumn of(String name, String tableQualifier) { } public static class Builder { - private String name; - private String tableQualifier; - private String columnAlias; - private JDBCType jdbcType; - private String typeHandler; + private @Nullable String name; + private @Nullable String tableQualifier; + private @Nullable String columnAlias; + private @Nullable JDBCType jdbcType; + private @Nullable String typeHandler; public Builder withName(String name) { this.name = name; return this; } - public Builder withTableQualifier(String tableQualifier) { + public Builder withTableQualifier(@Nullable String tableQualifier) { this.tableQualifier = tableQualifier; return this; } @@ -114,12 +115,12 @@ public Builder withColumnAlias(String columnAlias) { return this; } - public Builder withJdbcType(JDBCType jdbcType) { + public Builder withJdbcType(@Nullable JDBCType jdbcType) { this.jdbcType = jdbcType; return this; } - public Builder withTypeHandler(String typeHandler) { + public Builder withTypeHandler(@Nullable String typeHandler) { this.typeHandler = typeHandler; return this; } diff --git a/src/main/java/org/mybatis/dynamic/sql/ExistsCriterion.java b/src/main/java/org/mybatis/dynamic/sql/ExistsCriterion.java index b91b20036..17cecdaa6 100644 --- a/src/main/java/org/mybatis/dynamic/sql/ExistsCriterion.java +++ b/src/main/java/org/mybatis/dynamic/sql/ExistsCriterion.java @@ -17,6 +17,8 @@ import java.util.Objects; +import org.jspecify.annotations.Nullable; + public class ExistsCriterion extends SqlCriterion { private final ExistsPredicate existsPredicate; @@ -35,7 +37,7 @@ public R accept(SqlCriterionVisitor visitor) { } public static class Builder extends AbstractBuilder { - private ExistsPredicate existsPredicate; + private @Nullable ExistsPredicate existsPredicate; public Builder withExistsPredicate(ExistsPredicate existsPredicate) { this.existsPredicate = existsPredicate; diff --git a/src/main/java/org/mybatis/dynamic/sql/ExistsPredicate.java b/src/main/java/org/mybatis/dynamic/sql/ExistsPredicate.java index 139d7e379..c22a84aa2 100644 --- a/src/main/java/org/mybatis/dynamic/sql/ExistsPredicate.java +++ b/src/main/java/org/mybatis/dynamic/sql/ExistsPredicate.java @@ -17,7 +17,6 @@ import java.util.Objects; -import org.jetbrains.annotations.NotNull; import org.mybatis.dynamic.sql.select.SelectModel; import org.mybatis.dynamic.sql.util.Buildable; @@ -38,12 +37,10 @@ public Buildable selectModelBuilder() { return selectModelBuilder; } - @NotNull public static ExistsPredicate exists(Buildable selectModelBuilder) { return new ExistsPredicate("exists", selectModelBuilder); //$NON-NLS-1$ } - @NotNull public static ExistsPredicate notExists(Buildable selectModelBuilder) { return new ExistsPredicate("not exists", selectModelBuilder); //$NON-NLS-1$ } diff --git a/src/main/java/org/mybatis/dynamic/sql/ParameterTypeConverter.java b/src/main/java/org/mybatis/dynamic/sql/ParameterTypeConverter.java index 3b053b154..4f4856e19 100644 --- a/src/main/java/org/mybatis/dynamic/sql/ParameterTypeConverter.java +++ b/src/main/java/org/mybatis/dynamic/sql/ParameterTypeConverter.java @@ -15,6 +15,8 @@ */ package org.mybatis.dynamic.sql; +import org.jspecify.annotations.Nullable; + /** * A parameter type converter is used to change a parameter value from one type to another * during statement rendering and before the parameter is placed into the parameter map. This can be used @@ -50,5 +52,13 @@ */ @FunctionalInterface public interface ParameterTypeConverter { - T convert(S source); + /** + * Convert the value from one value to another. + * + *

The input value will never be null - the framework will automatically handle nulls. + * + * @param source value as specified in the condition, or after a map operation. Never null. + * @return Possibly null converted value. + */ + @Nullable T convert(S source); } diff --git a/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java b/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java index f118136e6..8b36417fe 100644 --- a/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java +++ b/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java @@ -21,6 +21,7 @@ import java.util.Objects; import java.util.function.Supplier; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.delete.DeleteDSL; import org.mybatis.dynamic.sql.delete.DeleteModel; import org.mybatis.dynamic.sql.insert.BatchInsertDSL; @@ -633,11 +634,11 @@ static IsEqualToColumn isEqualTo(BasicColumn column) { return IsEqualToColumn.of(column); } - static IsEqualTo isEqualToWhenPresent(T value) { - return IsEqualTo.of(value).filter(Objects::nonNull); + static IsEqualTo isEqualToWhenPresent(@Nullable T value) { + return value == null ? IsEqualTo.empty() : IsEqualTo.of(value); } - static IsEqualTo isEqualToWhenPresent(Supplier valueSupplier) { + static IsEqualTo isEqualToWhenPresent(Supplier<@Nullable T> valueSupplier) { return isEqualToWhenPresent(valueSupplier.get()); } @@ -657,11 +658,11 @@ static IsNotEqualToColumn isNotEqualTo(BasicColumn column) { return IsNotEqualToColumn.of(column); } - static IsNotEqualTo isNotEqualToWhenPresent(T value) { - return IsNotEqualTo.of(value).filter(Objects::nonNull); + static IsNotEqualTo isNotEqualToWhenPresent(@Nullable T value) { + return value == null ? IsNotEqualTo.empty() : IsNotEqualTo.of(value); } - static IsNotEqualTo isNotEqualToWhenPresent(Supplier valueSupplier) { + static IsNotEqualTo isNotEqualToWhenPresent(Supplier<@Nullable T> valueSupplier) { return isNotEqualToWhenPresent(valueSupplier.get()); } @@ -681,11 +682,11 @@ static IsGreaterThanColumn isGreaterThan(BasicColumn column) { return IsGreaterThanColumn.of(column); } - static IsGreaterThan isGreaterThanWhenPresent(T value) { - return IsGreaterThan.of(value).filter(Objects::nonNull); + static IsGreaterThan isGreaterThanWhenPresent(@Nullable T value) { + return value == null ? IsGreaterThan.empty() : IsGreaterThan.of(value); } - static IsGreaterThan isGreaterThanWhenPresent(Supplier valueSupplier) { + static IsGreaterThan isGreaterThanWhenPresent(Supplier<@Nullable T> valueSupplier) { return isGreaterThanWhenPresent(valueSupplier.get()); } @@ -706,11 +707,11 @@ static IsGreaterThanOrEqualToColumn isGreaterThanOrEqualTo(BasicColumn co return IsGreaterThanOrEqualToColumn.of(column); } - static IsGreaterThanOrEqualTo isGreaterThanOrEqualToWhenPresent(T value) { - return IsGreaterThanOrEqualTo.of(value).filter(Objects::nonNull); + static IsGreaterThanOrEqualTo isGreaterThanOrEqualToWhenPresent(@Nullable T value) { + return value == null ? IsGreaterThanOrEqualTo.empty() : IsGreaterThanOrEqualTo.of(value); } - static IsGreaterThanOrEqualTo isGreaterThanOrEqualToWhenPresent(Supplier valueSupplier) { + static IsGreaterThanOrEqualTo isGreaterThanOrEqualToWhenPresent(Supplier<@Nullable T> valueSupplier) { return isGreaterThanOrEqualToWhenPresent(valueSupplier.get()); } @@ -730,11 +731,11 @@ static IsLessThanColumn isLessThan(BasicColumn column) { return IsLessThanColumn.of(column); } - static IsLessThan isLessThanWhenPresent(T value) { - return IsLessThan.of(value).filter(Objects::nonNull); + static IsLessThan isLessThanWhenPresent(@Nullable T value) { + return value == null ? IsLessThan.empty() : IsLessThan.of(value); } - static IsLessThan isLessThanWhenPresent(Supplier valueSupplier) { + static IsLessThan isLessThanWhenPresent(Supplier<@Nullable T> valueSupplier) { return isLessThanWhenPresent(valueSupplier.get()); } @@ -754,11 +755,11 @@ static IsLessThanOrEqualToColumn isLessThanOrEqualTo(BasicColumn column) return IsLessThanOrEqualToColumn.of(column); } - static IsLessThanOrEqualTo isLessThanOrEqualToWhenPresent(T value) { - return IsLessThanOrEqualTo.of(value).filter(Objects::nonNull); + static IsLessThanOrEqualTo isLessThanOrEqualToWhenPresent(@Nullable T value) { + return value == null ? IsLessThanOrEqualTo.empty() : IsLessThanOrEqualTo.of(value); } - static IsLessThanOrEqualTo isLessThanOrEqualToWhenPresent(Supplier valueSupplier) { + static IsLessThanOrEqualTo isLessThanOrEqualToWhenPresent(Supplier<@Nullable T> valueSupplier) { return isLessThanOrEqualToWhenPresent(valueSupplier.get()); } @@ -776,11 +777,11 @@ static IsInWithSubselect isIn(Buildable selectModelBuilder) } @SafeVarargs - static IsInWhenPresent isInWhenPresent(T... values) { + static IsInWhenPresent isInWhenPresent(@Nullable T... values) { return IsInWhenPresent.of(values); } - static IsInWhenPresent isInWhenPresent(Collection values) { + static IsInWhenPresent isInWhenPresent(@Nullable Collection<@Nullable T> values) { return values == null ? IsInWhenPresent.empty() : IsInWhenPresent.of(values); } @@ -798,11 +799,11 @@ static IsNotInWithSubselect isNotIn(Buildable selectModelBui } @SafeVarargs - static IsNotInWhenPresent isNotInWhenPresent(T... values) { + static IsNotInWhenPresent isNotInWhenPresent(@Nullable T... values) { return IsNotInWhenPresent.of(values); } - static IsNotInWhenPresent isNotInWhenPresent(Collection values) { + static IsNotInWhenPresent isNotInWhenPresent(@Nullable Collection<@Nullable T> values) { return values == null ? IsNotInWhenPresent.empty() : IsNotInWhenPresent.of(values); } @@ -814,11 +815,11 @@ static IsBetween.Builder isBetween(Supplier valueSupplier1) { return isBetween(valueSupplier1.get()); } - static IsBetween.WhenPresentBuilder isBetweenWhenPresent(T value1) { + static IsBetween.WhenPresentBuilder isBetweenWhenPresent(@Nullable T value1) { return IsBetween.isBetweenWhenPresent(value1); } - static IsBetween.WhenPresentBuilder isBetweenWhenPresent(Supplier valueSupplier1) { + static IsBetween.WhenPresentBuilder isBetweenWhenPresent(Supplier<@Nullable T> valueSupplier1) { return isBetweenWhenPresent(valueSupplier1.get()); } @@ -830,11 +831,11 @@ static IsNotBetween.Builder isNotBetween(Supplier valueSupplier1) { return isNotBetween(valueSupplier1.get()); } - static IsNotBetween.WhenPresentBuilder isNotBetweenWhenPresent(T value1) { + static IsNotBetween.WhenPresentBuilder isNotBetweenWhenPresent(@Nullable T value1) { return IsNotBetween.isNotBetweenWhenPresent(value1); } - static IsNotBetween.WhenPresentBuilder isNotBetweenWhenPresent(Supplier valueSupplier1) { + static IsNotBetween.WhenPresentBuilder isNotBetweenWhenPresent(Supplier<@Nullable T> valueSupplier1) { return isNotBetweenWhenPresent(valueSupplier1.get()); } @@ -847,11 +848,11 @@ static IsLike isLike(Supplier valueSupplier) { return isLike(valueSupplier.get()); } - static IsLike isLikeWhenPresent(T value) { - return IsLike.of(value).filter(Objects::nonNull); + static IsLike isLikeWhenPresent(@Nullable T value) { + return value == null ? IsLike.empty() : IsLike.of(value); } - static IsLike isLikeWhenPresent(Supplier valueSupplier) { + static IsLike isLikeWhenPresent(Supplier<@Nullable T> valueSupplier) { return isLikeWhenPresent(valueSupplier.get()); } @@ -863,11 +864,11 @@ static IsNotLike isNotLike(Supplier valueSupplier) { return isNotLike(valueSupplier.get()); } - static IsNotLike isNotLikeWhenPresent(T value) { - return IsNotLike.of(value).filter(Objects::nonNull); + static IsNotLike isNotLikeWhenPresent(@Nullable T value) { + return value == null ? IsNotLike.empty() : IsNotLike.of(value); } - static IsNotLike isNotLikeWhenPresent(Supplier valueSupplier) { + static IsNotLike isNotLikeWhenPresent(Supplier<@Nullable T> valueSupplier) { return isNotLikeWhenPresent(valueSupplier.get()); } @@ -889,11 +890,11 @@ static IsLikeCaseInsensitive isLikeCaseInsensitive(Supplier valueSupplie return isLikeCaseInsensitive(valueSupplier.get()); } - static IsLikeCaseInsensitive isLikeCaseInsensitiveWhenPresent(String value) { - return IsLikeCaseInsensitive.of(value).filter(Objects::nonNull); + static IsLikeCaseInsensitive isLikeCaseInsensitiveWhenPresent(@Nullable String value) { + return value == null ? IsLikeCaseInsensitive.empty() : IsLikeCaseInsensitive.of(value); } - static IsLikeCaseInsensitive isLikeCaseInsensitiveWhenPresent(Supplier valueSupplier) { + static IsLikeCaseInsensitive isLikeCaseInsensitiveWhenPresent(Supplier<@Nullable String> valueSupplier) { return isLikeCaseInsensitiveWhenPresent(valueSupplier.get()); } @@ -905,11 +906,11 @@ static IsNotLikeCaseInsensitive isNotLikeCaseInsensitive(Supplier valueS return isNotLikeCaseInsensitive(valueSupplier.get()); } - static IsNotLikeCaseInsensitive isNotLikeCaseInsensitiveWhenPresent(String value) { - return IsNotLikeCaseInsensitive.of(value).filter(Objects::nonNull); + static IsNotLikeCaseInsensitive isNotLikeCaseInsensitiveWhenPresent(@Nullable String value) { + return value == null ? IsNotLikeCaseInsensitive.empty() : IsNotLikeCaseInsensitive.of(value); } - static IsNotLikeCaseInsensitive isNotLikeCaseInsensitiveWhenPresent(Supplier valueSupplier) { + static IsNotLikeCaseInsensitive isNotLikeCaseInsensitiveWhenPresent(Supplier<@Nullable String> valueSupplier) { return isNotLikeCaseInsensitiveWhenPresent(valueSupplier.get()); } @@ -921,11 +922,12 @@ static IsInCaseInsensitive isInCaseInsensitive(Collection values) { return IsInCaseInsensitive.of(values); } - static IsInCaseInsensitiveWhenPresent isInCaseInsensitiveWhenPresent(String... values) { + static IsInCaseInsensitiveWhenPresent isInCaseInsensitiveWhenPresent(@Nullable String... values) { return IsInCaseInsensitiveWhenPresent.of(values); } - static IsInCaseInsensitiveWhenPresent isInCaseInsensitiveWhenPresent(Collection values) { + static IsInCaseInsensitiveWhenPresent isInCaseInsensitiveWhenPresent( + @Nullable Collection<@Nullable String> values) { return values == null ? IsInCaseInsensitiveWhenPresent.empty() : IsInCaseInsensitiveWhenPresent.of(values); } @@ -937,11 +939,12 @@ static IsNotInCaseInsensitive isNotInCaseInsensitive(Collection values) return IsNotInCaseInsensitive.of(values); } - static IsNotInCaseInsensitiveWhenPresent isNotInCaseInsensitiveWhenPresent(String... values) { + static IsNotInCaseInsensitiveWhenPresent isNotInCaseInsensitiveWhenPresent(@Nullable String... values) { return IsNotInCaseInsensitiveWhenPresent.of(values); } - static IsNotInCaseInsensitiveWhenPresent isNotInCaseInsensitiveWhenPresent(Collection values) { + static IsNotInCaseInsensitiveWhenPresent isNotInCaseInsensitiveWhenPresent( + @Nullable Collection<@Nullable String> values) { return values == null ? IsNotInCaseInsensitiveWhenPresent.empty() : IsNotInCaseInsensitiveWhenPresent.of(values); } diff --git a/src/main/java/org/mybatis/dynamic/sql/SqlColumn.java b/src/main/java/org/mybatis/dynamic/sql/SqlColumn.java index 01eb235a3..4c841d86b 100644 --- a/src/main/java/org/mybatis/dynamic/sql/SqlColumn.java +++ b/src/main/java/org/mybatis/dynamic/sql/SqlColumn.java @@ -19,7 +19,7 @@ import java.util.Objects; import java.util.Optional; -import org.jetbrains.annotations.NotNull; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.render.RenderingStrategy; import org.mybatis.dynamic.sql.util.FragmentAndParameters; @@ -29,14 +29,14 @@ public class SqlColumn implements BindableColumn, SortSpecification { protected final String name; protected final SqlTable table; - protected final JDBCType jdbcType; + protected final @Nullable JDBCType jdbcType; protected final String descendingPhrase; - protected final String alias; - protected final String typeHandler; - protected final RenderingStrategy renderingStrategy; + protected final @Nullable String alias; + protected final @Nullable String typeHandler; + protected final @Nullable RenderingStrategy renderingStrategy; protected final ParameterTypeConverter parameterTypeConverter; - protected final String tableQualifier; - protected final Class javaType; + protected final @Nullable String tableQualifier; + protected final @Nullable Class javaType; private SqlColumn(Builder builder) { name = Objects.requireNonNull(builder.name); @@ -80,8 +80,8 @@ public Optional> javaType() { } @Override - public Object convertParameterType(T value) { - return parameterTypeConverter.convert(value); + public @Nullable Object convertParameterType(@Nullable T value) { + return value == null ? null : parameterTypeConverter.convert(value); } @Override @@ -144,25 +144,21 @@ public Optional renderingStrategy() { return Optional.ofNullable(renderingStrategy); } - @NotNull public SqlColumn withTypeHandler(String typeHandler) { Builder b = copy(); return b.withTypeHandler(typeHandler).build(); } - @NotNull public SqlColumn withRenderingStrategy(RenderingStrategy renderingStrategy) { Builder b = copy(); return b.withRenderingStrategy(renderingStrategy).build(); } - @NotNull public SqlColumn withParameterTypeConverter(ParameterTypeConverter parameterTypeConverter) { Builder b = copy(); return b.withParameterTypeConverter(parameterTypeConverter).build(); } - @NotNull public SqlColumn withJavaType(Class javaType) { Builder b = copy(); return b.withJavaType(javaType).build(); @@ -206,16 +202,16 @@ public static SqlColumn of(String name, SqlTable table, JDBCType jdbcType } public static class Builder { - protected String name; - protected SqlTable table; - protected JDBCType jdbcType; + protected @Nullable String name; + protected @Nullable SqlTable table; + protected @Nullable JDBCType jdbcType; protected String descendingPhrase = ""; //$NON-NLS-1$ - protected String alias; - protected String typeHandler; - protected RenderingStrategy renderingStrategy; + protected @Nullable String alias; + protected @Nullable String typeHandler; + protected @Nullable RenderingStrategy renderingStrategy; protected ParameterTypeConverter parameterTypeConverter = v -> v; - protected String tableQualifier; - protected Class javaType; + protected @Nullable String tableQualifier; + protected @Nullable Class javaType; public Builder withName(String name) { this.name = name; @@ -227,7 +223,7 @@ public Builder withTable(SqlTable table) { return this; } - public Builder withJdbcType(JDBCType jdbcType) { + public Builder withJdbcType(@Nullable JDBCType jdbcType) { this.jdbcType = jdbcType; return this; } @@ -237,17 +233,17 @@ public Builder withDescendingPhrase(String descendingPhrase) { return this; } - public Builder withAlias(String alias) { + public Builder withAlias(@Nullable String alias) { this.alias = alias; return this; } - public Builder withTypeHandler(String typeHandler) { + public Builder withTypeHandler(@Nullable String typeHandler) { this.typeHandler = typeHandler; return this; } - public Builder withRenderingStrategy(RenderingStrategy renderingStrategy) { + public Builder withRenderingStrategy(@Nullable RenderingStrategy renderingStrategy) { this.renderingStrategy = renderingStrategy; return this; } @@ -257,12 +253,12 @@ public Builder withParameterTypeConverter(ParameterTypeConverter parame return this; } - private Builder withTableQualifier(String tableQualifier) { + private Builder withTableQualifier(@Nullable String tableQualifier) { this.tableQualifier = tableQualifier; return this; } - public Builder withJavaType(Class javaType) { + public Builder withJavaType(@Nullable Class javaType) { this.javaType = javaType; return this; } diff --git a/src/main/java/org/mybatis/dynamic/sql/SqlTable.java b/src/main/java/org/mybatis/dynamic/sql/SqlTable.java index ac3665532..fab3d8c2a 100644 --- a/src/main/java/org/mybatis/dynamic/sql/SqlTable.java +++ b/src/main/java/org/mybatis/dynamic/sql/SqlTable.java @@ -19,8 +19,6 @@ import java.util.Objects; import java.util.Optional; -import org.jetbrains.annotations.NotNull; - public class SqlTable implements TableExpression { protected String tableName; @@ -37,17 +35,14 @@ public BasicColumn allColumns() { return SqlColumn.of("*", this); //$NON-NLS-1$ } - @NotNull public SqlColumn column(String name) { return SqlColumn.of(name, this); } - @NotNull public SqlColumn column(String name, JDBCType jdbcType) { return SqlColumn.of(name, this, jdbcType); } - @NotNull public SqlColumn column(String name, JDBCType jdbcType, String typeHandler) { SqlColumn column = SqlColumn.of(name, this, jdbcType); return column.withTypeHandler(typeHandler); diff --git a/src/main/java/org/mybatis/dynamic/sql/StringConstant.java b/src/main/java/org/mybatis/dynamic/sql/StringConstant.java index 0187bb1fa..ae9f0a75b 100644 --- a/src/main/java/org/mybatis/dynamic/sql/StringConstant.java +++ b/src/main/java/org/mybatis/dynamic/sql/StringConstant.java @@ -18,20 +18,21 @@ import java.util.Objects; import java.util.Optional; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.FragmentAndParameters; import org.mybatis.dynamic.sql.util.StringUtilities; public class StringConstant implements BindableColumn { - private final String alias; + private final @Nullable String alias; private final String value; private StringConstant(String value) { this(value, null); } - private StringConstant(String value, String alias) { + private StringConstant(String value, @Nullable String alias) { this.value = Objects.requireNonNull(value); this.alias = alias; } diff --git a/src/main/java/org/mybatis/dynamic/sql/common/AbstractBooleanExpressionDSL.java b/src/main/java/org/mybatis/dynamic/sql/common/AbstractBooleanExpressionDSL.java index d2acdde2e..c671b39a9 100644 --- a/src/main/java/org/mybatis/dynamic/sql/common/AbstractBooleanExpressionDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/common/AbstractBooleanExpressionDSL.java @@ -19,7 +19,7 @@ import java.util.Arrays; import java.util.List; -import org.jetbrains.annotations.NotNull; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AndOrCriteriaGroup; import org.mybatis.dynamic.sql.BindableColumn; import org.mybatis.dynamic.sql.ColumnAndConditionCriterion; @@ -31,86 +31,72 @@ import org.mybatis.dynamic.sql.util.Validator; public abstract class AbstractBooleanExpressionDSL> { - private SqlCriterion initialCriterion; // WARNING - may be null! + private @Nullable SqlCriterion initialCriterion; protected final List subCriteria = new ArrayList<>(); - @NotNull public T and(BindableColumn column, VisitableCondition condition, AndOrCriteriaGroup... subCriteria) { return and(column, condition, Arrays.asList(subCriteria)); } - @NotNull public T and(BindableColumn column, VisitableCondition condition, List subCriteria) { addSubCriteria("and", buildCriterion(column, condition), subCriteria); //$NON-NLS-1$ return getThis(); } - @NotNull public T and(ExistsPredicate existsPredicate, AndOrCriteriaGroup... subCriteria) { return and(existsPredicate, Arrays.asList(subCriteria)); } - @NotNull public T and(ExistsPredicate existsPredicate, List subCriteria) { addSubCriteria("and", buildCriterion(existsPredicate), subCriteria); //$NON-NLS-1$ return getThis(); } - @NotNull public T and(SqlCriterion initialCriterion, AndOrCriteriaGroup... subCriteria) { return and(initialCriterion, Arrays.asList(subCriteria)); } - @NotNull public T and(SqlCriterion initialCriterion, List subCriteria) { addSubCriteria("and", buildCriterion(initialCriterion), subCriteria); //$NON-NLS-1$ return getThis(); } - @NotNull public T and(List criteria) { addSubCriteria("and", criteria); //$NON-NLS-1$ return getThis(); } - @NotNull public T or(BindableColumn column, VisitableCondition condition, AndOrCriteriaGroup... subCriteria) { return or(column, condition, Arrays.asList(subCriteria)); } - @NotNull public T or(BindableColumn column, VisitableCondition condition, List subCriteria) { addSubCriteria("or", buildCriterion(column, condition), subCriteria); //$NON-NLS-1$ return getThis(); } - @NotNull public T or(ExistsPredicate existsPredicate, AndOrCriteriaGroup... subCriteria) { return or(existsPredicate, Arrays.asList(subCriteria)); } - @NotNull public T or(ExistsPredicate existsPredicate, List subCriteria) { addSubCriteria("or", buildCriterion(existsPredicate), subCriteria); //$NON-NLS-1$ return getThis(); } - @NotNull public T or(SqlCriterion initialCriterion, AndOrCriteriaGroup... subCriteria) { return or(initialCriterion, Arrays.asList(subCriteria)); } - @NotNull public T or(SqlCriterion initialCriterion, List subCriteria) { addSubCriteria("or", buildCriterion(initialCriterion), subCriteria); //$NON-NLS-1$ return getThis(); } - @NotNull public T or(List criteria) { addSubCriteria("or", criteria); //$NON-NLS-1$ return getThis(); @@ -144,17 +130,16 @@ private void addSubCriteria(String connector, List criteria) .build()); } - protected void setInitialCriterion(SqlCriterion initialCriterion) { + protected void setInitialCriterion(@Nullable SqlCriterion initialCriterion) { this.initialCriterion = initialCriterion; } - protected void setInitialCriterion(SqlCriterion initialCriterion, StatementType statementType) { + protected void setInitialCriterion(@Nullable SqlCriterion initialCriterion, StatementType statementType) { Validator.assertTrue(this.initialCriterion == null, statementType.messageNumber()); setInitialCriterion(initialCriterion); } - // may be null! - protected SqlCriterion getInitialCriterion() { + protected @Nullable SqlCriterion getInitialCriterion() { return initialCriterion; } diff --git a/src/main/java/org/mybatis/dynamic/sql/common/AbstractBooleanExpressionModel.java b/src/main/java/org/mybatis/dynamic/sql/common/AbstractBooleanExpressionModel.java index 0112c4555..edda8707f 100644 --- a/src/main/java/org/mybatis/dynamic/sql/common/AbstractBooleanExpressionModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/common/AbstractBooleanExpressionModel.java @@ -20,11 +20,12 @@ import java.util.List; import java.util.Optional; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AndOrCriteriaGroup; import org.mybatis.dynamic.sql.SqlCriterion; public abstract class AbstractBooleanExpressionModel { - private final SqlCriterion initialCriterion; + private final @Nullable SqlCriterion initialCriterion; private final List subCriteria ; protected AbstractBooleanExpressionModel(AbstractBuilder builder) { @@ -41,10 +42,10 @@ public List subCriteria() { } public abstract static class AbstractBuilder> { - private SqlCriterion initialCriterion; + private @Nullable SqlCriterion initialCriterion; private final List subCriteria = new ArrayList<>(); - public T withInitialCriterion(SqlCriterion initialCriterion) { + public T withInitialCriterion(@Nullable SqlCriterion initialCriterion) { this.initialCriterion = initialCriterion; return getThis(); } diff --git a/src/main/java/org/mybatis/dynamic/sql/common/AbstractBooleanExpressionRenderer.java b/src/main/java/org/mybatis/dynamic/sql/common/AbstractBooleanExpressionRenderer.java index 8ba9d7dce..a006b1834 100644 --- a/src/main/java/org/mybatis/dynamic/sql/common/AbstractBooleanExpressionRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/common/AbstractBooleanExpressionRenderer.java @@ -21,6 +21,7 @@ import java.util.Optional; import java.util.stream.Collectors; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.SqlCriterion; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.FragmentAndParameters; @@ -84,7 +85,7 @@ private String addPrefix(String fragment) { public abstract static class AbstractBuilder> { private final AbstractBooleanExpressionModel model; - private RenderingContext renderingContext; + private @Nullable RenderingContext renderingContext; protected AbstractBuilder(AbstractBooleanExpressionModel model) { this.model = model; diff --git a/src/main/java/org/mybatis/dynamic/sql/common/CommonBuilder.java b/src/main/java/org/mybatis/dynamic/sql/common/CommonBuilder.java index b8a9a9a52..269b857af 100644 --- a/src/main/java/org/mybatis/dynamic/sql/common/CommonBuilder.java +++ b/src/main/java/org/mybatis/dynamic/sql/common/CommonBuilder.java @@ -15,6 +15,7 @@ */ package org.mybatis.dynamic.sql.common; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.SqlTable; import org.mybatis.dynamic.sql.configuration.StatementConfiguration; import org.mybatis.dynamic.sql.where.EmbeddedWhereModel; @@ -25,34 +26,34 @@ * @param type of the implementing builder */ public abstract class CommonBuilder> { - private SqlTable table; - private String tableAlias; - private EmbeddedWhereModel whereModel; - private Long limit; - private OrderByModel orderByModel; - private StatementConfiguration statementConfiguration; + private @Nullable SqlTable table; + private @Nullable String tableAlias; + private @Nullable EmbeddedWhereModel whereModel; + private @Nullable Long limit; + private @Nullable OrderByModel orderByModel; + private @Nullable StatementConfiguration statementConfiguration; - public SqlTable table() { + public @Nullable SqlTable table() { return table; } - public String tableAlias() { + public @Nullable String tableAlias() { return tableAlias; } - public EmbeddedWhereModel whereModel() { + public @Nullable EmbeddedWhereModel whereModel() { return whereModel; } - public Long limit() { + public @Nullable Long limit() { return limit; } - public OrderByModel orderByModel() { + public @Nullable OrderByModel orderByModel() { return orderByModel; } - public StatementConfiguration statementConfiguration() { + public @Nullable StatementConfiguration statementConfiguration() { return statementConfiguration; } @@ -61,22 +62,22 @@ public T withTable(SqlTable table) { return getThis(); } - public T withTableAlias(String tableAlias) { + public T withTableAlias(@Nullable String tableAlias) { this.tableAlias = tableAlias; return getThis(); } - public T withWhereModel(EmbeddedWhereModel whereModel) { + public T withWhereModel(@Nullable EmbeddedWhereModel whereModel) { this.whereModel = whereModel; return getThis(); } - public T withLimit(Long limit) { + public T withLimit(@Nullable Long limit) { this.limit = limit; return getThis(); } - public T withOrderByModel(OrderByModel orderByModel) { + public T withOrderByModel(@Nullable OrderByModel orderByModel) { this.orderByModel = orderByModel; return getThis(); } diff --git a/src/main/java/org/mybatis/dynamic/sql/common/package-info.java b/src/main/java/org/mybatis/dynamic/sql/common/package-info.java new file mode 100644 index 000000000..f581c8034 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/common/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright 2016-2025 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. + */ +@NullMarked +package org.mybatis.dynamic.sql.common; + +import org.jspecify.annotations.NullMarked; diff --git a/src/main/java/org/mybatis/dynamic/sql/configuration/GlobalConfiguration.java b/src/main/java/org/mybatis/dynamic/sql/configuration/GlobalConfiguration.java index 8e7fd2eba..670ddd935 100644 --- a/src/main/java/org/mybatis/dynamic/sql/configuration/GlobalConfiguration.java +++ b/src/main/java/org/mybatis/dynamic/sql/configuration/GlobalConfiguration.java @@ -17,6 +17,7 @@ import java.io.IOException; import java.io.InputStream; +import java.util.Objects; import java.util.Properties; import org.mybatis.dynamic.sql.exception.DynamicSqlException; @@ -47,11 +48,7 @@ private void initializeProperties() { private String getConfigurationFileName() { String property = System.getProperty(CONFIGURATION_FILE_PROPERTY); - if (property == null) { - return DEFAULT_PROPERTY_FILE; - } else { - return property; - } + return Objects.requireNonNullElse(property, DEFAULT_PROPERTY_FILE); } void loadProperties(InputStream inputStream, String propertyFile) { diff --git a/src/main/java/org/mybatis/dynamic/sql/configuration/package-info.java b/src/main/java/org/mybatis/dynamic/sql/configuration/package-info.java new file mode 100644 index 000000000..41fcac6c7 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/configuration/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright 2016-2025 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. + */ +@NullMarked +package org.mybatis.dynamic.sql.configuration; + +import org.jspecify.annotations.NullMarked; diff --git a/src/main/java/org/mybatis/dynamic/sql/delete/DeleteDSL.java b/src/main/java/org/mybatis/dynamic/sql/delete/DeleteDSL.java index 2ea176c53..8dda9b10c 100644 --- a/src/main/java/org/mybatis/dynamic/sql/delete/DeleteDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/delete/DeleteDSL.java @@ -21,7 +21,7 @@ import java.util.function.Consumer; import java.util.function.Function; -import org.jetbrains.annotations.NotNull; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.SortSpecification; import org.mybatis.dynamic.sql.SqlTable; import org.mybatis.dynamic.sql.common.OrderByModel; @@ -37,13 +37,13 @@ public class DeleteDSL implements AbstractWhereStarter.DeleteWhe private final Function adapterFunction; private final SqlTable table; - private final String tableAlias; - private DeleteWhereBuilder whereBuilder; + private final @Nullable String tableAlias; + private @Nullable DeleteWhereBuilder whereBuilder; private final StatementConfiguration statementConfiguration = new StatementConfiguration(); - private Long limit; - private OrderByModel orderByModel; + private @Nullable Long limit; + private @Nullable OrderByModel orderByModel; - private DeleteDSL(SqlTable table, String tableAlias, Function adapterFunction) { + private DeleteDSL(SqlTable table, @Nullable String tableAlias, Function adapterFunction) { this.table = Objects.requireNonNull(table); this.tableAlias = tableAlias; this.adapterFunction = Objects.requireNonNull(adapterFunction); @@ -59,7 +59,7 @@ public DeleteDSL limit(long limit) { return limitWhenPresent(limit); } - public DeleteDSL limitWhenPresent(Long limit) { + public DeleteDSL limitWhenPresent(@Nullable Long limit) { this.limit = limit; return this; } @@ -79,7 +79,6 @@ public DeleteDSL orderBy(Collection columns) { * * @return the model class */ - @NotNull @Override public R build() { DeleteModel deleteModel = DeleteModel.withTable(table) @@ -100,7 +99,7 @@ public DeleteDSL configureStatement(Consumer consumer } public static DeleteDSL deleteFrom(Function adapterFunction, SqlTable table, - String tableAlias) { + @Nullable String tableAlias) { return new DeleteDSL<>(table, tableAlias, adapterFunction); } @@ -135,7 +134,6 @@ public DeleteDSL orderBy(Collection columns) { return DeleteDSL.this; } - @NotNull @Override public R build() { return DeleteDSL.this.build(); diff --git a/src/main/java/org/mybatis/dynamic/sql/delete/DeleteModel.java b/src/main/java/org/mybatis/dynamic/sql/delete/DeleteModel.java index d8f4d0e07..1f9dc606f 100644 --- a/src/main/java/org/mybatis/dynamic/sql/delete/DeleteModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/delete/DeleteModel.java @@ -18,7 +18,7 @@ import java.util.Objects; import java.util.Optional; -import org.jetbrains.annotations.NotNull; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.SqlTable; import org.mybatis.dynamic.sql.common.CommonBuilder; import org.mybatis.dynamic.sql.common.OrderByModel; @@ -30,10 +30,10 @@ public class DeleteModel { private final SqlTable table; - private final String tableAlias; - private final EmbeddedWhereModel whereModel; - private final Long limit; - private final OrderByModel orderByModel; + private final @Nullable String tableAlias; + private final @Nullable EmbeddedWhereModel whereModel; + private final @Nullable Long limit; + private final @Nullable OrderByModel orderByModel; private final StatementConfiguration statementConfiguration; private DeleteModel(Builder builder) { @@ -69,7 +69,6 @@ public StatementConfiguration statementConfiguration() { return statementConfiguration; } - @NotNull public DeleteStatementProvider render(RenderingStrategy renderingStrategy) { return DeleteRenderer.withDeleteModel(this) .withRenderingStrategy(renderingStrategy) diff --git a/src/main/java/org/mybatis/dynamic/sql/delete/package-info.java b/src/main/java/org/mybatis/dynamic/sql/delete/package-info.java new file mode 100644 index 000000000..a7bfc9d26 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/delete/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright 2016-2025 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. + */ +@NullMarked +package org.mybatis.dynamic.sql.delete; + +import org.jspecify.annotations.NullMarked; diff --git a/src/main/java/org/mybatis/dynamic/sql/delete/render/DefaultDeleteStatementProvider.java b/src/main/java/org/mybatis/dynamic/sql/delete/render/DefaultDeleteStatementProvider.java index 31ffc53f0..db5feef01 100644 --- a/src/main/java/org/mybatis/dynamic/sql/delete/render/DefaultDeleteStatementProvider.java +++ b/src/main/java/org/mybatis/dynamic/sql/delete/render/DefaultDeleteStatementProvider.java @@ -19,6 +19,8 @@ import java.util.Map; import java.util.Objects; +import org.jspecify.annotations.Nullable; + public class DefaultDeleteStatementProvider implements DeleteStatementProvider { private final String deleteStatement; private final Map parameters; @@ -43,7 +45,7 @@ public static Builder withDeleteStatement(String deleteStatement) { } public static class Builder { - private String deleteStatement; + private @Nullable String deleteStatement; private final Map parameters = new HashMap<>(); public Builder withDeleteStatement(String deleteStatement) { diff --git a/src/main/java/org/mybatis/dynamic/sql/delete/render/DeleteRenderer.java b/src/main/java/org/mybatis/dynamic/sql/delete/render/DeleteRenderer.java index 4671e4d79..d65fcdd58 100644 --- a/src/main/java/org/mybatis/dynamic/sql/delete/render/DeleteRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/delete/render/DeleteRenderer.java @@ -19,6 +19,7 @@ import java.util.Optional; import java.util.stream.Collectors; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.common.OrderByModel; import org.mybatis.dynamic.sql.common.OrderByRenderer; import org.mybatis.dynamic.sql.delete.DeleteModel; @@ -103,8 +104,8 @@ public static Builder withDeleteModel(DeleteModel deleteModel) { } public static class Builder { - private DeleteModel deleteModel; - private RenderingStrategy renderingStrategy; + private @Nullable DeleteModel deleteModel; + private @Nullable RenderingStrategy renderingStrategy; public Builder withDeleteModel(DeleteModel deleteModel) { this.deleteModel = deleteModel; diff --git a/src/main/java/org/mybatis/dynamic/sql/delete/render/package-info.java b/src/main/java/org/mybatis/dynamic/sql/delete/render/package-info.java new file mode 100644 index 000000000..8b25d555d --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/delete/render/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright 2016-2025 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. + */ +@NullMarked +package org.mybatis.dynamic.sql.delete.render; + +import org.jspecify.annotations.NullMarked; diff --git a/src/main/java/org/mybatis/dynamic/sql/exception/package-info.java b/src/main/java/org/mybatis/dynamic/sql/exception/package-info.java new file mode 100644 index 000000000..4e802e370 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/exception/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright 2016-2025 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. + */ +@NullMarked +package org.mybatis.dynamic.sql.exception; + +import org.jspecify.annotations.NullMarked; diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/AbstractMultiRowInsertModel.java b/src/main/java/org/mybatis/dynamic/sql/insert/AbstractMultiRowInsertModel.java index b4bdb7eab..4fc8a3b4d 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/AbstractMultiRowInsertModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/AbstractMultiRowInsertModel.java @@ -22,6 +22,7 @@ import java.util.Objects; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.SqlTable; import org.mybatis.dynamic.sql.util.AbstractColumnMapping; @@ -53,7 +54,7 @@ public int recordCount() { } public abstract static class AbstractBuilder> { - private SqlTable table; + private @Nullable SqlTable table; private final List records = new ArrayList<>(); private final List columnMappings = new ArrayList<>(); diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/BatchInsertDSL.java b/src/main/java/org/mybatis/dynamic/sql/insert/BatchInsertDSL.java index 8c8344929..71bc350d6 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/BatchInsertDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/BatchInsertDSL.java @@ -21,7 +21,7 @@ import java.util.List; import java.util.Objects; -import org.jetbrains.annotations.NotNull; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.SqlColumn; import org.mybatis.dynamic.sql.SqlTable; import org.mybatis.dynamic.sql.util.AbstractColumnMapping; @@ -48,7 +48,6 @@ public ColumnMappingFinisher map(SqlColumn column) { return new ColumnMappingFinisher<>(column); } - @NotNull @Override public BatchInsertModel build() { return BatchInsertModel.withRecords(records) @@ -113,7 +112,7 @@ public BatchInsertDSL toRow() { public abstract static class AbstractBuilder> { final Collection records = new ArrayList<>(); - SqlTable table; + @Nullable SqlTable table; final List columnMappings = new ArrayList<>(); public B withRecords(Collection records) { diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/BatchInsertModel.java b/src/main/java/org/mybatis/dynamic/sql/insert/BatchInsertModel.java index 4e85d5951..275ce2745 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/BatchInsertModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/BatchInsertModel.java @@ -17,7 +17,6 @@ import java.util.Collection; -import org.jetbrains.annotations.NotNull; import org.mybatis.dynamic.sql.insert.render.BatchInsert; import org.mybatis.dynamic.sql.insert.render.BatchInsertRenderer; import org.mybatis.dynamic.sql.render.RenderingStrategy; @@ -31,7 +30,6 @@ private BatchInsertModel(Builder builder) { Validator.assertNotEmpty(columnMappings, "ERROR.5"); //$NON-NLS-1$ } - @NotNull public BatchInsert render(RenderingStrategy renderingStrategy) { return BatchInsertRenderer.withBatchInsertModel(this) .withRenderingStrategy(renderingStrategy) diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/GeneralInsertDSL.java b/src/main/java/org/mybatis/dynamic/sql/insert/GeneralInsertDSL.java index 18e05a1d1..5cba9063d 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/GeneralInsertDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/GeneralInsertDSL.java @@ -21,7 +21,7 @@ import java.util.Objects; import java.util.function.Supplier; -import org.jetbrains.annotations.NotNull; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.SqlColumn; import org.mybatis.dynamic.sql.SqlTable; import org.mybatis.dynamic.sql.configuration.StatementConfiguration; @@ -47,7 +47,6 @@ public SetClauseFinisher set(SqlColumn column) { return new SetClauseFinisher<>(column); } - @NotNull @Override public GeneralInsertModel build() { return new GeneralInsertModel.Builder() @@ -93,20 +92,20 @@ public GeneralInsertDSL toValue(Supplier valueSupplier) { return GeneralInsertDSL.this; } - public GeneralInsertDSL toValueOrNull(T value) { + public GeneralInsertDSL toValueOrNull(@Nullable T value) { return toValueOrNull(() -> value); } - public GeneralInsertDSL toValueOrNull(Supplier valueSupplier) { + public GeneralInsertDSL toValueOrNull(Supplier<@Nullable T> valueSupplier) { columnMappings.add(ValueOrNullMapping.of(column, valueSupplier)); return GeneralInsertDSL.this; } - public GeneralInsertDSL toValueWhenPresent(T value) { + public GeneralInsertDSL toValueWhenPresent(@Nullable T value) { return toValueWhenPresent(() -> value); } - public GeneralInsertDSL toValueWhenPresent(Supplier valueSupplier) { + public GeneralInsertDSL toValueWhenPresent(Supplier<@Nullable T> valueSupplier) { columnMappings.add(ValueWhenPresentMapping.of(column, valueSupplier)); return GeneralInsertDSL.this; } @@ -114,7 +113,7 @@ public GeneralInsertDSL toValueWhenPresent(Supplier valueSupplier) { public static class Builder { private final List columnMappings = new ArrayList<>(); - private SqlTable table; + private @Nullable SqlTable table; public Builder withTable(SqlTable table) { this.table = table; diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/GeneralInsertModel.java b/src/main/java/org/mybatis/dynamic/sql/insert/GeneralInsertModel.java index 4a9de2270..873c98f5f 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/GeneralInsertModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/GeneralInsertModel.java @@ -20,7 +20,7 @@ import java.util.Objects; import java.util.stream.Stream; -import org.jetbrains.annotations.NotNull; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.SqlTable; import org.mybatis.dynamic.sql.configuration.StatementConfiguration; import org.mybatis.dynamic.sql.insert.render.GeneralInsertRenderer; @@ -54,7 +54,6 @@ public StatementConfiguration statementConfiguration() { return statementConfiguration; } - @NotNull public GeneralInsertStatementProvider render(RenderingStrategy renderingStrategy) { return GeneralInsertRenderer.withInsertModel(this) .withRenderingStrategy(renderingStrategy) @@ -63,9 +62,9 @@ public GeneralInsertStatementProvider render(RenderingStrategy renderingStrategy } public static class Builder { - private SqlTable table; + private @Nullable SqlTable table; private final List insertMappings = new ArrayList<>(); - private StatementConfiguration statementConfiguration; + private @Nullable StatementConfiguration statementConfiguration; public Builder withTable(SqlTable table) { this.table = table; diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/InsertColumnListModel.java b/src/main/java/org/mybatis/dynamic/sql/insert/InsertColumnListModel.java index c1c0669c9..56131f0e9 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/InsertColumnListModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/InsertColumnListModel.java @@ -20,13 +20,14 @@ import java.util.Objects; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.SqlColumn; import org.mybatis.dynamic.sql.util.Validator; public class InsertColumnListModel { private final List> columns = new ArrayList<>(); - private InsertColumnListModel(List> columns) { + private InsertColumnListModel(@Nullable List> columns) { Objects.requireNonNull(columns); Validator.assertNotEmpty(columns, "ERROR.4"); //$NON-NLS-1$ this.columns.addAll(columns); @@ -37,7 +38,7 @@ public Stream> columns() { return columns.stream(); } - public static InsertColumnListModel of(List> columns) { + public static InsertColumnListModel of(@Nullable List> columns) { return new InsertColumnListModel(columns); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/InsertDSL.java b/src/main/java/org/mybatis/dynamic/sql/insert/InsertDSL.java index e2fbb49b5..d622ced8c 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/InsertDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/InsertDSL.java @@ -21,7 +21,7 @@ import java.util.Objects; import java.util.function.Supplier; -import org.jetbrains.annotations.NotNull; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.SqlColumn; import org.mybatis.dynamic.sql.SqlTable; import org.mybatis.dynamic.sql.util.AbstractColumnMapping; @@ -49,7 +49,6 @@ public ColumnMappingFinisher map(SqlColumn column) { return new ColumnMappingFinisher<>(column); } - @NotNull @Override public InsertModel build() { return InsertModel.withRow(row) @@ -113,8 +112,8 @@ public InsertDSL toRow() { } public static class Builder { - private T row; - private SqlTable table; + private @Nullable T row; + private @Nullable SqlTable table; private final List columnMappings = new ArrayList<>(); public Builder withRow(T row) { diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/InsertModel.java b/src/main/java/org/mybatis/dynamic/sql/insert/InsertModel.java index a0d451358..4495e32fd 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/InsertModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/InsertModel.java @@ -20,7 +20,7 @@ import java.util.Objects; import java.util.stream.Stream; -import org.jetbrains.annotations.NotNull; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.SqlTable; import org.mybatis.dynamic.sql.insert.render.InsertRenderer; import org.mybatis.dynamic.sql.insert.render.InsertStatementProvider; @@ -52,7 +52,6 @@ public SqlTable table() { return table; } - @NotNull public InsertStatementProvider render(RenderingStrategy renderingStrategy) { return InsertRenderer.withInsertModel(this) .withRenderingStrategy(renderingStrategy) @@ -65,8 +64,8 @@ public static Builder withRow(T row) { } public static class Builder { - private SqlTable table; - private T row; + private @Nullable SqlTable table; + private @Nullable T row; private final List columnMappings = new ArrayList<>(); public Builder withTable(SqlTable table) { diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/InsertSelectDSL.java b/src/main/java/org/mybatis/dynamic/sql/insert/InsertSelectDSL.java index 5e071d169..e7f8b5e09 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/InsertSelectDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/InsertSelectDSL.java @@ -20,7 +20,7 @@ import java.util.Objects; import java.util.function.Consumer; -import org.jetbrains.annotations.NotNull; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.SqlColumn; import org.mybatis.dynamic.sql.SqlTable; import org.mybatis.dynamic.sql.configuration.StatementConfiguration; @@ -31,7 +31,7 @@ public class InsertSelectDSL implements Buildable, ConfigurableStatement { private final SqlTable table; - private final InsertColumnListModel columnList; + private final @Nullable InsertColumnListModel columnList; private final SelectModel selectModel; private final StatementConfiguration statementConfiguration = new StatementConfiguration(); @@ -47,7 +47,6 @@ private InsertSelectDSL(SqlTable table, SelectModel selectModel) { this.columnList = null; } - @NotNull @Override public InsertSelectModel build() { return InsertSelectModel.withTable(table) diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/InsertSelectModel.java b/src/main/java/org/mybatis/dynamic/sql/insert/InsertSelectModel.java index 25d01b7de..36051700c 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/InsertSelectModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/InsertSelectModel.java @@ -18,7 +18,7 @@ import java.util.Objects; import java.util.Optional; -import org.jetbrains.annotations.NotNull; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.SqlTable; import org.mybatis.dynamic.sql.configuration.StatementConfiguration; import org.mybatis.dynamic.sql.insert.render.InsertSelectRenderer; @@ -28,7 +28,7 @@ public class InsertSelectModel { private final SqlTable table; - private final InsertColumnListModel columnList; + private final @Nullable InsertColumnListModel columnList; private final SelectModel selectModel; private final StatementConfiguration statementConfiguration; @@ -55,7 +55,6 @@ public StatementConfiguration statementConfiguration() { return statementConfiguration; } - @NotNull public InsertSelectStatementProvider render(RenderingStrategy renderingStrategy) { return InsertSelectRenderer.withInsertSelectModel(this) .withRenderingStrategy(renderingStrategy) @@ -68,17 +67,17 @@ public static Builder withTable(SqlTable table) { } public static class Builder { - private SqlTable table; - private InsertColumnListModel columnList; - private SelectModel selectModel; - private StatementConfiguration statementConfiguration; + private @Nullable SqlTable table; + private @Nullable InsertColumnListModel columnList; + private @Nullable SelectModel selectModel; + private @Nullable StatementConfiguration statementConfiguration; public Builder withTable(SqlTable table) { this.table = table; return this; } - public Builder withColumnList(InsertColumnListModel columnList) { + public Builder withColumnList(@Nullable InsertColumnListModel columnList) { this.columnList = columnList; return this; } diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/MultiRowInsertDSL.java b/src/main/java/org/mybatis/dynamic/sql/insert/MultiRowInsertDSL.java index b29684a4f..8e5f30e49 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/MultiRowInsertDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/MultiRowInsertDSL.java @@ -20,7 +20,6 @@ import java.util.List; import java.util.Objects; -import org.jetbrains.annotations.NotNull; import org.mybatis.dynamic.sql.SqlColumn; import org.mybatis.dynamic.sql.SqlTable; import org.mybatis.dynamic.sql.util.AbstractColumnMapping; @@ -47,7 +46,6 @@ public ColumnMappingFinisher map(SqlColumn column) { return new ColumnMappingFinisher<>(column); } - @NotNull @Override public MultiRowInsertModel build() { return MultiRowInsertModel.withRecords(records) diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/MultiRowInsertModel.java b/src/main/java/org/mybatis/dynamic/sql/insert/MultiRowInsertModel.java index 3b380ca66..435267652 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/MultiRowInsertModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/MultiRowInsertModel.java @@ -17,7 +17,6 @@ import java.util.Collection; -import org.jetbrains.annotations.NotNull; import org.mybatis.dynamic.sql.insert.render.MultiRowInsertRenderer; import org.mybatis.dynamic.sql.insert.render.MultiRowInsertStatementProvider; import org.mybatis.dynamic.sql.render.RenderingStrategy; @@ -31,7 +30,6 @@ private MultiRowInsertModel(Builder builder) { Validator.assertNotEmpty(columnMappings, "ERROR.8"); //$NON-NLS-1$ } - @NotNull public MultiRowInsertStatementProvider render(RenderingStrategy renderingStrategy) { return MultiRowInsertRenderer.withMultiRowInsertModel(this) .withRenderingStrategy(renderingStrategy) diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/package-info.java b/src/main/java/org/mybatis/dynamic/sql/insert/package-info.java new file mode 100644 index 000000000..5ef9f74ea --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/insert/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright 2016-2025 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. + */ +@NullMarked +package org.mybatis.dynamic.sql.insert; + +import org.jspecify.annotations.NullMarked; diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/render/BatchInsert.java b/src/main/java/org/mybatis/dynamic/sql/insert/render/BatchInsert.java index 5272a0ba0..8af9e30fe 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/render/BatchInsert.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/render/BatchInsert.java @@ -20,6 +20,8 @@ import java.util.List; import java.util.Objects; +import org.jspecify.annotations.Nullable; + public class BatchInsert { private final String insertStatement; private final List records; @@ -64,7 +66,7 @@ public static Builder withRecords(List records) { } public static class Builder { - private String insertStatement; + private @Nullable String insertStatement; private final List records = new ArrayList<>(); public Builder withInsertStatement(String insertStatement) { diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/render/BatchInsertRenderer.java b/src/main/java/org/mybatis/dynamic/sql/insert/render/BatchInsertRenderer.java index 48d5f5eea..875820c02 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/render/BatchInsertRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/render/BatchInsertRenderer.java @@ -17,6 +17,7 @@ import java.util.Objects; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.insert.BatchInsertModel; import org.mybatis.dynamic.sql.render.RenderingStrategy; @@ -27,7 +28,8 @@ public class BatchInsertRenderer { private BatchInsertRenderer(Builder builder) { model = Objects.requireNonNull(builder.model); - visitor = new MultiRowValuePhraseVisitor(builder.renderingStrategy, "row"); //$NON-NLS-1$) + visitor = new MultiRowValuePhraseVisitor(Objects.requireNonNull(builder.renderingStrategy), + "row"); //$NON-NLS-1$) } public BatchInsert render() { @@ -47,8 +49,8 @@ public static Builder withBatchInsertModel(BatchInsertModel model) { } public static class Builder { - private BatchInsertModel model; - private RenderingStrategy renderingStrategy; + private @Nullable BatchInsertModel model; + private @Nullable RenderingStrategy renderingStrategy; public Builder withBatchInsertModel(BatchInsertModel model) { this.model = model; diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/render/DefaultGeneralInsertStatementProvider.java b/src/main/java/org/mybatis/dynamic/sql/insert/render/DefaultGeneralInsertStatementProvider.java index 94b3eac7a..eaa3d0911 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/render/DefaultGeneralInsertStatementProvider.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/render/DefaultGeneralInsertStatementProvider.java @@ -19,6 +19,8 @@ import java.util.Map; import java.util.Objects; +import org.jspecify.annotations.Nullable; + public class DefaultGeneralInsertStatementProvider implements GeneralInsertStatementProvider, InsertSelectStatementProvider { private final String insertStatement; @@ -44,7 +46,7 @@ public static Builder withInsertStatement(String insertStatement) { } public static class Builder { - private String insertStatement; + private @Nullable String insertStatement; private final Map parameters = new HashMap<>(); public Builder withInsertStatement(String insertStatement) { diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/render/DefaultInsertStatementProvider.java b/src/main/java/org/mybatis/dynamic/sql/insert/render/DefaultInsertStatementProvider.java index d45f9f956..a16967456 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/render/DefaultInsertStatementProvider.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/render/DefaultInsertStatementProvider.java @@ -17,7 +17,7 @@ import java.util.Objects; -import org.jetbrains.annotations.NotNull; +import org.jspecify.annotations.Nullable; public class DefaultInsertStatementProvider implements InsertStatementProvider { private final String insertStatement; @@ -29,7 +29,6 @@ private DefaultInsertStatementProvider(Builder builder) { } @Override - @NotNull public T getRow() { return row; } @@ -44,8 +43,8 @@ public static Builder withRow(T row) { } public static class Builder { - private String insertStatement; - private T row; + private @Nullable String insertStatement; + private @Nullable T row; public Builder withInsertStatement(String insertStatement) { this.insertStatement = insertStatement; diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/render/DefaultMultiRowInsertStatementProvider.java b/src/main/java/org/mybatis/dynamic/sql/insert/render/DefaultMultiRowInsertStatementProvider.java index f1395ecd9..db8c9f489 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/render/DefaultMultiRowInsertStatementProvider.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/render/DefaultMultiRowInsertStatementProvider.java @@ -20,6 +20,8 @@ import java.util.List; import java.util.Objects; +import org.jspecify.annotations.Nullable; + public class DefaultMultiRowInsertStatementProvider implements MultiRowInsertStatementProvider { private final List records; @@ -42,7 +44,7 @@ public List getRecords() { public static class Builder { private final List records = new ArrayList<>(); - private String insertStatement; + private @Nullable String insertStatement; public Builder withRecords(List records) { this.records.addAll(records); diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/render/FieldAndValueAndParameters.java b/src/main/java/org/mybatis/dynamic/sql/insert/render/FieldAndValueAndParameters.java index 1ec27d5a5..d923020c0 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/render/FieldAndValueAndParameters.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/render/FieldAndValueAndParameters.java @@ -20,6 +20,8 @@ import java.util.Objects; import java.util.Optional; +import org.jspecify.annotations.Nullable; + public class FieldAndValueAndParameters { private final String fieldName; private final String valuePhrase; @@ -48,8 +50,8 @@ public static Builder withFieldName(String fieldName) { } public static class Builder { - private String fieldName; - private String valuePhrase; + private @Nullable String fieldName; + private @Nullable String valuePhrase; private final Map parameters = new HashMap<>(); public Builder withFieldName(String fieldName) { @@ -62,7 +64,10 @@ public Builder withValuePhrase(String valuePhrase) { return this; } - public Builder withParameter(String key, Object value) { + public Builder withParameter(String key, @Nullable Object value) { + // the value can be null because a parameter type converter may return null + + //noinspection DataFlowIssue parameters.put(key, value); return this; } diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/render/GeneralInsertRenderer.java b/src/main/java/org/mybatis/dynamic/sql/insert/render/GeneralInsertRenderer.java index 8dfe89d4e..08eddb54f 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/render/GeneralInsertRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/render/GeneralInsertRenderer.java @@ -18,6 +18,7 @@ import java.util.Objects; import java.util.Optional; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.insert.GeneralInsertModel; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.render.RenderingStrategy; @@ -30,7 +31,8 @@ public class GeneralInsertRenderer { private GeneralInsertRenderer(Builder builder) { model = Objects.requireNonNull(builder.model); - RenderingContext renderingContext = RenderingContext.withRenderingStrategy(builder.renderingStrategy) + RenderingContext renderingContext = RenderingContext + .withRenderingStrategy(Objects.requireNonNull(builder.renderingStrategy)) .withStatementConfiguration(model.statementConfiguration()) .build(); visitor = new GeneralInsertValuePhraseVisitor(renderingContext); @@ -56,8 +58,8 @@ public static Builder withInsertModel(GeneralInsertModel model) { } public static class Builder { - private GeneralInsertModel model; - private RenderingStrategy renderingStrategy; + private @Nullable GeneralInsertModel model; + private @Nullable RenderingStrategy renderingStrategy; public Builder withInsertModel(GeneralInsertModel model) { this.model = model; diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/render/GeneralInsertValuePhraseVisitor.java b/src/main/java/org/mybatis/dynamic/sql/insert/render/GeneralInsertValuePhraseVisitor.java index 30897e86f..914d710cf 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/render/GeneralInsertValuePhraseVisitor.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/render/GeneralInsertValuePhraseVisitor.java @@ -18,6 +18,7 @@ import java.util.Objects; import java.util.Optional; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.render.RenderedParameterInfo; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.AbstractColumnMapping; @@ -74,7 +75,7 @@ public Optional visit(ValueWhenPresentMapping } private Optional buildValueFragment(AbstractColumnMapping mapping, - Object value) { + @Nullable Object value) { return buildFragment(mapping, value); } @@ -84,7 +85,7 @@ private Optional buildNullFragment(AbstractColumnMap .buildOptional(); } - private Optional buildFragment(AbstractColumnMapping mapping, Object value) { + private Optional buildFragment(AbstractColumnMapping mapping, @Nullable Object value) { RenderedParameterInfo parameterInfo = renderingContext.calculateParameterInfo(mapping.column()); return FieldAndValueAndParameters.withFieldName(mapping.columnName()) diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertRenderer.java b/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertRenderer.java index f3f67c062..9ff5858be 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertRenderer.java @@ -18,6 +18,7 @@ import java.util.Objects; import java.util.Optional; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.insert.InsertModel; import org.mybatis.dynamic.sql.render.RenderingStrategy; import org.mybatis.dynamic.sql.util.Validator; @@ -29,7 +30,7 @@ public class InsertRenderer { private InsertRenderer(Builder builder) { model = Objects.requireNonNull(builder.model); - visitor = new ValuePhraseVisitor(builder.renderingStrategy); + visitor = new ValuePhraseVisitor(Objects.requireNonNull(builder.renderingStrategy)); } public InsertStatementProvider render() { @@ -52,8 +53,8 @@ public static Builder withInsertModel(InsertModel model) { } public static class Builder { - private InsertModel model; - private RenderingStrategy renderingStrategy; + private @Nullable InsertModel model; + private @Nullable RenderingStrategy renderingStrategy; public Builder withInsertModel(InsertModel model) { this.model = model; diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertSelectRenderer.java b/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertSelectRenderer.java index 909f1c418..7740309bd 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertSelectRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertSelectRenderer.java @@ -20,6 +20,7 @@ import java.util.Objects; import java.util.stream.Collectors; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.SqlColumn; import org.mybatis.dynamic.sql.insert.InsertColumnListModel; import org.mybatis.dynamic.sql.insert.InsertSelectModel; @@ -35,7 +36,7 @@ public class InsertSelectRenderer { private InsertSelectRenderer(Builder builder) { model = Objects.requireNonNull(builder.model); - renderingContext = RenderingContext.withRenderingStrategy(builder.renderingStrategy) + renderingContext = RenderingContext.withRenderingStrategy(Objects.requireNonNull(builder.renderingStrategy)) .withStatementConfiguration(model.statementConfiguration()) .build(); } @@ -71,8 +72,8 @@ public static Builder withInsertSelectModel(InsertSelectModel model) { } public static class Builder { - private InsertSelectModel model; - private RenderingStrategy renderingStrategy; + private @Nullable InsertSelectModel model; + private @Nullable RenderingStrategy renderingStrategy; public Builder withInsertSelectModel(InsertSelectModel model) { this.model = model; diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertStatementProvider.java b/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertStatementProvider.java index f68fb1db3..bd40a0e1f 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertStatementProvider.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/render/InsertStatementProvider.java @@ -15,15 +15,12 @@ */ package org.mybatis.dynamic.sql.insert.render; -import org.jetbrains.annotations.NotNull; - public interface InsertStatementProvider { /** * Return the row associated with this insert statement. * * @return the row associated with this insert statement. */ - @NotNull T getRow(); /** diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/render/MultiRowInsertRenderer.java b/src/main/java/org/mybatis/dynamic/sql/insert/render/MultiRowInsertRenderer.java index 21da95cca..5f3146a77 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/render/MultiRowInsertRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/render/MultiRowInsertRenderer.java @@ -19,6 +19,7 @@ import java.util.Objects; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.insert.MultiRowInsertModel; import org.mybatis.dynamic.sql.render.RenderingStrategy; @@ -30,7 +31,8 @@ public class MultiRowInsertRenderer { private MultiRowInsertRenderer(Builder builder) { model = Objects.requireNonNull(builder.model); // the prefix is a generic format that will be resolved below with String.format(...) - visitor = new MultiRowValuePhraseVisitor(builder.renderingStrategy, "records[%s]"); //$NON-NLS-1$ + visitor = new MultiRowValuePhraseVisitor(Objects.requireNonNull(builder.renderingStrategy), + "records[%s]"); //$NON-NLS-1$ } public MultiRowInsertStatementProvider render() { @@ -58,8 +60,8 @@ public static Builder withMultiRowInsertModel(MultiRowInsertModel mode } public static class Builder { - private MultiRowInsertModel model; - private RenderingStrategy renderingStrategy; + private @Nullable MultiRowInsertModel model; + private @Nullable RenderingStrategy renderingStrategy; public Builder withMultiRowInsertModel(MultiRowInsertModel model) { this.model = model; diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/render/MultiRowValuePhraseVisitor.java b/src/main/java/org/mybatis/dynamic/sql/insert/render/MultiRowValuePhraseVisitor.java index 639248c3e..ba2d2ffa5 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/render/MultiRowValuePhraseVisitor.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/render/MultiRowValuePhraseVisitor.java @@ -15,8 +15,6 @@ */ package org.mybatis.dynamic.sql.insert.render; -import java.util.Objects; - import org.mybatis.dynamic.sql.SqlColumn; import org.mybatis.dynamic.sql.render.RenderingStrategy; import org.mybatis.dynamic.sql.util.ConstantMapping; @@ -32,8 +30,8 @@ public class MultiRowValuePhraseVisitor extends MultiRowInsertMappingVisitor aliasForTable(SqlTable table) { } public static class Builder { - private TableAliasCalculator parent; - private TableAliasCalculator child; + private @Nullable TableAliasCalculator parent; + private @Nullable TableAliasCalculator child; public Builder withParent(TableAliasCalculator parent) { this.parent = parent; diff --git a/src/main/java/org/mybatis/dynamic/sql/render/package-info.java b/src/main/java/org/mybatis/dynamic/sql/render/package-info.java new file mode 100644 index 000000000..770ff3d47 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/render/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright 2016-2025 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. + */ +@NullMarked +package org.mybatis.dynamic.sql.render; + +import org.jspecify.annotations.NullMarked; diff --git a/src/main/java/org/mybatis/dynamic/sql/select/AbstractHavingFinisher.java b/src/main/java/org/mybatis/dynamic/sql/select/AbstractHavingFinisher.java index bcf21b23a..872b964eb 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/AbstractHavingFinisher.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/AbstractHavingFinisher.java @@ -17,6 +17,7 @@ import java.util.List; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AndOrCriteriaGroup; import org.mybatis.dynamic.sql.SqlCriterion; import org.mybatis.dynamic.sql.common.AbstractBooleanExpressionDSL; @@ -27,7 +28,7 @@ void initialize(SqlCriterion sqlCriterion) { setInitialCriterion(sqlCriterion, StatementType.HAVING); } - void initialize(SqlCriterion sqlCriterion, List subCriteria) { + void initialize(@Nullable SqlCriterion sqlCriterion, List subCriteria) { setInitialCriterion(sqlCriterion, StatementType.HAVING); super.subCriteria.addAll(subCriteria); } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/AbstractQueryExpressionDSL.java b/src/main/java/org/mybatis/dynamic/sql/select/AbstractQueryExpressionDSL.java index bee032a30..f1fd826a8 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/AbstractQueryExpressionDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/AbstractQueryExpressionDSL.java @@ -25,6 +25,7 @@ import java.util.Optional; import java.util.function.Supplier; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AndOrCriteriaGroup; import org.mybatis.dynamic.sql.SqlCriterion; import org.mybatis.dynamic.sql.SqlTable; @@ -65,19 +66,19 @@ public T join(SqlTable joinTable, String tableAlias, SqlCriterion onJoinCriterio return join(joinTable, onJoinCriterion, andJoinCriteria); } - public T join(SqlTable joinTable, SqlCriterion onJoinCriterion, + public T join(SqlTable joinTable, @Nullable SqlCriterion onJoinCriterion, List andJoinCriteria) { addJoinSpecificationSupplier(joinTable, onJoinCriterion, JoinType.INNER, andJoinCriteria); return getThis(); } - public T join(SqlTable joinTable, String tableAlias, SqlCriterion onJoinCriterion, + public T join(SqlTable joinTable, String tableAlias, @Nullable SqlCriterion onJoinCriterion, List andJoinCriteria) { addTableAlias(joinTable, tableAlias); return join(joinTable, onJoinCriterion, andJoinCriteria); } - public T join(Buildable subQuery, String tableAlias, SqlCriterion onJoinCriterion, + public T join(Buildable subQuery, @Nullable String tableAlias, @Nullable SqlCriterion onJoinCriterion, List andJoinCriteria) { addJoinSpecificationSupplier(buildSubQuery(subQuery, tableAlias), onJoinCriterion, JoinType.INNER, andJoinCriteria); @@ -96,20 +97,20 @@ public T leftJoin(SqlTable joinTable, String tableAlias, SqlCriterion onJoinCrit return leftJoin(joinTable, onJoinCriterion, andJoinCriteria); } - public T leftJoin(SqlTable joinTable, SqlCriterion onJoinCriterion, + public T leftJoin(SqlTable joinTable, @Nullable SqlCriterion onJoinCriterion, List andJoinCriteria) { addJoinSpecificationSupplier(joinTable, onJoinCriterion, JoinType.LEFT, andJoinCriteria); return getThis(); } - public T leftJoin(SqlTable joinTable, String tableAlias, SqlCriterion onJoinCriterion, + public T leftJoin(SqlTable joinTable, String tableAlias, @Nullable SqlCriterion onJoinCriterion, List andJoinCriteria) { addTableAlias(joinTable, tableAlias); return leftJoin(joinTable, onJoinCriterion, andJoinCriteria); } - public T leftJoin(Buildable subQuery, String tableAlias, SqlCriterion onJoinCriterion, - List andJoinCriteria) { + public T leftJoin(Buildable subQuery, @Nullable String tableAlias, + @Nullable SqlCriterion onJoinCriterion, List andJoinCriteria) { addJoinSpecificationSupplier(buildSubQuery(subQuery, tableAlias), onJoinCriterion, JoinType.LEFT, andJoinCriteria); return getThis(); @@ -127,20 +128,20 @@ public T rightJoin(SqlTable joinTable, String tableAlias, SqlCriterion onJoinCri return rightJoin(joinTable, onJoinCriterion, andJoinCriteria); } - public T rightJoin(SqlTable joinTable, SqlCriterion onJoinCriterion, + public T rightJoin(SqlTable joinTable, @Nullable SqlCriterion onJoinCriterion, List andJoinCriteria) { addJoinSpecificationSupplier(joinTable, onJoinCriterion, JoinType.RIGHT, andJoinCriteria); return getThis(); } - public T rightJoin(SqlTable joinTable, String tableAlias, SqlCriterion onJoinCriterion, + public T rightJoin(SqlTable joinTable, String tableAlias, @Nullable SqlCriterion onJoinCriterion, List andJoinCriteria) { addTableAlias(joinTable, tableAlias); return rightJoin(joinTable, onJoinCriterion, andJoinCriteria); } - public T rightJoin(Buildable subQuery, String tableAlias, SqlCriterion onJoinCriterion, - List andJoinCriteria) { + public T rightJoin(Buildable subQuery, @Nullable String tableAlias, + @Nullable SqlCriterion onJoinCriterion, List andJoinCriteria) { addJoinSpecificationSupplier(buildSubQuery(subQuery, tableAlias), onJoinCriterion, JoinType.RIGHT, andJoinCriteria); return getThis(); @@ -158,26 +159,26 @@ public T fullJoin(SqlTable joinTable, String tableAlias, SqlCriterion onJoinCrit return fullJoin(joinTable, onJoinCriterion, andJoinCriteria); } - public T fullJoin(SqlTable joinTable, SqlCriterion onJoinCriterion, + public T fullJoin(SqlTable joinTable, @Nullable SqlCriterion onJoinCriterion, List andJoinCriteria) { addJoinSpecificationSupplier(joinTable, onJoinCriterion, JoinType.FULL, andJoinCriteria); return getThis(); } - public T fullJoin(SqlTable joinTable, String tableAlias, SqlCriterion onJoinCriterion, + public T fullJoin(SqlTable joinTable, String tableAlias, @Nullable SqlCriterion onJoinCriterion, List andJoinCriteria) { addTableAlias(joinTable, tableAlias); return fullJoin(joinTable, onJoinCriterion, andJoinCriteria); } - public T fullJoin(Buildable subQuery, String tableAlias, SqlCriterion onJoinCriterion, - List andJoinCriteria) { + public T fullJoin(Buildable subQuery, @Nullable String tableAlias, + @Nullable SqlCriterion onJoinCriterion, List andJoinCriteria) { addJoinSpecificationSupplier(buildSubQuery(subQuery, tableAlias), onJoinCriterion, JoinType.FULL, andJoinCriteria); return getThis(); } - private void addJoinSpecificationSupplier(TableExpression joinTable, SqlCriterion onJoinCriterion, + private void addJoinSpecificationSupplier(TableExpression joinTable, @Nullable SqlCriterion onJoinCriterion, JoinType joinType, List andJoinCriteria) { joinSpecificationSuppliers.add(() -> new JoinSpecification.Builder() .withJoinTable(joinTable) @@ -218,7 +219,7 @@ protected static SubQuery buildSubQuery(Buildable selectModel) { .build(); } - protected static SubQuery buildSubQuery(Buildable selectModel, String alias) { + protected static SubQuery buildSubQuery(Buildable selectModel, @Nullable String alias) { return new SubQuery.Builder() .withSelectModel(selectModel.build()) .withAlias(alias) diff --git a/src/main/java/org/mybatis/dynamic/sql/select/AbstractSelectModel.java b/src/main/java/org/mybatis/dynamic/sql/select/AbstractSelectModel.java index d19f45c55..51c3d4fe7 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/AbstractSelectModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/AbstractSelectModel.java @@ -18,12 +18,13 @@ import java.util.Objects; import java.util.Optional; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.common.OrderByModel; import org.mybatis.dynamic.sql.configuration.StatementConfiguration; public abstract class AbstractSelectModel { - private final OrderByModel orderByModel; - private final PagingModel pagingModel; + private final @Nullable OrderByModel orderByModel; + private final @Nullable PagingModel pagingModel; protected final StatementConfiguration statementConfiguration; protected AbstractSelectModel(AbstractBuilder builder) { @@ -45,16 +46,16 @@ public StatementConfiguration statementConfiguration() { } public abstract static class AbstractBuilder> { - private OrderByModel orderByModel; - private PagingModel pagingModel; - private StatementConfiguration statementConfiguration; + private @Nullable OrderByModel orderByModel; + private @Nullable PagingModel pagingModel; + private @Nullable StatementConfiguration statementConfiguration; - public T withOrderByModel(OrderByModel orderByModel) { + public T withOrderByModel(@Nullable OrderByModel orderByModel) { this.orderByModel = orderByModel; return getThis(); } - public T withPagingModel(PagingModel pagingModel) { + public T withPagingModel(@Nullable PagingModel pagingModel) { this.pagingModel = pagingModel; return getThis(); } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/CountDSL.java b/src/main/java/org/mybatis/dynamic/sql/select/CountDSL.java index 069249072..a867c8bf8 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/CountDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/CountDSL.java @@ -19,7 +19,7 @@ import java.util.function.Consumer; import java.util.function.Function; -import org.jetbrains.annotations.NotNull; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.BasicColumn; import org.mybatis.dynamic.sql.SqlBuilder; import org.mybatis.dynamic.sql.SqlTable; @@ -42,7 +42,7 @@ public class CountDSL extends AbstractQueryExpressionDSL.CountWhe implements Buildable { private final Function adapterFunction; - private CountWhereBuilder whereBuilder; + private @Nullable CountWhereBuilder whereBuilder; private final BasicColumn countColumn; private final StatementConfiguration statementConfiguration = new StatementConfiguration(); @@ -58,7 +58,6 @@ public CountWhereBuilder where() { return whereBuilder; } - @NotNull @Override public R build() { return adapterFunction.apply(buildModel()); @@ -134,7 +133,6 @@ private CountWhereBuilder() { super(CountDSL.this); } - @NotNull @Override public R build() { return CountDSL.this.build(); diff --git a/src/main/java/org/mybatis/dynamic/sql/select/HavingDSL.java b/src/main/java/org/mybatis/dynamic/sql/select/HavingDSL.java index 2f5a7e5fa..34be15f62 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/HavingDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/HavingDSL.java @@ -15,7 +15,6 @@ */ package org.mybatis.dynamic.sql.select; -import org.jetbrains.annotations.NotNull; import org.mybatis.dynamic.sql.util.Buildable; public class HavingDSL extends AbstractHavingStarter { @@ -36,7 +35,6 @@ protected StandaloneHavingFinisher getThis() { return this; } - @NotNull @Override public HavingModel build() { return buildModel(); diff --git a/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectDSL.java b/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectDSL.java index 2eb3c8b89..308107c30 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectDSL.java @@ -22,7 +22,7 @@ import java.util.Optional; import java.util.function.Consumer; -import org.jetbrains.annotations.NotNull; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.SortSpecification; import org.mybatis.dynamic.sql.common.OrderByModel; import org.mybatis.dynamic.sql.configuration.StatementConfiguration; @@ -33,10 +33,10 @@ public class MultiSelectDSL implements Buildable, Configurable PagingDSL { private final List unionQueries = new ArrayList<>(); private final SelectModel initialSelect; - private OrderByModel orderByModel; - private Long limit; - private Long offset; - private Long fetchFirstRows; + private @Nullable OrderByModel orderByModel; + private @Nullable Long limit; + private @Nullable Long offset; + private @Nullable Long fetchFirstRows; private final StatementConfiguration statementConfiguration = new StatementConfiguration(); public MultiSelectDSL(Buildable builder) { @@ -63,24 +63,23 @@ public MultiSelectDSL orderBy(Collection columns) { } @Override - public LimitFinisher limitWhenPresent(Long limit) { + public LimitFinisher limitWhenPresent(@Nullable Long limit) { this.limit = limit; return new LocalLimitFinisher(); } @Override - public OffsetFirstFinisher offsetWhenPresent(Long offset) { + public OffsetFirstFinisher offsetWhenPresent(@Nullable Long offset) { this.offset = offset; return new LocalOffsetFirstFinisher(); } @Override - public FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows) { + public FetchFirstFinisher fetchFirstWhenPresent(@Nullable Long fetchFirstRows) { this.fetchFirstRows = fetchFirstRows; return () -> this; } - @NotNull @Override public MultiSelectModel build() { return new MultiSelectModel.Builder() @@ -107,7 +106,6 @@ public MultiSelectDSL configureStatement(Consumer consum } abstract class BaseBuildable implements Buildable { - @NotNull @Override public MultiSelectModel build() { return MultiSelectDSL.this.build(); diff --git a/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectModel.java b/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectModel.java index c61188d80..94dbe765b 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/MultiSelectModel.java @@ -20,7 +20,7 @@ import java.util.Objects; import java.util.stream.Stream; -import org.jetbrains.annotations.NotNull; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.render.RenderingStrategy; import org.mybatis.dynamic.sql.select.render.MultiSelectRenderer; import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; @@ -45,7 +45,6 @@ public Stream unionQueries() { return unionQueries.stream(); } - @NotNull public SelectStatementProvider render(RenderingStrategy renderingStrategy) { return MultiSelectRenderer.withMultiSelectModel(this) .withRenderingStrategy(renderingStrategy) @@ -54,7 +53,7 @@ public SelectStatementProvider render(RenderingStrategy renderingStrategy) { } public static class Builder extends AbstractBuilder { - private SelectModel initialSelect; + private @Nullable SelectModel initialSelect; private final List unionQueries = new ArrayList<>(); public Builder withInitialSelect(SelectModel initialSelect) { diff --git a/src/main/java/org/mybatis/dynamic/sql/select/PagingModel.java b/src/main/java/org/mybatis/dynamic/sql/select/PagingModel.java index 59b4a8bf2..b5da5e01c 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/PagingModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/PagingModel.java @@ -17,11 +17,13 @@ import java.util.Optional; +import org.jspecify.annotations.Nullable; + public class PagingModel { - private final Long limit; - private final Long offset; - private final Long fetchFirstRows; + private final @Nullable Long limit; + private final @Nullable Long offset; + private final @Nullable Long fetchFirstRows; private PagingModel(Builder builder) { super(); @@ -43,21 +45,21 @@ public Optional fetchFirstRows() { } public static class Builder { - private Long limit; - private Long offset; - private Long fetchFirstRows; + private @Nullable Long limit; + private @Nullable Long offset; + private @Nullable Long fetchFirstRows; - public Builder withLimit(Long limit) { + public Builder withLimit(@Nullable Long limit) { this.limit = limit; return this; } - public Builder withOffset(Long offset) { + public Builder withOffset(@Nullable Long offset) { this.offset = offset; return this; } - public Builder withFetchFirstRows(Long fetchFirstRows) { + public Builder withFetchFirstRows(@Nullable Long fetchFirstRows) { this.fetchFirstRows = fetchFirstRows; return this; } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionDSL.java b/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionDSL.java index 90156cea7..0964ee3b3 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionDSL.java @@ -22,7 +22,7 @@ import java.util.Objects; import java.util.function.Consumer; -import org.jetbrains.annotations.NotNull; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AndOrCriteriaGroup; import org.mybatis.dynamic.sql.BasicColumn; import org.mybatis.dynamic.sql.BindableColumn; @@ -46,13 +46,13 @@ public class QueryExpressionDSL extends AbstractQueryExpressionDSL.QueryExpressionWhereBuilder, QueryExpressionDSL> implements Buildable, PagingDSL { - private final String connector; + private final @Nullable String connector; private final SelectDSL selectDSL; private final boolean isDistinct; private final List selectList; - private QueryExpressionWhereBuilder whereBuilder; - private GroupByModel groupByModel; - private QueryExpressionHavingBuilder havingBuilder; + private @Nullable QueryExpressionWhereBuilder whereBuilder; + private @Nullable GroupByModel groupByModel; + private @Nullable QueryExpressionHavingBuilder havingBuilder; protected QueryExpressionDSL(FromGatherer fromGatherer, TableExpression table) { super(table); @@ -99,7 +99,6 @@ protected void applyHaving(CriteriaGroup criteriaGroup) { having().initialize(criteriaGroup); } - @NotNull @Override public R build() { return selectDSL.build(); @@ -197,17 +196,17 @@ protected QueryExpressionModel buildModel() { } @Override - public PagingDSL.LimitFinisher limitWhenPresent(Long limit) { + public PagingDSL.LimitFinisher limitWhenPresent(@Nullable Long limit) { return selectDSL.limitWhenPresent(limit); } @Override - public PagingDSL.OffsetFirstFinisher offsetWhenPresent(Long offset) { + public PagingDSL.OffsetFirstFinisher offsetWhenPresent(@Nullable Long offset) { return selectDSL.offsetWhenPresent(offset); } @Override - public PagingDSL.FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows) { + public PagingDSL.FetchFirstFinisher fetchFirstWhenPresent(@Nullable Long fetchFirstRows) { return selectDSL.fetchFirstWhenPresent(fetchFirstRows); } @@ -217,7 +216,7 @@ protected QueryExpressionDSL getThis() { } public static class FromGatherer { - private final String connector; + private final @Nullable String connector; private final List selectList; private final SelectDSL selectDSL; private final boolean isDistinct; @@ -246,9 +245,9 @@ public QueryExpressionDSL from(SqlTable table, String tableAlias) { } public static class Builder { - private String connector; + private @Nullable String connector; private final List selectList = new ArrayList<>(); - private SelectDSL selectDSL; + private @Nullable SelectDSL selectDSL; private boolean isDistinct; public Builder withConnector(String connector) { @@ -308,21 +307,20 @@ public GroupByFinisher groupBy(Collection columns) { } @Override - public PagingDSL.LimitFinisher limitWhenPresent(Long limit) { + public PagingDSL.LimitFinisher limitWhenPresent(@Nullable Long limit) { return QueryExpressionDSL.this.limitWhenPresent(limit); } @Override - public PagingDSL.OffsetFirstFinisher offsetWhenPresent(Long offset) { + public PagingDSL.OffsetFirstFinisher offsetWhenPresent(@Nullable Long offset) { return QueryExpressionDSL.this.offsetWhenPresent(offset); } @Override - public PagingDSL.FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows) { + public PagingDSL.FetchFirstFinisher fetchFirstWhenPresent(@Nullable Long fetchFirstRows) { return QueryExpressionDSL.this.fetchFirstWhenPresent(fetchFirstRows); } - @NotNull @Override public R build() { return QueryExpressionDSL.this.build(); @@ -400,7 +398,6 @@ private JoinSpecification buildJoinSpecification() { .build(); } - @NotNull @Override public R build() { return QueryExpressionDSL.this.build(); @@ -490,17 +487,17 @@ public SelectDSL orderBy(Collection columns) { } @Override - public PagingDSL.LimitFinisher limitWhenPresent(Long limit) { + public PagingDSL.LimitFinisher limitWhenPresent(@Nullable Long limit) { return QueryExpressionDSL.this.limitWhenPresent(limit); } @Override - public PagingDSL.OffsetFirstFinisher offsetWhenPresent(Long offset) { + public PagingDSL.OffsetFirstFinisher offsetWhenPresent(@Nullable Long offset) { return QueryExpressionDSL.this.offsetWhenPresent(offset); } @Override - public PagingDSL.FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows) { + public PagingDSL.FetchFirstFinisher fetchFirstWhenPresent(@Nullable Long fetchFirstRows) { return QueryExpressionDSL.this.fetchFirstWhenPresent(fetchFirstRows); } @@ -520,7 +517,6 @@ public SelectDSL orderBy(Collection columns) { return QueryExpressionDSL.this.orderBy(columns); } - @NotNull @Override public R build() { return QueryExpressionDSL.this.build(); @@ -535,17 +531,17 @@ public UnionBuilder unionAll() { } @Override - public PagingDSL.LimitFinisher limitWhenPresent(Long limit) { + public PagingDSL.LimitFinisher limitWhenPresent(@Nullable Long limit) { return QueryExpressionDSL.this.limitWhenPresent(limit); } @Override - public PagingDSL.OffsetFirstFinisher offsetWhenPresent(Long offset) { + public PagingDSL.OffsetFirstFinisher offsetWhenPresent(@Nullable Long offset) { return QueryExpressionDSL.this.offsetWhenPresent(offset); } @Override - public PagingDSL.FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows) { + public PagingDSL.FetchFirstFinisher fetchFirstWhenPresent(@Nullable Long fetchFirstRows) { return QueryExpressionDSL.this.fetchFirstWhenPresent(fetchFirstRows); } @@ -592,17 +588,17 @@ public class QueryExpressionHavingBuilder extends AbstractHavingFinisher, PagingDSL { @Override - public PagingDSL.LimitFinisher limitWhenPresent(Long limit) { + public PagingDSL.LimitFinisher limitWhenPresent(@Nullable Long limit) { return QueryExpressionDSL.this.limitWhenPresent(limit); } @Override - public PagingDSL.OffsetFirstFinisher offsetWhenPresent(Long offset) { + public PagingDSL.OffsetFirstFinisher offsetWhenPresent(@Nullable Long offset) { return QueryExpressionDSL.this.offsetWhenPresent(offset); } @Override - public PagingDSL.FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows) { + public PagingDSL.FetchFirstFinisher fetchFirstWhenPresent(@Nullable Long fetchFirstRows) { return QueryExpressionDSL.this.fetchFirstWhenPresent(fetchFirstRows); } @@ -622,7 +618,6 @@ public UnionBuilder unionAll() { return QueryExpressionDSL.this.unionAll(); } - @NotNull @Override public R build() { return QueryExpressionDSL.this.build(); diff --git a/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionModel.java b/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionModel.java index 4d5e948ea..4561c0781 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionModel.java @@ -23,6 +23,7 @@ import java.util.Optional; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.BasicColumn; import org.mybatis.dynamic.sql.SqlTable; import org.mybatis.dynamic.sql.TableExpression; @@ -31,15 +32,15 @@ import org.mybatis.dynamic.sql.where.EmbeddedWhereModel; public class QueryExpressionModel { - private final String connector; + private final @Nullable String connector; private final boolean isDistinct; private final List selectList; private final TableExpression table; - private final JoinModel joinModel; + private final @Nullable JoinModel joinModel; private final Map tableAliases; - private final EmbeddedWhereModel whereModel; - private final GroupByModel groupByModel; - private final HavingModel havingModel; + private final @Nullable EmbeddedWhereModel whereModel; + private final @Nullable GroupByModel groupByModel; + private final @Nullable HavingModel havingModel; private QueryExpressionModel(Builder builder) { connector = builder.connector; @@ -95,17 +96,17 @@ public static Builder withSelectList(List columnList) { } public static class Builder { - private String connector; + private @Nullable String connector; private boolean isDistinct; private final List selectList = new ArrayList<>(); - private TableExpression table; + private @Nullable TableExpression table; private final Map tableAliases = new HashMap<>(); - private EmbeddedWhereModel whereModel; - private JoinModel joinModel; - private GroupByModel groupByModel; - private HavingModel havingModel; + private @Nullable EmbeddedWhereModel whereModel; + private @Nullable JoinModel joinModel; + private @Nullable GroupByModel groupByModel; + private @Nullable HavingModel havingModel; - public Builder withConnector(String connector) { + public Builder withConnector(@Nullable String connector) { this.connector = connector; return this; } @@ -135,22 +136,22 @@ public Builder withTableAliases(Map tableAliases) { return this; } - public Builder withWhereModel(EmbeddedWhereModel whereModel) { + public Builder withWhereModel(@Nullable EmbeddedWhereModel whereModel) { this.whereModel = whereModel; return this; } - public Builder withJoinModel(JoinModel joinModel) { + public Builder withJoinModel(@Nullable JoinModel joinModel) { this.joinModel = joinModel; return this; } - public Builder withGroupByModel(GroupByModel groupByModel) { + public Builder withGroupByModel(@Nullable GroupByModel groupByModel) { this.groupByModel = groupByModel; return this; } - public Builder withHavingModel(HavingModel havingModel) { + public Builder withHavingModel(@Nullable HavingModel havingModel) { this.havingModel = havingModel; return this; } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/SelectDSL.java b/src/main/java/org/mybatis/dynamic/sql/select/SelectDSL.java index eed99b218..7f1fd239b 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/SelectDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/SelectDSL.java @@ -24,7 +24,7 @@ import java.util.function.Consumer; import java.util.function.Function; -import org.jetbrains.annotations.NotNull; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.BasicColumn; import org.mybatis.dynamic.sql.SortSpecification; import org.mybatis.dynamic.sql.common.OrderByModel; @@ -45,10 +45,10 @@ public class SelectDSL implements Buildable, ConfigurableStatement adapterFunction; private final List> queryExpressions = new ArrayList<>(); - private OrderByModel orderByModel; - private Long limit; - private Long offset; - private Long fetchFirstRows; + private @Nullable OrderByModel orderByModel; + private @Nullable Long limit; + private @Nullable Long offset; + private @Nullable Long fetchFirstRows; final StatementConfiguration statementConfiguration = new StatementConfiguration(); private SelectDSL(Function adapterFunction) { @@ -107,17 +107,17 @@ void orderBy(Collection columns) { orderByModel = OrderByModel.of(columns); } - public LimitFinisher limitWhenPresent(Long limit) { + public LimitFinisher limitWhenPresent(@Nullable Long limit) { this.limit = limit; return new LocalLimitFinisher(); } - public OffsetFirstFinisher offsetWhenPresent(Long offset) { + public OffsetFirstFinisher offsetWhenPresent(@Nullable Long offset) { this.offset = offset; return new LocalOffsetFirstFinisher(); } - public FetchFirstFinisher fetchFirstWhenPresent(Long fetchFirstRows) { + public FetchFirstFinisher fetchFirstWhenPresent(@Nullable Long fetchFirstRows) { this.fetchFirstRows = fetchFirstRows; return () -> this; } @@ -128,7 +128,6 @@ public SelectDSL configureStatement(Consumer consumer return this; } - @NotNull @Override public R build() { SelectModel selectModel = SelectModel.withQueryExpressions(buildModels()) @@ -154,7 +153,6 @@ private Optional buildPagingModel() { } abstract class BaseBuildable implements Buildable { - @NotNull @Override public R build() { return SelectDSL.this.build(); diff --git a/src/main/java/org/mybatis/dynamic/sql/select/SelectModel.java b/src/main/java/org/mybatis/dynamic/sql/select/SelectModel.java index cb7d135dd..fd4eecc0c 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/SelectModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/SelectModel.java @@ -20,7 +20,6 @@ import java.util.Objects; import java.util.stream.Stream; -import org.jetbrains.annotations.NotNull; import org.mybatis.dynamic.sql.render.RenderingStrategy; import org.mybatis.dynamic.sql.select.render.SelectRenderer; import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; @@ -39,7 +38,6 @@ public Stream queryExpressions() { return queryExpressions.stream(); } - @NotNull public SelectStatementProvider render(RenderingStrategy renderingStrategy) { return SelectRenderer.withSelectModel(this) .withRenderingStrategy(renderingStrategy) diff --git a/src/main/java/org/mybatis/dynamic/sql/select/SubQuery.java b/src/main/java/org/mybatis/dynamic/sql/select/SubQuery.java index 271682870..c2264c162 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/SubQuery.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/SubQuery.java @@ -18,12 +18,13 @@ import java.util.Objects; import java.util.Optional; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.TableExpression; import org.mybatis.dynamic.sql.TableExpressionVisitor; public class SubQuery implements TableExpression { private final SelectModel selectModel; - private final String alias; + private final @Nullable String alias; private SubQuery(Builder builder) { selectModel = Objects.requireNonNull(builder.selectModel); @@ -49,15 +50,15 @@ public R accept(TableExpressionVisitor visitor) { } public static class Builder { - private SelectModel selectModel; - private String alias; + private @Nullable SelectModel selectModel; + private @Nullable String alias; public Builder withSelectModel(SelectModel selectModel) { this.selectModel = selectModel; return this; } - public Builder withAlias(String alias) { + public Builder withAlias(@Nullable String alias) { this.alias = alias; return this; } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/aggregate/AbstractCount.java b/src/main/java/org/mybatis/dynamic/sql/select/aggregate/AbstractCount.java index ae91015ae..fe40329ea 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/aggregate/AbstractCount.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/aggregate/AbstractCount.java @@ -17,6 +17,7 @@ import java.util.Optional; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.BindableColumn; /** @@ -25,13 +26,13 @@ * as it is assumed that the count functions always return a number. */ public abstract class AbstractCount implements BindableColumn { - private final String alias; + private final @Nullable String alias; protected AbstractCount() { this(null); } - protected AbstractCount(String alias) { + protected AbstractCount(@Nullable String alias) { this.alias = alias; } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/aggregate/package-info.java b/src/main/java/org/mybatis/dynamic/sql/select/aggregate/package-info.java new file mode 100644 index 000000000..60e9e8918 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/select/aggregate/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright 2016-2025 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. + */ +@NullMarked +package org.mybatis.dynamic.sql.select.aggregate; + +import org.jspecify.annotations.NullMarked; diff --git a/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SearchedCaseDSL.java b/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SearchedCaseDSL.java index 1dbd663a3..0c0c6ea87 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SearchedCaseDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SearchedCaseDSL.java @@ -19,6 +19,7 @@ import java.util.Arrays; import java.util.List; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AndOrCriteriaGroup; import org.mybatis.dynamic.sql.BasicColumn; import org.mybatis.dynamic.sql.BindableColumn; @@ -30,7 +31,7 @@ public class SearchedCaseDSL implements ElseDSL { private final List whenConditions = new ArrayList<>(); - private BasicColumn elseValue; + private @Nullable BasicColumn elseValue; public WhenDSL when(BindableColumn column, VisitableCondition condition, AndOrCriteriaGroup... subCriteria) { diff --git a/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SearchedCaseModel.java b/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SearchedCaseModel.java index 8ca95513c..c42372868 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SearchedCaseModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SearchedCaseModel.java @@ -20,6 +20,7 @@ import java.util.Optional; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.BasicColumn; import org.mybatis.dynamic.sql.SortSpecification; import org.mybatis.dynamic.sql.render.RenderingContext; @@ -29,8 +30,8 @@ public class SearchedCaseModel implements BasicColumn, SortSpecification { private final List whenConditions; - private final BasicColumn elseValue; - private final String alias; + private final @Nullable BasicColumn elseValue; + private final @Nullable String alias; private final String descendingPhrase; private SearchedCaseModel(Builder builder) { @@ -84,8 +85,8 @@ public FragmentAndParameters render(RenderingContext renderingContext) { public static class Builder { private final List whenConditions = new ArrayList<>(); - private BasicColumn elseValue; - private String alias; + private @Nullable BasicColumn elseValue; + private @Nullable String alias; private String descendingPhrase = ""; //$NON-NLS-1$ public Builder withWhenConditions(List whenConditions) { @@ -93,12 +94,12 @@ public Builder withWhenConditions(List whenConditions return this; } - public Builder withElseValue(BasicColumn elseValue) { + public Builder withElseValue(@Nullable BasicColumn elseValue) { this.elseValue = elseValue; return this; } - public Builder withAlias(String alias) { + public Builder withAlias(@Nullable String alias) { this.alias = alias; return this; } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SearchedCaseWhenCondition.java b/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SearchedCaseWhenCondition.java index 21fab5010..9b251be9c 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SearchedCaseWhenCondition.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SearchedCaseWhenCondition.java @@ -17,6 +17,7 @@ import java.util.Objects; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.BasicColumn; import org.mybatis.dynamic.sql.common.AbstractBooleanExpressionModel; @@ -33,7 +34,7 @@ private SearchedCaseWhenCondition(Builder builder) { } public static class Builder extends AbstractBuilder { - private BasicColumn thenValue; + private @Nullable BasicColumn thenValue; public Builder withThenValue(BasicColumn thenValue) { this.thenValue = thenValue; diff --git a/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SimpleCaseDSL.java b/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SimpleCaseDSL.java index 8fc7a8360..488f20060 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SimpleCaseDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SimpleCaseDSL.java @@ -20,6 +20,7 @@ import java.util.List; import java.util.Objects; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.BasicColumn; import org.mybatis.dynamic.sql.BindableColumn; import org.mybatis.dynamic.sql.VisitableCondition; @@ -27,7 +28,7 @@ public class SimpleCaseDSL implements ElseDSL.SimpleCaseEnder> { private final BindableColumn column; private final List> whenConditions = new ArrayList<>(); - private BasicColumn elseValue; + private @Nullable BasicColumn elseValue; private SimpleCaseDSL(BindableColumn column) { this.column = Objects.requireNonNull(column); diff --git a/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SimpleCaseModel.java b/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SimpleCaseModel.java index db666df22..45eb95c01 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SimpleCaseModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/SimpleCaseModel.java @@ -21,6 +21,7 @@ import java.util.Optional; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.BasicColumn; import org.mybatis.dynamic.sql.BindableColumn; import org.mybatis.dynamic.sql.SortSpecification; @@ -32,8 +33,8 @@ public class SimpleCaseModel implements BasicColumn, SortSpecification { private final BindableColumn column; private final List> whenConditions; - private final BasicColumn elseValue; - private final String alias; + private final @Nullable BasicColumn elseValue; + private final @Nullable String alias; private final String descendingPhrase; private SimpleCaseModel(Builder builder) { @@ -95,10 +96,10 @@ public FragmentAndParameters render(RenderingContext renderingContext) { } public static class Builder { - private BindableColumn column; + private @Nullable BindableColumn column; private final List> whenConditions = new ArrayList<>(); - private BasicColumn elseValue; - private String alias; + private @Nullable BasicColumn elseValue; + private @Nullable String alias; private String descendingPhrase = ""; //$NON-NLS-1$ public Builder withColumn(BindableColumn column) { @@ -111,12 +112,12 @@ public Builder withWhenConditions(List> whenCondit return this; } - public Builder withElseValue(BasicColumn elseValue) { + public Builder withElseValue(@Nullable BasicColumn elseValue) { this.elseValue = elseValue; return this; } - public Builder withAlias(String alias) { + public Builder withAlias(@Nullable String alias) { this.alias = alias; return this; } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/package-info.java b/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/package-info.java new file mode 100644 index 000000000..a383bc305 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/select/caseexpression/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright 2016-2025 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. + */ +@NullMarked +package org.mybatis.dynamic.sql.select.caseexpression; + +import org.jspecify.annotations.NullMarked; diff --git a/src/main/java/org/mybatis/dynamic/sql/select/function/AbstractTypeConvertingFunction.java b/src/main/java/org/mybatis/dynamic/sql/select/function/AbstractTypeConvertingFunction.java index 448b97cad..1517d3519 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/function/AbstractTypeConvertingFunction.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/function/AbstractTypeConvertingFunction.java @@ -18,6 +18,8 @@ import java.util.Objects; import java.util.Optional; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.BasicColumn; import org.mybatis.dynamic.sql.BindableColumn; @@ -38,7 +40,7 @@ public abstract class AbstractTypeConvertingFunction> implements BindableColumn { protected final BasicColumn column; - protected String alias; + protected @Nullable String alias; protected AbstractTypeConvertingFunction(BasicColumn column) { this.column = Objects.requireNonNull(column); @@ -49,6 +51,7 @@ public Optional alias() { return Optional.ofNullable(alias); } + @NonNull @Override public U as(String alias) { U newThing = copy(); diff --git a/src/main/java/org/mybatis/dynamic/sql/select/function/Cast.java b/src/main/java/org/mybatis/dynamic/sql/select/function/Cast.java index 742ba2705..1349d4f51 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/function/Cast.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/function/Cast.java @@ -18,6 +18,7 @@ import java.util.Objects; import java.util.Optional; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.BasicColumn; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.util.FragmentAndParameters; @@ -25,7 +26,7 @@ public class Cast implements BasicColumn { private final BasicColumn column; private final String targetType; - private final String alias; + private final @Nullable String alias; private Cast(Builder builder) { column = Objects.requireNonNull(builder.column); @@ -56,9 +57,9 @@ private String applyCast(String in) { } public static class Builder { - private BasicColumn column; - private String targetType; - private String alias; + private @Nullable BasicColumn column; + private @Nullable String targetType; + private @Nullable String alias; public Builder withColumn(BasicColumn column) { this.column = column; diff --git a/src/main/java/org/mybatis/dynamic/sql/select/function/package-info.java b/src/main/java/org/mybatis/dynamic/sql/select/function/package-info.java new file mode 100644 index 000000000..4f8535279 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/select/function/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright 2016-2025 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. + */ +@NullMarked +package org.mybatis.dynamic.sql.select.function; + +import org.jspecify.annotations.NullMarked; diff --git a/src/main/java/org/mybatis/dynamic/sql/select/join/JoinModel.java b/src/main/java/org/mybatis/dynamic/sql/select/join/JoinModel.java index ab6cc67db..fe987c1b4 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/join/JoinModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/join/JoinModel.java @@ -20,13 +20,14 @@ import java.util.Objects; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.TableExpression; import org.mybatis.dynamic.sql.util.Validator; public class JoinModel { private final List joinSpecifications = new ArrayList<>(); - private JoinModel(List joinSpecifications) { + private JoinModel(@Nullable List joinSpecifications) { Objects.requireNonNull(joinSpecifications); Validator.assertNotEmpty(joinSpecifications, "ERROR.15"); //$NON-NLS-1$ this.joinSpecifications.addAll(joinSpecifications); @@ -36,7 +37,7 @@ public Stream joinSpecifications() { return joinSpecifications.stream(); } - public static JoinModel of(List joinSpecifications) { + public static JoinModel of(@Nullable List joinSpecifications) { return new JoinModel(joinSpecifications); } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/join/JoinSpecification.java b/src/main/java/org/mybatis/dynamic/sql/select/join/JoinSpecification.java index 5ce6677cc..8cefbba6b 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/join/JoinSpecification.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/join/JoinSpecification.java @@ -17,6 +17,7 @@ import java.util.Objects; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.TableExpression; import org.mybatis.dynamic.sql.common.AbstractBooleanExpressionModel; import org.mybatis.dynamic.sql.util.Validator; @@ -47,8 +48,8 @@ public static Builder withJoinTable(TableExpression table) { } public static class Builder extends AbstractBuilder { - private TableExpression table; - private JoinType joinType; + private @Nullable TableExpression table; + private @Nullable JoinType joinType; public Builder withJoinTable(TableExpression table) { this.table = table; diff --git a/src/main/java/org/mybatis/dynamic/sql/select/join/package-info.java b/src/main/java/org/mybatis/dynamic/sql/select/join/package-info.java new file mode 100644 index 000000000..03ec51bcc --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/select/join/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright 2016-2025 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. + */ +@NullMarked +package org.mybatis.dynamic.sql.select.join; + +import org.jspecify.annotations.NullMarked; diff --git a/src/main/java/org/mybatis/dynamic/sql/select/package-info.java b/src/main/java/org/mybatis/dynamic/sql/select/package-info.java new file mode 100644 index 000000000..7e49fd4ec --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/select/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright 2016-2025 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. + */ +@NullMarked +package org.mybatis.dynamic.sql.select; + +import org.jspecify.annotations.NullMarked; diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/DefaultSelectStatementProvider.java b/src/main/java/org/mybatis/dynamic/sql/select/render/DefaultSelectStatementProvider.java index e84eea978..a79029144 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/DefaultSelectStatementProvider.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/DefaultSelectStatementProvider.java @@ -20,6 +20,8 @@ import java.util.Map; import java.util.Objects; +import org.jspecify.annotations.Nullable; + public class DefaultSelectStatementProvider implements SelectStatementProvider { private final String selectStatement; private final Map parameters; @@ -44,7 +46,7 @@ public static Builder withSelectStatement(String selectStatement) { } public static class Builder { - private String selectStatement; + private @Nullable String selectStatement; private final Map parameters = new HashMap<>(); public Builder withSelectStatement(String selectStatement) { diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/JoinRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/JoinRenderer.java index 67e84bc5a..c1e8a0387 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/JoinRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/JoinRenderer.java @@ -18,6 +18,7 @@ import java.util.Objects; import java.util.stream.Collectors; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.exception.InvalidSqlException; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.select.join.JoinModel; @@ -63,9 +64,9 @@ public static Builder withJoinModel(JoinModel joinModel) { } public static class Builder { - private JoinModel joinModel; - private TableExpressionRenderer tableExpressionRenderer; - private RenderingContext renderingContext; + private @Nullable JoinModel joinModel; + private @Nullable TableExpressionRenderer tableExpressionRenderer; + private @Nullable RenderingContext renderingContext; public Builder withJoinModel(JoinModel joinModel) { this.joinModel = joinModel; diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/MultiSelectRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/MultiSelectRenderer.java index 6634da889..4daf576d4 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/MultiSelectRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/MultiSelectRenderer.java @@ -19,6 +19,7 @@ import java.util.Optional; import java.util.stream.Collectors; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.common.OrderByModel; import org.mybatis.dynamic.sql.common.OrderByRenderer; import org.mybatis.dynamic.sql.render.RenderingContext; @@ -37,7 +38,7 @@ public class MultiSelectRenderer { private MultiSelectRenderer(Builder builder) { multiSelectModel = Objects.requireNonNull(builder.multiSelectModel); renderingContext = RenderingContext - .withRenderingStrategy(builder.renderingStrategy) + .withRenderingStrategy(Objects.requireNonNull(builder.renderingStrategy)) .withStatementConfiguration(multiSelectModel.statementConfiguration()) .build(); } @@ -106,8 +107,8 @@ public static Builder withMultiSelectModel(MultiSelectModel multiSelectModel) { } public static class Builder { - private RenderingStrategy renderingStrategy; - private MultiSelectModel multiSelectModel; + private @Nullable RenderingStrategy renderingStrategy; + private @Nullable MultiSelectModel multiSelectModel; public Builder withRenderingStrategy(RenderingStrategy renderingStrategy) { this.renderingStrategy = renderingStrategy; diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/PagingModelRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/PagingModelRenderer.java index fecebbf92..6b79de960 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/PagingModelRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/PagingModelRenderer.java @@ -17,6 +17,7 @@ import java.util.Objects; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.select.PagingModel; import org.mybatis.dynamic.sql.util.FragmentAndParameters; @@ -44,8 +45,8 @@ private FragmentAndParameters fetchFirstRender() { } public static class Builder { - private PagingModel pagingModel; - private RenderingContext renderingContext; + private @Nullable PagingModel pagingModel; + private @Nullable RenderingContext renderingContext; public Builder withRenderingContext(RenderingContext renderingContext) { this.renderingContext = renderingContext; diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/QueryExpressionRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/QueryExpressionRenderer.java index d1c5baf09..610ba6d10 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/QueryExpressionRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/QueryExpressionRenderer.java @@ -19,6 +19,7 @@ import java.util.Optional; import java.util.stream.Collectors; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.BasicColumn; import org.mybatis.dynamic.sql.TableExpression; import org.mybatis.dynamic.sql.render.ExplicitTableAliasCalculator; @@ -43,7 +44,8 @@ private QueryExpressionRenderer(Builder builder) { queryExpression = Objects.requireNonNull(builder.queryExpression); TableAliasCalculator childTableAliasCalculator = calculateChildTableAliasCalculator(queryExpression); - renderingContext = builder.renderingContext.withChildTableAliasCalculator(childTableAliasCalculator); + renderingContext = Objects.requireNonNull(builder.renderingContext) + .withChildTableAliasCalculator(childTableAliasCalculator); tableExpressionRenderer = new TableExpressionRenderer.Builder() .withRenderingContext(renderingContext) @@ -199,8 +201,8 @@ public static Builder withQueryExpression(QueryExpressionModel model) { } public static class Builder { - private QueryExpressionModel queryExpression; - private RenderingContext renderingContext; + private @Nullable QueryExpressionModel queryExpression; + private @Nullable RenderingContext renderingContext; public Builder withRenderingContext(RenderingContext renderingContext) { this.renderingContext = renderingContext; diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/SelectRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/SelectRenderer.java index 048a0b0e6..719d6aafe 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/SelectRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/SelectRenderer.java @@ -17,6 +17,7 @@ import java.util.Objects; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.render.RenderingStrategy; import org.mybatis.dynamic.sql.select.SelectModel; @@ -51,8 +52,8 @@ public static Builder withSelectModel(SelectModel selectModel) { } public static class Builder { - private SelectModel selectModel; - private RenderingStrategy renderingStrategy; + private @Nullable SelectModel selectModel; + private @Nullable RenderingStrategy renderingStrategy; public Builder withRenderingStrategy(RenderingStrategy renderingStrategy) { this.renderingStrategy = renderingStrategy; diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/SubQueryRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/SubQueryRenderer.java index 906adc8f9..6c4eb82ad 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/SubQueryRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/SubQueryRenderer.java @@ -19,6 +19,7 @@ import java.util.Optional; import java.util.stream.Collectors; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.common.OrderByModel; import org.mybatis.dynamic.sql.common.OrderByRenderer; import org.mybatis.dynamic.sql.render.RenderingContext; @@ -85,10 +86,10 @@ public static Builder withSelectModel(SelectModel selectModel) { } public static class Builder { - private SelectModel selectModel; - private RenderingContext renderingContext; - private String prefix; - private String suffix; + private @Nullable SelectModel selectModel; + private @Nullable RenderingContext renderingContext; + private @Nullable String prefix; + private @Nullable String suffix; public Builder withRenderingContext(RenderingContext renderingContext) { this.renderingContext = renderingContext; diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/TableExpressionRenderer.java b/src/main/java/org/mybatis/dynamic/sql/select/render/TableExpressionRenderer.java index 402013623..8114e2411 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/render/TableExpressionRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/TableExpressionRenderer.java @@ -17,6 +17,7 @@ import java.util.Objects; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.SqlTable; import org.mybatis.dynamic.sql.TableExpressionVisitor; import org.mybatis.dynamic.sql.render.RenderingContext; @@ -49,7 +50,7 @@ public FragmentAndParameters visit(SubQuery subQuery) { } public static class Builder { - private RenderingContext renderingContext; + private @Nullable RenderingContext renderingContext; public Builder withRenderingContext(RenderingContext renderingContext) { this.renderingContext = renderingContext; diff --git a/src/main/java/org/mybatis/dynamic/sql/select/render/package-info.java b/src/main/java/org/mybatis/dynamic/sql/select/render/package-info.java new file mode 100644 index 000000000..d2f457254 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/select/render/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright 2016-2025 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. + */ +@NullMarked +package org.mybatis.dynamic.sql.select.render; + +import org.jspecify.annotations.NullMarked; diff --git a/src/main/java/org/mybatis/dynamic/sql/update/UpdateDSL.java b/src/main/java/org/mybatis/dynamic/sql/update/UpdateDSL.java index 75ccc9ac2..c6fcd50d7 100644 --- a/src/main/java/org/mybatis/dynamic/sql/update/UpdateDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/update/UpdateDSL.java @@ -24,7 +24,7 @@ import java.util.function.Function; import java.util.function.Supplier; -import org.jetbrains.annotations.NotNull; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.BasicColumn; import org.mybatis.dynamic.sql.SortSpecification; import org.mybatis.dynamic.sql.SqlColumn; @@ -53,13 +53,13 @@ public class UpdateDSL implements AbstractWhereStarter.UpdateWhe private final Function adapterFunction; private final List columnMappings = new ArrayList<>(); private final SqlTable table; - private final String tableAlias; - private UpdateWhereBuilder whereBuilder; + private final @Nullable String tableAlias; + private @Nullable UpdateWhereBuilder whereBuilder; private final StatementConfiguration statementConfiguration = new StatementConfiguration(); - private Long limit; - private OrderByModel orderByModel; + private @Nullable Long limit; + private @Nullable OrderByModel orderByModel; - private UpdateDSL(SqlTable table, String tableAlias, Function adapterFunction) { + private UpdateDSL(SqlTable table, @Nullable String tableAlias, Function adapterFunction) { this.table = Objects.requireNonNull(table); this.tableAlias = tableAlias; this.adapterFunction = Objects.requireNonNull(adapterFunction); @@ -79,7 +79,7 @@ public UpdateDSL limit(long limit) { return limitWhenPresent(limit); } - public UpdateDSL limitWhenPresent(Long limit) { + public UpdateDSL limitWhenPresent(@Nullable Long limit) { this.limit = limit; return this; } @@ -99,7 +99,6 @@ public UpdateDSL orderBy(Collection columns) { * * @return the update model */ - @NotNull @Override public R build() { UpdateModel updateModel = UpdateModel.withTable(table) @@ -120,7 +119,8 @@ public UpdateDSL configureStatement(Consumer consumer return this; } - public static UpdateDSL update(Function adapterFunction, SqlTable table, String tableAlias) { + public static UpdateDSL update(Function adapterFunction, SqlTable table, + @Nullable String tableAlias) { return new UpdateDSL<>(table, tableAlias, adapterFunction); } @@ -174,20 +174,20 @@ public UpdateDSL equalTo(BasicColumn rightColumn) { return UpdateDSL.this; } - public UpdateDSL equalToOrNull(T value) { + public UpdateDSL equalToOrNull(@Nullable T value) { return equalToOrNull(() -> value); } - public UpdateDSL equalToOrNull(Supplier valueSupplier) { + public UpdateDSL equalToOrNull(Supplier<@Nullable T> valueSupplier) { columnMappings.add(ValueOrNullMapping.of(column, valueSupplier)); return UpdateDSL.this; } - public UpdateDSL equalToWhenPresent(T value) { + public UpdateDSL equalToWhenPresent(@Nullable T value) { return equalToWhenPresent(() -> value); } - public UpdateDSL equalToWhenPresent(Supplier valueSupplier) { + public UpdateDSL equalToWhenPresent(Supplier<@Nullable T> valueSupplier) { columnMappings.add(ValueWhenPresentMapping.of(column, valueSupplier)); return UpdateDSL.this; } @@ -216,7 +216,6 @@ public UpdateDSL orderBy(Collection columns) { return UpdateDSL.this; } - @NotNull @Override public R build() { return UpdateDSL.this.build(); diff --git a/src/main/java/org/mybatis/dynamic/sql/update/UpdateModel.java b/src/main/java/org/mybatis/dynamic/sql/update/UpdateModel.java index 813ad51f8..7fd07f766 100644 --- a/src/main/java/org/mybatis/dynamic/sql/update/UpdateModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/update/UpdateModel.java @@ -21,7 +21,7 @@ import java.util.Optional; import java.util.stream.Stream; -import org.jetbrains.annotations.NotNull; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.SqlTable; import org.mybatis.dynamic.sql.common.CommonBuilder; import org.mybatis.dynamic.sql.common.OrderByModel; @@ -35,11 +35,11 @@ public class UpdateModel { private final SqlTable table; - private final String tableAlias; - private final EmbeddedWhereModel whereModel; + private final @Nullable String tableAlias; + private final @Nullable EmbeddedWhereModel whereModel; private final List columnMappings; - private final Long limit; - private final OrderByModel orderByModel; + private final @Nullable Long limit; + private final @Nullable OrderByModel orderByModel; private final StatementConfiguration statementConfiguration; private UpdateModel(Builder builder) { @@ -81,7 +81,6 @@ public StatementConfiguration statementConfiguration() { return statementConfiguration; } - @NotNull public UpdateStatementProvider render(RenderingStrategy renderingStrategy) { return UpdateRenderer.withUpdateModel(this) .withRenderingStrategy(renderingStrategy) diff --git a/src/main/java/org/mybatis/dynamic/sql/update/package-info.java b/src/main/java/org/mybatis/dynamic/sql/update/package-info.java new file mode 100644 index 000000000..b1b75a4f4 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/update/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright 2016-2025 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. + */ +@NullMarked +package org.mybatis.dynamic.sql.update; + +import org.jspecify.annotations.NullMarked; diff --git a/src/main/java/org/mybatis/dynamic/sql/update/render/DefaultUpdateStatementProvider.java b/src/main/java/org/mybatis/dynamic/sql/update/render/DefaultUpdateStatementProvider.java index 5e2d5d355..eb7f9fba6 100644 --- a/src/main/java/org/mybatis/dynamic/sql/update/render/DefaultUpdateStatementProvider.java +++ b/src/main/java/org/mybatis/dynamic/sql/update/render/DefaultUpdateStatementProvider.java @@ -19,6 +19,8 @@ import java.util.Map; import java.util.Objects; +import org.jspecify.annotations.Nullable; + public class DefaultUpdateStatementProvider implements UpdateStatementProvider { private final String updateStatement; private final Map parameters; @@ -43,7 +45,7 @@ public static Builder withUpdateStatement(String updateStatement) { } public static class Builder { - private String updateStatement; + private @Nullable String updateStatement; private final Map parameters = new HashMap<>(); public Builder withUpdateStatement(String updateStatement) { diff --git a/src/main/java/org/mybatis/dynamic/sql/update/render/SetPhraseVisitor.java b/src/main/java/org/mybatis/dynamic/sql/update/render/SetPhraseVisitor.java index 0e057ad47..5667830e2 100644 --- a/src/main/java/org/mybatis/dynamic/sql/update/render/SetPhraseVisitor.java +++ b/src/main/java/org/mybatis/dynamic/sql/update/render/SetPhraseVisitor.java @@ -18,6 +18,7 @@ import java.util.Objects; import java.util.Optional; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.render.RenderedParameterInfo; import org.mybatis.dynamic.sql.render.RenderingContext; import org.mybatis.dynamic.sql.select.render.SubQueryRenderer; @@ -103,7 +104,7 @@ public Optional visit(ColumnToColumnMapping mapping) { return Optional.of(fragmentAndParameters); } - private Optional buildValueFragment(AbstractColumnMapping mapping, T value) { + private Optional buildValueFragment(AbstractColumnMapping mapping, @Nullable T value) { RenderedParameterInfo parameterInfo = renderingContext.calculateParameterInfo(mapping.column()); String setPhrase = renderingContext.aliasedColumnName(mapping.column()) + " = " //$NON-NLS-1$ diff --git a/src/main/java/org/mybatis/dynamic/sql/update/render/UpdateRenderer.java b/src/main/java/org/mybatis/dynamic/sql/update/render/UpdateRenderer.java index a22b8f756..2a3599788 100644 --- a/src/main/java/org/mybatis/dynamic/sql/update/render/UpdateRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/update/render/UpdateRenderer.java @@ -20,6 +20,7 @@ import java.util.Optional; import java.util.stream.Collectors; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.common.OrderByModel; import org.mybatis.dynamic.sql.common.OrderByRenderer; import org.mybatis.dynamic.sql.render.ExplicitTableAliasCalculator; @@ -128,8 +129,8 @@ public static Builder withUpdateModel(UpdateModel updateModel) { } public static class Builder { - private UpdateModel updateModel; - private RenderingStrategy renderingStrategy; + private @Nullable UpdateModel updateModel; + private @Nullable RenderingStrategy renderingStrategy; public Builder withUpdateModel(UpdateModel updateModel) { this.updateModel = updateModel; diff --git a/src/main/java/org/mybatis/dynamic/sql/update/render/package-info.java b/src/main/java/org/mybatis/dynamic/sql/update/render/package-info.java new file mode 100644 index 000000000..625393ac4 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/update/render/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright 2016-2025 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. + */ +@NullMarked +package org.mybatis.dynamic.sql.update.render; + +import org.jspecify.annotations.NullMarked; diff --git a/src/main/java/org/mybatis/dynamic/sql/util/Buildable.java b/src/main/java/org/mybatis/dynamic/sql/util/Buildable.java index dcb9fde70..1dcbe70ea 100644 --- a/src/main/java/org/mybatis/dynamic/sql/util/Buildable.java +++ b/src/main/java/org/mybatis/dynamic/sql/util/Buildable.java @@ -15,10 +15,7 @@ */ package org.mybatis.dynamic.sql.util; -import org.jetbrains.annotations.NotNull; - @FunctionalInterface public interface Buildable { - @NotNull T build(); -} \ No newline at end of file +} diff --git a/src/main/java/org/mybatis/dynamic/sql/util/FragmentAndParameters.java b/src/main/java/org/mybatis/dynamic/sql/util/FragmentAndParameters.java index 44a679201..3426accf8 100644 --- a/src/main/java/org/mybatis/dynamic/sql/util/FragmentAndParameters.java +++ b/src/main/java/org/mybatis/dynamic/sql/util/FragmentAndParameters.java @@ -22,6 +22,8 @@ import java.util.Optional; import java.util.function.UnaryOperator; +import org.jspecify.annotations.Nullable; + public class FragmentAndParameters { private final String fragment; @@ -61,7 +63,7 @@ public static FragmentAndParameters fromFragment(String fragment) { } public static class Builder { - private String fragment; + private @Nullable String fragment; private final Map parameters = new HashMap<>(); public Builder withFragment(String fragment) { @@ -69,7 +71,10 @@ public Builder withFragment(String fragment) { return this; } - public Builder withParameter(String key, Object value) { + public Builder withParameter(String key, @Nullable Object value) { + // the value can be null because a parameter type converter may return null + + //noinspection DataFlowIssue parameters.put(key, value); return this; } diff --git a/src/main/java/org/mybatis/dynamic/sql/util/Predicates.java b/src/main/java/org/mybatis/dynamic/sql/util/Predicates.java index d840a214a..4fb7efa99 100644 --- a/src/main/java/org/mybatis/dynamic/sql/util/Predicates.java +++ b/src/main/java/org/mybatis/dynamic/sql/util/Predicates.java @@ -17,10 +17,12 @@ import java.util.function.BiPredicate; +import org.jspecify.annotations.Nullable; + public class Predicates { private Predicates() {} - public static BiPredicate bothPresent() { + public static BiPredicate<@Nullable T, @Nullable T> bothPresent() { return (v1, v2) -> v1 != null && v2 != null; } } diff --git a/src/main/java/org/mybatis/dynamic/sql/util/StringUtilities.java b/src/main/java/org/mybatis/dynamic/sql/util/StringUtilities.java index ea993d420..3104c2905 100644 --- a/src/main/java/org/mybatis/dynamic/sql/util/StringUtilities.java +++ b/src/main/java/org/mybatis/dynamic/sql/util/StringUtilities.java @@ -15,6 +15,8 @@ */ package org.mybatis.dynamic.sql.util; +import org.jspecify.annotations.Nullable; + public interface StringUtilities { static String spaceAfter(String in) { @@ -25,7 +27,7 @@ static String spaceBefore(String in) { return " " + in; //$NON-NLS-1$ } - static String safelyUpperCase(String s) { + static @Nullable String safelyUpperCase(@Nullable String s) { return s == null ? null : s.toUpperCase(); } @@ -44,7 +46,7 @@ static String toCamelCase(String inputString) { sb.append(Character.toLowerCase(c)); } } else { - if (sb.length() > 0) { + if (!sb.isEmpty()) { nextUpperCase = true; } } diff --git a/src/main/java/org/mybatis/dynamic/sql/util/Utilities.java b/src/main/java/org/mybatis/dynamic/sql/util/Utilities.java index 4a70597da..e0aa47bc0 100644 --- a/src/main/java/org/mybatis/dynamic/sql/util/Utilities.java +++ b/src/main/java/org/mybatis/dynamic/sql/util/Utilities.java @@ -15,14 +15,28 @@ */ package org.mybatis.dynamic.sql.util; +import java.util.Collection; +import java.util.Objects; import java.util.function.Supplier; +import java.util.stream.Stream; + +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; public interface Utilities { - static T buildIfNecessary(T current, Supplier builder) { + static T buildIfNecessary(@Nullable T current, @NonNull Supplier builder) { return current == null ? builder.get() : current; } - static long safelyUnbox(Long l) { + static long safelyUnbox(@Nullable Long l) { return l == null ? 0 : l; } + + static Stream<@NonNull T> filterNullValues(Stream<@Nullable T> values) { + return values.filter(Objects::nonNull); + } + + static Collection<@NonNull T> removeNullElements(Collection<@Nullable T> values) { + return filterNullValues(values.stream()).toList(); + } } diff --git a/src/main/java/org/mybatis/dynamic/sql/util/ValueMapping.java b/src/main/java/org/mybatis/dynamic/sql/util/ValueMapping.java index 424970f19..fc8681010 100644 --- a/src/main/java/org/mybatis/dynamic/sql/util/ValueMapping.java +++ b/src/main/java/org/mybatis/dynamic/sql/util/ValueMapping.java @@ -18,6 +18,7 @@ import java.util.Objects; import java.util.function.Supplier; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.SqlColumn; public class ValueMapping extends AbstractColumnMapping { @@ -32,7 +33,7 @@ private ValueMapping(SqlColumn column, Supplier valueSupplier) { localColumn = Objects.requireNonNull(column); } - public Object value() { + public @Nullable Object value() { return localColumn.convertParameterType(valueSupplier.get()); } diff --git a/src/main/java/org/mybatis/dynamic/sql/util/ValueOrNullMapping.java b/src/main/java/org/mybatis/dynamic/sql/util/ValueOrNullMapping.java index f1198c14d..f39a706ac 100644 --- a/src/main/java/org/mybatis/dynamic/sql/util/ValueOrNullMapping.java +++ b/src/main/java/org/mybatis/dynamic/sql/util/ValueOrNullMapping.java @@ -19,15 +19,16 @@ import java.util.Optional; import java.util.function.Supplier; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.SqlColumn; public class ValueOrNullMapping extends AbstractColumnMapping { - private final Supplier valueSupplier; + private final Supplier<@Nullable T> valueSupplier; // keep a reference to the column so we don't lose the type private final SqlColumn localColumn; - private ValueOrNullMapping(SqlColumn column, Supplier valueSupplier) { + private ValueOrNullMapping(SqlColumn column, Supplier<@Nullable T> valueSupplier) { super(column); this.valueSupplier = Objects.requireNonNull(valueSupplier); localColumn = Objects.requireNonNull(column); @@ -42,7 +43,7 @@ public R accept(ColumnMappingVisitor visitor) { return visitor.visit(this); } - public static ValueOrNullMapping of(SqlColumn column, Supplier valueSupplier) { + public static ValueOrNullMapping of(SqlColumn column, Supplier<@Nullable T> valueSupplier) { return new ValueOrNullMapping<>(column, valueSupplier); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/util/ValueWhenPresentMapping.java b/src/main/java/org/mybatis/dynamic/sql/util/ValueWhenPresentMapping.java index eb28e8a81..a9dae6c66 100644 --- a/src/main/java/org/mybatis/dynamic/sql/util/ValueWhenPresentMapping.java +++ b/src/main/java/org/mybatis/dynamic/sql/util/ValueWhenPresentMapping.java @@ -19,15 +19,16 @@ import java.util.Optional; import java.util.function.Supplier; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.SqlColumn; public class ValueWhenPresentMapping extends AbstractColumnMapping { - private final Supplier valueSupplier; + private final Supplier<@Nullable T> valueSupplier; // keep a reference to the column so we don't lose the type private final SqlColumn localColumn; - private ValueWhenPresentMapping(SqlColumn column, Supplier valueSupplier) { + private ValueWhenPresentMapping(SqlColumn column, Supplier<@Nullable T> valueSupplier) { super(column); this.valueSupplier = Objects.requireNonNull(valueSupplier); localColumn = Objects.requireNonNull(column); @@ -37,7 +38,7 @@ public Optional value() { return Optional.ofNullable(valueSupplier.get()).map(this::convert); } - private Object convert(T value) { + private @Nullable Object convert(@Nullable T value) { return localColumn.convertParameterType(value); } @@ -46,7 +47,7 @@ public R accept(ColumnMappingVisitor visitor) { return visitor.visit(this); } - public static ValueWhenPresentMapping of(SqlColumn column, Supplier valueSupplier) { + public static ValueWhenPresentMapping of(SqlColumn column, Supplier<@Nullable T> valueSupplier) { return new ValueWhenPresentMapping<>(column, valueSupplier); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/util/mybatis3/package-info.java b/src/main/java/org/mybatis/dynamic/sql/util/mybatis3/package-info.java new file mode 100644 index 000000000..3eda4b115 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/util/mybatis3/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright 2016-2025 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. + */ +@NullMarked +package org.mybatis.dynamic.sql.util.mybatis3; + +import org.jspecify.annotations.NullMarked; diff --git a/src/main/java/org/mybatis/dynamic/sql/util/package-info.java b/src/main/java/org/mybatis/dynamic/sql/util/package-info.java new file mode 100644 index 000000000..82bcfdd13 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/util/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright 2016-2025 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. + */ +@NullMarked +package org.mybatis.dynamic.sql.util; + +import org.jspecify.annotations.NullMarked; diff --git a/src/main/java/org/mybatis/dynamic/sql/util/spring/package-info.java b/src/main/java/org/mybatis/dynamic/sql/util/spring/package-info.java new file mode 100644 index 000000000..1c53822b8 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/util/spring/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright 2016-2025 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. + */ +@NullMarked +package org.mybatis.dynamic.sql.util.spring; + +import org.jspecify.annotations.NullMarked; diff --git a/src/main/java/org/mybatis/dynamic/sql/util/springbatch/package-info.java b/src/main/java/org/mybatis/dynamic/sql/util/springbatch/package-info.java new file mode 100644 index 000000000..16a66a9fe --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/util/springbatch/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright 2016-2025 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. + */ +@NullMarked +package org.mybatis.dynamic.sql.util.springbatch; + +import org.jspecify.annotations.NullMarked; diff --git a/src/main/java/org/mybatis/dynamic/sql/where/AbstractWhereFinisher.java b/src/main/java/org/mybatis/dynamic/sql/where/AbstractWhereFinisher.java index cf1604307..260fef7ea 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/AbstractWhereFinisher.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/AbstractWhereFinisher.java @@ -19,6 +19,8 @@ import java.util.Objects; import java.util.function.Consumer; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AndOrCriteriaGroup; import org.mybatis.dynamic.sql.SqlCriterion; import org.mybatis.dynamic.sql.common.AbstractBooleanExpressionDSL; @@ -37,11 +39,12 @@ void initialize(SqlCriterion sqlCriterion) { setInitialCriterion(sqlCriterion, StatementType.WHERE); } - void initialize(SqlCriterion sqlCriterion, List subCriteria) { + void initialize(@Nullable SqlCriterion sqlCriterion, List subCriteria) { setInitialCriterion(sqlCriterion, StatementType.WHERE); super.subCriteria.addAll(subCriteria); } + @NonNull @Override public T configureStatement(Consumer consumer) { parentStatement.configureStatement(consumer); diff --git a/src/main/java/org/mybatis/dynamic/sql/where/AbstractWhereStarter.java b/src/main/java/org/mybatis/dynamic/sql/where/AbstractWhereStarter.java index 3070bde18..3a037e5e9 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/AbstractWhereStarter.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/AbstractWhereStarter.java @@ -18,6 +18,7 @@ import java.util.Arrays; import java.util.List; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AndOrCriteriaGroup; import org.mybatis.dynamic.sql.BindableColumn; import org.mybatis.dynamic.sql.ColumnAndConditionCriterion; @@ -69,7 +70,7 @@ default F where(SqlCriterion initialCriterion, AndOrCriteriaGroup... subCriteria return where(initialCriterion, Arrays.asList(subCriteria)); } - default F where(SqlCriterion initialCriterion, List subCriteria) { + default F where(@Nullable SqlCriterion initialCriterion, List subCriteria) { SqlCriterion sqlCriterion = new CriteriaGroup.Builder() .withInitialCriterion(initialCriterion) .withSubCriteria(subCriteria) diff --git a/src/main/java/org/mybatis/dynamic/sql/where/WhereDSL.java b/src/main/java/org/mybatis/dynamic/sql/where/WhereDSL.java index 418ed9fde..6a20b57e8 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/WhereDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/WhereDSL.java @@ -17,7 +17,6 @@ import java.util.function.Consumer; -import org.jetbrains.annotations.NotNull; import org.mybatis.dynamic.sql.configuration.StatementConfiguration; import org.mybatis.dynamic.sql.util.Buildable; @@ -52,7 +51,6 @@ protected StandaloneWhereFinisher getThis() { return this; } - @NotNull @Override public WhereModel build() { return new WhereModel.Builder() diff --git a/src/main/java/org/mybatis/dynamic/sql/where/WhereModel.java b/src/main/java/org/mybatis/dynamic/sql/where/WhereModel.java index 1901d1163..27fed4eed 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/WhereModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/WhereModel.java @@ -18,6 +18,7 @@ import java.util.Objects; import java.util.Optional; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.common.AbstractBooleanExpressionModel; import org.mybatis.dynamic.sql.configuration.StatementConfiguration; import org.mybatis.dynamic.sql.render.RenderingContext; @@ -99,7 +100,7 @@ private WhereClauseProvider toWhereClauseProvider(FragmentAndParameters fragment } public static class Builder extends AbstractBuilder { - private StatementConfiguration statementConfiguration; + private @Nullable StatementConfiguration statementConfiguration; public Builder withStatementConfiguration(StatementConfiguration statementConfiguration) { this.statementConfiguration = statementConfiguration; diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/AndGatherer.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/AndGatherer.java index 6a91f8e88..8a587262a 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/AndGatherer.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/AndGatherer.java @@ -29,20 +29,18 @@ */ public abstract class AndGatherer { protected final T value1; - protected T value2; protected AndGatherer(T value1) { this.value1 = value1; } public R and(T value2) { - this.value2 = value2; - return build(); + return build(value2); } public R and(Supplier valueSupplier2) { return and(valueSupplier2.get()); } - protected abstract R build(); + protected abstract R build(T value2); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/AndWhenPresentGatherer.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/AndWhenPresentGatherer.java new file mode 100644 index 000000000..d4d8f3d7c --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/AndWhenPresentGatherer.java @@ -0,0 +1,49 @@ +/* + * Copyright 2016-2025 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. + */ +package org.mybatis.dynamic.sql.where.condition; + +import java.util.function.Supplier; + +import org.jspecify.annotations.Nullable; + +/** + * Utility class supporting the "and" part of a between when present condition. This class supports builders, + * so it is mutable. + * + * @author Jeff Butler + * + * @param + * the type of field for the between condition + * @param + * the type of condition being built + */ +public abstract class AndWhenPresentGatherer { + protected final @Nullable T value1; + + protected AndWhenPresentGatherer(@Nullable T value1) { + this.value1 = value1; + } + + public R and(@Nullable T value2) { + return build(value2); + } + + public R and(Supplier<@Nullable T> valueSupplier2) { + return and(valueSupplier2.get()); + } + + protected abstract R build(@Nullable T value2); +} diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetween.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetween.java index c252abb09..deeddb4c9 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetween.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetween.java @@ -15,15 +15,26 @@ */ package org.mybatis.dynamic.sql.where.condition; -import java.util.Objects; +import java.util.NoSuchElementException; import java.util.function.BiPredicate; import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractTwoValueCondition; public class IsBetween extends AbstractTwoValueCondition { - private static final IsBetween EMPTY = new IsBetween(null, null) { + private static final IsBetween EMPTY = new IsBetween(-1, -1) { + @Override + public Object value1() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + + @Override + public Object value2() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + @Override public boolean isEmpty() { return true; @@ -91,7 +102,7 @@ public static Builder isBetween(T value1) { return new Builder<>(value1); } - public static WhenPresentBuilder isBetweenWhenPresent(T value1) { + public static WhenPresentBuilder isBetweenWhenPresent(@Nullable T value1) { return new WhenPresentBuilder<>(value1); } @@ -101,19 +112,23 @@ private Builder(T value1) { } @Override - protected IsBetween build() { + protected IsBetween build(T value2) { return new IsBetween<>(value1, value2); } } - public static class WhenPresentBuilder extends AndGatherer> { - private WhenPresentBuilder(T value1) { + public static class WhenPresentBuilder extends AndWhenPresentGatherer> { + private WhenPresentBuilder(@Nullable T value1) { super(value1); } @Override - protected IsBetween build() { - return new IsBetween<>(value1, value2).filter(Objects::nonNull); + protected IsBetween build(@Nullable T value2) { + if (value1 == null || value2 == null) { + return empty(); + } else { + return new IsBetween<>(value1, value2); + } } } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsEqualTo.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsEqualTo.java index 0d1ee2ba0..0a4b19207 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsEqualTo.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsEqualTo.java @@ -15,6 +15,7 @@ */ package org.mybatis.dynamic.sql.where.condition; +import java.util.NoSuchElementException; import java.util.function.Function; import java.util.function.Predicate; @@ -22,7 +23,12 @@ public class IsEqualTo extends AbstractSingleValueCondition { - private static final IsEqualTo EMPTY = new IsEqualTo(null) { + private static final IsEqualTo EMPTY = new IsEqualTo(-1) { + @Override + public Object value() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + @Override public boolean isEmpty() { return true; diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsEqualToWithSubselect.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsEqualToWithSubselect.java index 0c11774be..10bc2c285 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsEqualToWithSubselect.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsEqualToWithSubselect.java @@ -15,7 +15,6 @@ */ package org.mybatis.dynamic.sql.where.condition; -import org.jetbrains.annotations.NotNull; import org.mybatis.dynamic.sql.AbstractSubselectCondition; import org.mybatis.dynamic.sql.select.SelectModel; import org.mybatis.dynamic.sql.util.Buildable; @@ -26,7 +25,6 @@ protected IsEqualToWithSubselect(Buildable selectModelBuilder) { super(selectModelBuilder); } - @NotNull public static IsEqualToWithSubselect of(Buildable selectModelBuilder) { return new IsEqualToWithSubselect<>(selectModelBuilder); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThan.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThan.java index 673042b89..a0ed1a2bc 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThan.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThan.java @@ -15,13 +15,19 @@ */ package org.mybatis.dynamic.sql.where.condition; +import java.util.NoSuchElementException; import java.util.function.Function; import java.util.function.Predicate; import org.mybatis.dynamic.sql.AbstractSingleValueCondition; public class IsGreaterThan extends AbstractSingleValueCondition { - private static final IsGreaterThan EMPTY = new IsGreaterThan(null) { + private static final IsGreaterThan EMPTY = new IsGreaterThan(-1) { + @Override + public Object value() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + @Override public boolean isEmpty() { return true; diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualTo.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualTo.java index 3b1e970c9..59560339b 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualTo.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualTo.java @@ -15,13 +15,19 @@ */ package org.mybatis.dynamic.sql.where.condition; +import java.util.NoSuchElementException; import java.util.function.Function; import java.util.function.Predicate; import org.mybatis.dynamic.sql.AbstractSingleValueCondition; public class IsGreaterThanOrEqualTo extends AbstractSingleValueCondition { - private static final IsGreaterThanOrEqualTo EMPTY = new IsGreaterThanOrEqualTo(null) { + private static final IsGreaterThanOrEqualTo EMPTY = new IsGreaterThanOrEqualTo(-1) { + @Override + public Object value() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + @Override public boolean isEmpty() { return true; diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualToWithSubselect.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualToWithSubselect.java index 7f5e0fb7a..05aea23f2 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualToWithSubselect.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanOrEqualToWithSubselect.java @@ -15,7 +15,6 @@ */ package org.mybatis.dynamic.sql.where.condition; -import org.jetbrains.annotations.NotNull; import org.mybatis.dynamic.sql.AbstractSubselectCondition; import org.mybatis.dynamic.sql.select.SelectModel; import org.mybatis.dynamic.sql.util.Buildable; @@ -26,7 +25,6 @@ protected IsGreaterThanOrEqualToWithSubselect(Buildable selectModel super(selectModelBuilder); } - @NotNull public static IsGreaterThanOrEqualToWithSubselect of(Buildable selectModelBuilder) { return new IsGreaterThanOrEqualToWithSubselect<>(selectModelBuilder); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanWithSubselect.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanWithSubselect.java index 5774fc5ec..225423cbd 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanWithSubselect.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsGreaterThanWithSubselect.java @@ -15,7 +15,6 @@ */ package org.mybatis.dynamic.sql.where.condition; -import org.jetbrains.annotations.NotNull; import org.mybatis.dynamic.sql.AbstractSubselectCondition; import org.mybatis.dynamic.sql.select.SelectModel; import org.mybatis.dynamic.sql.util.Buildable; @@ -26,7 +25,6 @@ protected IsGreaterThanWithSubselect(Buildable selectModelBuilder) super(selectModelBuilder); } - @NotNull public static IsGreaterThanWithSubselect of(Buildable selectModelBuilder) { return new IsGreaterThanWithSubselect<>(selectModelBuilder); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java index 80ad63b44..6f14406fa 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java @@ -70,6 +70,8 @@ public static IsInCaseInsensitive of(String... values) { } public static IsInCaseInsensitive of(Collection values) { + // Keep the null safe upper case utility for backwards compatibility + //noinspection DataFlowIssue return new IsInCaseInsensitive(values).map(StringUtilities::safelyUpperCase); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java index c65062323..d366f0857 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitiveWhenPresent.java @@ -18,12 +18,13 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.Objects; import java.util.function.Predicate; import java.util.function.UnaryOperator; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractListValueCondition; import org.mybatis.dynamic.sql.util.StringUtilities; +import org.mybatis.dynamic.sql.util.Utilities; public class IsInCaseInsensitiveWhenPresent extends AbstractListValueCondition implements CaseInsensitiveVisitableCondition { @@ -34,8 +35,8 @@ public static IsInCaseInsensitiveWhenPresent empty() { return EMPTY; } - protected IsInCaseInsensitiveWhenPresent(Collection values) { - super(values.stream().filter(Objects::nonNull).toList()); + protected IsInCaseInsensitiveWhenPresent(Collection<@Nullable String> values) { + super(Utilities.removeNullElements(values)); } @Override @@ -60,11 +61,13 @@ public IsInCaseInsensitiveWhenPresent map(UnaryOperator mapper) { return mapSupport(mapper, IsInCaseInsensitiveWhenPresent::new, IsInCaseInsensitiveWhenPresent::empty); } - public static IsInCaseInsensitiveWhenPresent of(String... values) { + public static IsInCaseInsensitiveWhenPresent of(@Nullable String... values) { return of(Arrays.asList(values)); } - public static IsInCaseInsensitiveWhenPresent of(Collection values) { + public static IsInCaseInsensitiveWhenPresent of(Collection<@Nullable String> values) { + // Keep the null safe upper case utility for backwards compatibility + //noinspection DataFlowIssue return new IsInCaseInsensitiveWhenPresent(values).map(StringUtilities::safelyUpperCase); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInWhenPresent.java index 458bab590..ea1bfe509 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInWhenPresent.java @@ -22,6 +22,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractListValueCondition; public class IsInWhenPresent extends AbstractListValueCondition { @@ -61,11 +62,11 @@ public IsInWhenPresent map(Function mapper) { } @SafeVarargs - public static IsInWhenPresent of(T... values) { + public static IsInWhenPresent of(@Nullable T... values) { return of(Arrays.asList(values)); } - public static IsInWhenPresent of(Collection values) { + public static IsInWhenPresent of(Collection<@Nullable T> values) { return new IsInWhenPresent<>(values); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInWithSubselect.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInWithSubselect.java index 60b936305..771e2637b 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInWithSubselect.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInWithSubselect.java @@ -15,7 +15,6 @@ */ package org.mybatis.dynamic.sql.where.condition; -import org.jetbrains.annotations.NotNull; import org.mybatis.dynamic.sql.AbstractSubselectCondition; import org.mybatis.dynamic.sql.select.SelectModel; import org.mybatis.dynamic.sql.util.Buildable; @@ -26,7 +25,6 @@ protected IsInWithSubselect(Buildable selectModelBuilder) { super(selectModelBuilder); } - @NotNull public static IsInWithSubselect of(Buildable selectModelBuilder) { return new IsInWithSubselect<>(selectModelBuilder); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThan.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThan.java index 764e92c1c..09e2e7ba6 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThan.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThan.java @@ -15,13 +15,19 @@ */ package org.mybatis.dynamic.sql.where.condition; +import java.util.NoSuchElementException; import java.util.function.Function; import java.util.function.Predicate; import org.mybatis.dynamic.sql.AbstractSingleValueCondition; public class IsLessThan extends AbstractSingleValueCondition { - private static final IsLessThan EMPTY = new IsLessThan(null) { + private static final IsLessThan EMPTY = new IsLessThan(-1) { + @Override + public Object value() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + @Override public boolean isEmpty() { return true; diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanOrEqualTo.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanOrEqualTo.java index a853838c3..b11d06c88 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanOrEqualTo.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanOrEqualTo.java @@ -15,13 +15,19 @@ */ package org.mybatis.dynamic.sql.where.condition; +import java.util.NoSuchElementException; import java.util.function.Function; import java.util.function.Predicate; import org.mybatis.dynamic.sql.AbstractSingleValueCondition; public class IsLessThanOrEqualTo extends AbstractSingleValueCondition { - private static final IsLessThanOrEqualTo EMPTY = new IsLessThanOrEqualTo(null) { + private static final IsLessThanOrEqualTo EMPTY = new IsLessThanOrEqualTo(-1) { + @Override + public Object value() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + @Override public boolean isEmpty() { return true; diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanOrEqualToWithSubselect.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanOrEqualToWithSubselect.java index 58895b8bc..7a7769016 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanOrEqualToWithSubselect.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanOrEqualToWithSubselect.java @@ -15,7 +15,6 @@ */ package org.mybatis.dynamic.sql.where.condition; -import org.jetbrains.annotations.NotNull; import org.mybatis.dynamic.sql.AbstractSubselectCondition; import org.mybatis.dynamic.sql.select.SelectModel; import org.mybatis.dynamic.sql.util.Buildable; @@ -26,7 +25,6 @@ protected IsLessThanOrEqualToWithSubselect(Buildable selectModelBui super(selectModelBuilder); } - @NotNull public static IsLessThanOrEqualToWithSubselect of(Buildable selectModelBuilder) { return new IsLessThanOrEqualToWithSubselect<>(selectModelBuilder); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanWithSubselect.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanWithSubselect.java index efc62b982..91a2765a4 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanWithSubselect.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLessThanWithSubselect.java @@ -15,7 +15,6 @@ */ package org.mybatis.dynamic.sql.where.condition; -import org.jetbrains.annotations.NotNull; import org.mybatis.dynamic.sql.AbstractSubselectCondition; import org.mybatis.dynamic.sql.select.SelectModel; import org.mybatis.dynamic.sql.util.Buildable; @@ -26,7 +25,6 @@ protected IsLessThanWithSubselect(Buildable selectModelBuilder) { super(selectModelBuilder); } - @NotNull public static IsLessThanWithSubselect of(Buildable selectModelBuilder) { return new IsLessThanWithSubselect<>(selectModelBuilder); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLike.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLike.java index 233485ff4..9d79bed81 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLike.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLike.java @@ -15,13 +15,19 @@ */ package org.mybatis.dynamic.sql.where.condition; +import java.util.NoSuchElementException; import java.util.function.Function; import java.util.function.Predicate; import org.mybatis.dynamic.sql.AbstractSingleValueCondition; public class IsLike extends AbstractSingleValueCondition { - private static final IsLike EMPTY = new IsLike(null) { + private static final IsLike EMPTY = new IsLike(-1) { + @Override + public Object value() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + @Override public boolean isEmpty() { return true; diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java index 430eb41df..ccf6699ee 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsLikeCaseInsensitive.java @@ -15,6 +15,7 @@ */ package org.mybatis.dynamic.sql.where.condition; +import java.util.NoSuchElementException; import java.util.function.Predicate; import java.util.function.UnaryOperator; @@ -23,7 +24,12 @@ public class IsLikeCaseInsensitive extends AbstractSingleValueCondition implements CaseInsensitiveVisitableCondition { - private static final IsLikeCaseInsensitive EMPTY = new IsLikeCaseInsensitive(null) { + private static final IsLikeCaseInsensitive EMPTY = new IsLikeCaseInsensitive("") { //$NON-NLS-1$ + @Override + public String value() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + @Override public boolean isEmpty() { return true; @@ -61,6 +67,8 @@ public IsLikeCaseInsensitive map(UnaryOperator mapper) { } public static IsLikeCaseInsensitive of(String value) { + // Keep the null safe upper case utility for backwards compatibility + //noinspection DataFlowIssue return new IsLikeCaseInsensitive(value).map(StringUtilities::safelyUpperCase); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetween.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetween.java index b449571bb..5700de2ac 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetween.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetween.java @@ -15,15 +15,26 @@ */ package org.mybatis.dynamic.sql.where.condition; -import java.util.Objects; +import java.util.NoSuchElementException; import java.util.function.BiPredicate; import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractTwoValueCondition; public class IsNotBetween extends AbstractTwoValueCondition { - private static final IsNotBetween EMPTY = new IsNotBetween(null, null) { + private static final IsNotBetween EMPTY = new IsNotBetween(-1, -1) { + @Override + public Object value1() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + + @Override + public Object value2() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + @Override public boolean isEmpty() { return true; @@ -92,7 +103,7 @@ public static Builder isNotBetween(T value1) { return new Builder<>(value1); } - public static WhenPresentBuilder isNotBetweenWhenPresent(T value1) { + public static WhenPresentBuilder isNotBetweenWhenPresent(@Nullable T value1) { return new WhenPresentBuilder<>(value1); } @@ -103,20 +114,24 @@ private Builder(T value1) { } @Override - protected IsNotBetween build() { + protected IsNotBetween build(T value2) { return new IsNotBetween<>(value1, value2); } } - public static class WhenPresentBuilder extends AndGatherer> { + public static class WhenPresentBuilder extends AndWhenPresentGatherer> { - private WhenPresentBuilder(T value1) { + private WhenPresentBuilder(@Nullable T value1) { super(value1); } @Override - protected IsNotBetween build() { - return new IsNotBetween<>(value1, value2).filter(Objects::nonNull); + protected IsNotBetween build(@Nullable T value2) { + if (value1 == null || value2 == null) { + return empty(); + } else { + return new IsNotBetween<>(value1, value2); + } } } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotEqualTo.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotEqualTo.java index 6af567f9d..821fd019f 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotEqualTo.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotEqualTo.java @@ -15,13 +15,19 @@ */ package org.mybatis.dynamic.sql.where.condition; +import java.util.NoSuchElementException; import java.util.function.Function; import java.util.function.Predicate; import org.mybatis.dynamic.sql.AbstractSingleValueCondition; public class IsNotEqualTo extends AbstractSingleValueCondition { - private static final IsNotEqualTo EMPTY = new IsNotEqualTo(null) { + private static final IsNotEqualTo EMPTY = new IsNotEqualTo(-1) { + @Override + public Object value() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + @Override public boolean isEmpty() { return true; diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotEqualToWithSubselect.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotEqualToWithSubselect.java index f9651646d..2e19d9a19 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotEqualToWithSubselect.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotEqualToWithSubselect.java @@ -15,7 +15,6 @@ */ package org.mybatis.dynamic.sql.where.condition; -import org.jetbrains.annotations.NotNull; import org.mybatis.dynamic.sql.AbstractSubselectCondition; import org.mybatis.dynamic.sql.select.SelectModel; import org.mybatis.dynamic.sql.util.Buildable; @@ -26,7 +25,6 @@ protected IsNotEqualToWithSubselect(Buildable selectModelBuilder) { super(selectModelBuilder); } - @NotNull public static IsNotEqualToWithSubselect of(Buildable selectModelBuilder) { return new IsNotEqualToWithSubselect<>(selectModelBuilder); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java index 2045c8096..b4c1e96a7 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java @@ -70,6 +70,8 @@ public static IsNotInCaseInsensitive of(String... values) { } public static IsNotInCaseInsensitive of(Collection values) { + // Keep the null safe upper case utility for backwards compatibility + //noinspection DataFlowIssue return new IsNotInCaseInsensitive(values).map(StringUtilities::safelyUpperCase); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java index 65a1311e8..5562b0ff4 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitiveWhenPresent.java @@ -18,12 +18,13 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.Objects; import java.util.function.Predicate; import java.util.function.UnaryOperator; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractListValueCondition; import org.mybatis.dynamic.sql.util.StringUtilities; +import org.mybatis.dynamic.sql.util.Utilities; public class IsNotInCaseInsensitiveWhenPresent extends AbstractListValueCondition implements CaseInsensitiveVisitableCondition { @@ -34,8 +35,8 @@ public static IsNotInCaseInsensitiveWhenPresent empty() { return EMPTY; } - protected IsNotInCaseInsensitiveWhenPresent(Collection values) { - super(values.stream().filter(Objects::nonNull).toList()); + protected IsNotInCaseInsensitiveWhenPresent(Collection<@Nullable String> values) { + super(Utilities.removeNullElements(values)); } @Override @@ -60,11 +61,13 @@ public IsNotInCaseInsensitiveWhenPresent map(UnaryOperator mapper) { return mapSupport(mapper, IsNotInCaseInsensitiveWhenPresent::new, IsNotInCaseInsensitiveWhenPresent::empty); } - public static IsNotInCaseInsensitiveWhenPresent of(String... values) { + public static IsNotInCaseInsensitiveWhenPresent of(@Nullable String... values) { return of(Arrays.asList(values)); } - public static IsNotInCaseInsensitiveWhenPresent of(Collection values) { + public static IsNotInCaseInsensitiveWhenPresent of(Collection<@Nullable String> values) { + // Keep the null safe upper case utility for backwards compatibility + //noinspection DataFlowIssue return new IsNotInCaseInsensitiveWhenPresent(values).map(StringUtilities::safelyUpperCase); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInWithSubselect.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInWithSubselect.java index 0892afd96..f6f3764f1 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInWithSubselect.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInWithSubselect.java @@ -15,7 +15,6 @@ */ package org.mybatis.dynamic.sql.where.condition; -import org.jetbrains.annotations.NotNull; import org.mybatis.dynamic.sql.AbstractSubselectCondition; import org.mybatis.dynamic.sql.select.SelectModel; import org.mybatis.dynamic.sql.util.Buildable; @@ -26,7 +25,6 @@ protected IsNotInWithSubselect(Buildable selectModelBuilder) { super(selectModelBuilder); } - @NotNull public static IsNotInWithSubselect of(Buildable selectModelBuilder) { return new IsNotInWithSubselect<>(selectModelBuilder); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLike.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLike.java index f1b6c6ee6..7379a316b 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLike.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLike.java @@ -15,13 +15,19 @@ */ package org.mybatis.dynamic.sql.where.condition; +import java.util.NoSuchElementException; import java.util.function.Function; import java.util.function.Predicate; import org.mybatis.dynamic.sql.AbstractSingleValueCondition; public class IsNotLike extends AbstractSingleValueCondition { - private static final IsNotLike EMPTY = new IsNotLike(null) { + private static final IsNotLike EMPTY = new IsNotLike(-1) { + @Override + public Object value() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + @Override public boolean isEmpty() { return true; diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java index b2ba76951..5d9d8c3af 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotLikeCaseInsensitive.java @@ -15,6 +15,7 @@ */ package org.mybatis.dynamic.sql.where.condition; +import java.util.NoSuchElementException; import java.util.function.Predicate; import java.util.function.UnaryOperator; @@ -23,7 +24,12 @@ public class IsNotLikeCaseInsensitive extends AbstractSingleValueCondition implements CaseInsensitiveVisitableCondition { - private static final IsNotLikeCaseInsensitive EMPTY = new IsNotLikeCaseInsensitive(null) { + private static final IsNotLikeCaseInsensitive EMPTY = new IsNotLikeCaseInsensitive("") { //$NON-NLS-1$ + @Override + public String value() { + throw new NoSuchElementException("No value present"); //$NON-NLS-1$ + } + @Override public boolean isEmpty() { return true; @@ -63,6 +69,8 @@ public IsNotLikeCaseInsensitive map(UnaryOperator mapper) { } public static IsNotLikeCaseInsensitive of(String value) { + // Keep the null safe upper case utility for backwards compatibility + //noinspection DataFlowIssue return new IsNotLikeCaseInsensitive(value).map(StringUtilities::safelyUpperCase); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotNull.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotNull.java index d4e4cf56a..03d558387 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotNull.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotNull.java @@ -20,7 +20,7 @@ import org.mybatis.dynamic.sql.AbstractNoValueCondition; public class IsNotNull extends AbstractNoValueCondition { - private static final IsNotNull EMPTY = new IsNotNull() { + private static final IsNotNull EMPTY = new IsNotNull<>() { @Override public boolean isEmpty() { return true; diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNull.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNull.java index eae093f10..36c68aa34 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNull.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNull.java @@ -20,7 +20,7 @@ import org.mybatis.dynamic.sql.AbstractNoValueCondition; public class IsNull extends AbstractNoValueCondition { - private static final IsNull EMPTY = new IsNull() { + private static final IsNull EMPTY = new IsNull<>() { @Override public boolean isEmpty() { return true; diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/package-info.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/package-info.java new file mode 100644 index 000000000..3457063de --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright 2016-2025 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. + */ +@NullMarked +package org.mybatis.dynamic.sql.where.condition; + +import org.jspecify.annotations.NullMarked; diff --git a/src/main/java/org/mybatis/dynamic/sql/where/package-info.java b/src/main/java/org/mybatis/dynamic/sql/where/package-info.java new file mode 100644 index 000000000..194b40e86 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright 2016-2025 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. + */ +@NullMarked +package org.mybatis.dynamic.sql.where; + +import org.jspecify.annotations.NullMarked; diff --git a/src/main/java/org/mybatis/dynamic/sql/where/render/ColumnAndConditionRenderer.java b/src/main/java/org/mybatis/dynamic/sql/where/render/ColumnAndConditionRenderer.java index 879c4f54d..73f456981 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/render/ColumnAndConditionRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/render/ColumnAndConditionRenderer.java @@ -19,6 +19,7 @@ import java.util.Objects; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.BindableColumn; import org.mybatis.dynamic.sql.VisitableCondition; import org.mybatis.dynamic.sql.render.RenderingContext; @@ -56,9 +57,9 @@ public FragmentAndParameters render() { } public static class Builder { - private BindableColumn column; - private VisitableCondition condition; - private RenderingContext renderingContext; + private @Nullable BindableColumn column; + private @Nullable VisitableCondition condition; + private @Nullable RenderingContext renderingContext; public Builder withColumn(BindableColumn column) { this.column = column; diff --git a/src/main/java/org/mybatis/dynamic/sql/where/render/DefaultConditionVisitor.java b/src/main/java/org/mybatis/dynamic/sql/where/render/DefaultConditionVisitor.java index 3b2852f31..6a3fb038d 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/render/DefaultConditionVisitor.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/render/DefaultConditionVisitor.java @@ -20,6 +20,7 @@ import java.util.Objects; import java.util.stream.Collectors; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.AbstractColumnComparisonCondition; import org.mybatis.dynamic.sql.AbstractListValueCondition; import org.mybatis.dynamic.sql.AbstractNoValueCondition; @@ -109,7 +110,7 @@ public FragmentAndParameters visit(AbstractColumnComparisonCondition conditio .mapFragment(f -> condition.operator() + spaceBefore(f)); } - private Object convertValue(T value) { + private @Nullable Object convertValue(T value) { return column.convertParameterType(value); } @@ -125,8 +126,8 @@ public static Builder withColumn(BindableColumn column) { } public static class Builder { - private BindableColumn column; - private RenderingContext renderingContext; + private @Nullable BindableColumn column; + private @Nullable RenderingContext renderingContext; public Builder withColumn(BindableColumn column) { this.column = column; diff --git a/src/main/java/org/mybatis/dynamic/sql/where/render/DefaultWhereClauseProvider.java b/src/main/java/org/mybatis/dynamic/sql/where/render/DefaultWhereClauseProvider.java index fa8968c16..5a10f77d7 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/render/DefaultWhereClauseProvider.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/render/DefaultWhereClauseProvider.java @@ -19,6 +19,8 @@ import java.util.Map; import java.util.Objects; +import org.jspecify.annotations.Nullable; + public class DefaultWhereClauseProvider implements WhereClauseProvider { private final String whereClause; private final Map parameters; @@ -43,7 +45,7 @@ public static Builder withWhereClause(String whereClause) { } public static class Builder { - private String whereClause; + private @Nullable String whereClause; private final Map parameters = new HashMap<>(); public Builder withWhereClause(String whereClause) { diff --git a/src/main/java/org/mybatis/dynamic/sql/where/render/RenderedCriterion.java b/src/main/java/org/mybatis/dynamic/sql/where/render/RenderedCriterion.java index 690b72eae..1c6b54f27 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/render/RenderedCriterion.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/render/RenderedCriterion.java @@ -19,10 +19,11 @@ import java.util.Objects; +import org.jspecify.annotations.Nullable; import org.mybatis.dynamic.sql.util.FragmentAndParameters; public class RenderedCriterion { - private final String connector; + private final @Nullable String connector; private final FragmentAndParameters fragmentAndParameters; private RenderedCriterion(Builder builder) { @@ -54,8 +55,8 @@ private FragmentAndParameters prependFragment(FragmentAndParameters fragmentAndP } public static class Builder { - private String connector; - private FragmentAndParameters fragmentAndParameters; + private @Nullable String connector; + private @Nullable FragmentAndParameters fragmentAndParameters; public Builder withConnector(String connector) { this.connector = connector; diff --git a/src/main/java/org/mybatis/dynamic/sql/where/render/package-info.java b/src/main/java/org/mybatis/dynamic/sql/where/render/package-info.java new file mode 100644 index 000000000..cde1387a3 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/where/render/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright 2016-2025 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. + */ +@NullMarked +package org.mybatis.dynamic.sql.where.render; + +import org.jspecify.annotations.NullMarked; diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/GroupingCriteriaCollector.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/GroupingCriteriaCollector.kt index 32e78b5ff..841539eeb 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/GroupingCriteriaCollector.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/GroupingCriteriaCollector.kt @@ -229,7 +229,7 @@ open class GroupingCriteriaCollector : SubCriteriaCollector() { * * @param condition the condition to be applied to this column, in this scope */ - operator fun BindableColumn.invoke(condition: VisitableCondition) { + operator fun BindableColumn.invoke(condition: VisitableCondition) { initialCriterion = ColumnAndConditionCriterion.withColumn(this) .withCondition(condition) .build() @@ -243,7 +243,7 @@ open class GroupingCriteriaCollector : SubCriteriaCollector() { fun BindableColumn<*>.isNotNull() = invoke(org.mybatis.dynamic.sql.util.kotlin.elements.isNotNull()) - infix fun BindableColumn.isEqualTo(value: T & Any) = + infix fun BindableColumn.isEqualTo(value: T) = invoke(org.mybatis.dynamic.sql.util.kotlin.elements.isEqualTo(value)) infix fun BindableColumn<*>.isEqualTo(subQuery: KotlinSubQueryBuilder.() -> Unit) = @@ -252,10 +252,10 @@ open class GroupingCriteriaCollector : SubCriteriaCollector() { infix fun BindableColumn<*>.isEqualTo(column: BasicColumn) = invoke(org.mybatis.dynamic.sql.util.kotlin.elements.isEqualTo(column)) - infix fun BindableColumn.isEqualToWhenPresent(value: T?) = + infix fun BindableColumn.isEqualToWhenPresent(value: T?) = invoke(org.mybatis.dynamic.sql.util.kotlin.elements.isEqualToWhenPresent(value)) - infix fun BindableColumn.isNotEqualTo(value: T & Any) = + infix fun BindableColumn.isNotEqualTo(value: T) = invoke(org.mybatis.dynamic.sql.util.kotlin.elements.isNotEqualTo(value)) infix fun BindableColumn<*>.isNotEqualTo(subQuery: KotlinSubQueryBuilder.() -> Unit) = @@ -264,10 +264,10 @@ open class GroupingCriteriaCollector : SubCriteriaCollector() { infix fun BindableColumn<*>.isNotEqualTo(column: BasicColumn) = invoke(org.mybatis.dynamic.sql.util.kotlin.elements.isNotEqualTo(column)) - infix fun BindableColumn.isNotEqualToWhenPresent(value: T?) = + infix fun BindableColumn.isNotEqualToWhenPresent(value: T?) = invoke(org.mybatis.dynamic.sql.util.kotlin.elements.isNotEqualToWhenPresent(value)) - infix fun BindableColumn.isGreaterThan(value: T & Any) = + infix fun BindableColumn.isGreaterThan(value: T) = invoke(org.mybatis.dynamic.sql.util.kotlin.elements.isGreaterThan(value)) infix fun BindableColumn<*>.isGreaterThan(subQuery: KotlinSubQueryBuilder.() -> Unit) = @@ -276,10 +276,10 @@ open class GroupingCriteriaCollector : SubCriteriaCollector() { infix fun BindableColumn<*>.isGreaterThan(column: BasicColumn) = invoke(org.mybatis.dynamic.sql.util.kotlin.elements.isGreaterThan(column)) - infix fun BindableColumn.isGreaterThanWhenPresent(value: T?) = + infix fun BindableColumn.isGreaterThanWhenPresent(value: T?) = invoke(org.mybatis.dynamic.sql.util.kotlin.elements.isGreaterThanWhenPresent(value)) - infix fun BindableColumn.isGreaterThanOrEqualTo(value: T & Any) = + infix fun BindableColumn.isGreaterThanOrEqualTo(value: T) = invoke(org.mybatis.dynamic.sql.util.kotlin.elements.isGreaterThanOrEqualTo(value)) infix fun BindableColumn<*>.isGreaterThanOrEqualTo(subQuery: KotlinSubQueryBuilder.() -> Unit) = @@ -288,10 +288,10 @@ open class GroupingCriteriaCollector : SubCriteriaCollector() { infix fun BindableColumn<*>.isGreaterThanOrEqualTo(column: BasicColumn) = invoke(org.mybatis.dynamic.sql.util.kotlin.elements.isGreaterThanOrEqualTo(column)) - infix fun BindableColumn.isGreaterThanOrEqualToWhenPresent(value: T?) = + infix fun BindableColumn.isGreaterThanOrEqualToWhenPresent(value: T?) = invoke(org.mybatis.dynamic.sql.util.kotlin.elements.isGreaterThanOrEqualToWhenPresent(value)) - infix fun BindableColumn.isLessThan(value: T & Any) = + infix fun BindableColumn.isLessThan(value: T) = invoke(org.mybatis.dynamic.sql.util.kotlin.elements.isLessThan(value)) infix fun BindableColumn<*>.isLessThan(subQuery: KotlinSubQueryBuilder.() -> Unit) = @@ -300,10 +300,10 @@ open class GroupingCriteriaCollector : SubCriteriaCollector() { infix fun BindableColumn<*>.isLessThan(column: BasicColumn) = invoke(org.mybatis.dynamic.sql.util.kotlin.elements.isLessThan(column)) - infix fun BindableColumn.isLessThanWhenPresent(value: T?) = + infix fun BindableColumn.isLessThanWhenPresent(value: T?) = invoke(org.mybatis.dynamic.sql.util.kotlin.elements.isLessThanWhenPresent(value)) - infix fun BindableColumn.isLessThanOrEqualTo(value: T & Any) = + infix fun BindableColumn.isLessThanOrEqualTo(value: T) = invoke(org.mybatis.dynamic.sql.util.kotlin.elements.isLessThanOrEqualTo(value)) infix fun BindableColumn<*>.isLessThanOrEqualTo(subQuery: KotlinSubQueryBuilder.() -> Unit) = @@ -312,82 +312,82 @@ open class GroupingCriteriaCollector : SubCriteriaCollector() { infix fun BindableColumn<*>.isLessThanOrEqualTo(column: BasicColumn) = invoke(org.mybatis.dynamic.sql.util.kotlin.elements.isLessThanOrEqualTo(column)) - infix fun BindableColumn.isLessThanOrEqualToWhenPresent(value: T?) = + infix fun BindableColumn.isLessThanOrEqualToWhenPresent(value: T?) = invoke(org.mybatis.dynamic.sql.util.kotlin.elements.isLessThanOrEqualToWhenPresent(value)) - fun BindableColumn.isIn(vararg values: T & Any) = isIn(values.asList()) + fun BindableColumn.isIn(vararg values: T) = isIn(values.asList()) @JvmName("isInArray") - infix fun BindableColumn.isIn(values: Array) = + infix fun BindableColumn.isIn(values: Array) = invoke(org.mybatis.dynamic.sql.util.kotlin.elements.isIn(values)) - infix fun BindableColumn.isIn(values: Collection) = + infix fun BindableColumn.isIn(values: Collection) = invoke(org.mybatis.dynamic.sql.util.kotlin.elements.isIn(values)) infix fun BindableColumn<*>.isIn(subQuery: KotlinSubQueryBuilder.() -> Unit) = invoke(org.mybatis.dynamic.sql.util.kotlin.elements.isIn(subQuery)) - fun BindableColumn.isInWhenPresent(vararg values: T?) = isInWhenPresent(values.asList()) + fun BindableColumn.isInWhenPresent(vararg values: T?) = isInWhenPresent(values.asList()) @JvmName("isInArrayWhenPresent") - infix fun BindableColumn.isInWhenPresent(values: Array?) = + infix fun BindableColumn.isInWhenPresent(values: Array?) = invoke(org.mybatis.dynamic.sql.util.kotlin.elements.isInWhenPresent(values)) - infix fun BindableColumn.isInWhenPresent(values: Collection?) = + infix fun BindableColumn.isInWhenPresent(values: Collection?) = invoke(org.mybatis.dynamic.sql.util.kotlin.elements.isInWhenPresent(values)) - fun BindableColumn.isNotIn(vararg values: T & Any) = isNotIn(values.asList()) + fun BindableColumn.isNotIn(vararg values: T) = isNotIn(values.asList()) @JvmName("isNotInArray") - infix fun BindableColumn.isNotIn(values: Array) = + infix fun BindableColumn.isNotIn(values: Array) = invoke(org.mybatis.dynamic.sql.util.kotlin.elements.isNotIn(values)) - infix fun BindableColumn.isNotIn(values: Collection) = + infix fun BindableColumn.isNotIn(values: Collection) = invoke(org.mybatis.dynamic.sql.util.kotlin.elements.isNotIn(values)) infix fun BindableColumn<*>.isNotIn(subQuery: KotlinSubQueryBuilder.() -> Unit) = invoke(org.mybatis.dynamic.sql.util.kotlin.elements.isNotIn(subQuery)) - fun BindableColumn.isNotInWhenPresent(vararg values: T?) = isNotInWhenPresent(values.asList()) + fun BindableColumn.isNotInWhenPresent(vararg values: T?) = isNotInWhenPresent(values.asList()) @JvmName("isNotInArrayWhenPresent") - infix fun BindableColumn.isNotInWhenPresent(values: Array?) = + infix fun BindableColumn.isNotInWhenPresent(values: Array?) = invoke(org.mybatis.dynamic.sql.util.kotlin.elements.isNotInWhenPresent(values)) - infix fun BindableColumn.isNotInWhenPresent(values: Collection?) = + infix fun BindableColumn.isNotInWhenPresent(values: Collection?) = invoke(org.mybatis.dynamic.sql.util.kotlin.elements.isNotInWhenPresent(values)) - infix fun BindableColumn.isBetween(value1: T & Any) = - SecondValueCollector { + infix fun BindableColumn.isBetween(value1: T) = + SecondValueCollector { invoke(org.mybatis.dynamic.sql.util.kotlin.elements.isBetween(value1).and(it)) } - infix fun BindableColumn.isBetweenWhenPresent(value1: T?) = + infix fun BindableColumn.isBetweenWhenPresent(value1: T?) = NullableSecondValueCollector { invoke(org.mybatis.dynamic.sql.util.kotlin.elements.isBetweenWhenPresent(value1).and(it)) } - infix fun BindableColumn.isNotBetween(value1: T & Any) = - SecondValueCollector { + infix fun BindableColumn.isNotBetween(value1: T) = + SecondValueCollector { invoke(org.mybatis.dynamic.sql.util.kotlin.elements.isNotBetween(value1).and(it)) } - infix fun BindableColumn.isNotBetweenWhenPresent(value1: T?) = + infix fun BindableColumn.isNotBetweenWhenPresent(value1: T?) = NullableSecondValueCollector { invoke(org.mybatis.dynamic.sql.util.kotlin.elements.isNotBetweenWhenPresent(value1).and(it)) } // for string columns, but generic for columns with type handlers - infix fun BindableColumn.isLike(value: T & Any) = + infix fun BindableColumn.isLike(value: T) = invoke(org.mybatis.dynamic.sql.util.kotlin.elements.isLike(value)) - infix fun BindableColumn.isLikeWhenPresent(value: T?) = + infix fun BindableColumn.isLikeWhenPresent(value: T?) = invoke(org.mybatis.dynamic.sql.util.kotlin.elements.isLikeWhenPresent(value)) - infix fun BindableColumn.isNotLike(value: T & Any) = + infix fun BindableColumn.isNotLike(value: T) = invoke(org.mybatis.dynamic.sql.util.kotlin.elements.isNotLike(value)) - infix fun BindableColumn.isNotLikeWhenPresent(value: T?) = + infix fun BindableColumn.isNotLikeWhenPresent(value: T?) = invoke(org.mybatis.dynamic.sql.util.kotlin.elements.isNotLikeWhenPresent(value)) // shortcuts for booleans diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/JoinCollector.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/JoinCollector.kt index e724e3146..f85927682 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/JoinCollector.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/JoinCollector.kt @@ -28,17 +28,17 @@ class JoinCollector { internal fun initialCriterion() = invalidIfNull(criteriaCollector.initialCriterion, "ERROR.22") //$NON-NLS-1$ internal fun subCriteria() = criteriaCollector.subCriteria - fun on(leftColumn: BindableColumn): RightColumnCollector = RightColumnCollector { + fun on(leftColumn: BindableColumn): RightColumnCollector = RightColumnCollector { assertNull(criteriaCollector.initialCriterion, "ERROR.45") //$NON-NLS-1$ criteriaCollector.apply { leftColumn.invoke(it) } } - fun and(leftColumn: BindableColumn): RightColumnCollector = RightColumnCollector { + fun and(leftColumn: BindableColumn): RightColumnCollector = RightColumnCollector { criteriaCollector.and { leftColumn.invoke(it) } } } -class RightColumnCollector(private val joinConditionConsumer: (VisitableCondition) -> Unit) { +class RightColumnCollector(private val joinConditionConsumer: (VisitableCondition) -> Unit) { infix fun equalTo(rightColumn: BindableColumn) = joinConditionConsumer.invoke(SqlBuilder.isEqualTo(rightColumn)) infix fun equalTo(value: T) = joinConditionConsumer.invoke(SqlBuilder.isEqualTo(value)) diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBatchInsertBuilder.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBatchInsertBuilder.kt index 2d2d798c7..aa2dd3703 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBatchInsertBuilder.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBatchInsertBuilder.kt @@ -33,7 +33,7 @@ class KotlinBatchInsertBuilder (private val rows: Collection): Build this.table = table } - fun map(column: SqlColumn) = MultiRowInsertColumnMapCompleter(column) { + fun map(column: SqlColumn) = MultiRowInsertColumnMapCompleter(column) { columnMappings.add(it) } @@ -41,7 +41,7 @@ class KotlinBatchInsertBuilder (private val rows: Collection): Build assertNotNull(table, "ERROR.23") //$NON-NLS-1$ return with(BatchInsertDSL.Builder()) { withRecords(rows) - withTable(table) + withTable(table!!) withColumnMappings(columnMappings) build() }.build() diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinGeneralInsertBuilder.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinGeneralInsertBuilder.kt index 296d7aa28..413ddcac4 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinGeneralInsertBuilder.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinGeneralInsertBuilder.kt @@ -29,7 +29,7 @@ class KotlinGeneralInsertBuilder(private val table: SqlTable) : Buildable() - fun set(column: SqlColumn) = GeneralInsertColumnSetCompleter(column) { + fun set(column: SqlColumn) = GeneralInsertColumnSetCompleter(column) { columnMappings.add(it) } diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinInsertBuilder.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinInsertBuilder.kt index e161b5c6e..8b76231f7 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinInsertBuilder.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinInsertBuilder.kt @@ -33,7 +33,7 @@ class KotlinInsertBuilder (private val row: T): Buildable map(column: SqlColumn) = SingleRowInsertColumnMapCompleter(column) { + fun map(column: SqlColumn) = SingleRowInsertColumnMapCompleter(column) { columnMappings.add(it) } @@ -41,7 +41,7 @@ class KotlinInsertBuilder (private val row: T): Buildable()) { withRow(row) - withTable(table) + withTable(table!!) withColumnMappings(columnMappings) build() }.build() diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinInsertColumnMapCompleters.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinInsertColumnMapCompleters.kt index ab49f086a..076001b9e 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinInsertColumnMapCompleters.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinInsertColumnMapCompleters.kt @@ -28,7 +28,7 @@ import org.mybatis.dynamic.sql.util.ValueOrNullMapping import org.mybatis.dynamic.sql.util.ValueWhenPresentMapping @MyBatisDslMarker -sealed class AbstractInsertColumnMapCompleter( +sealed class AbstractInsertColumnMapCompleter( internal val column: SqlColumn, internal val mappingConsumer: (AbstractColumnMapping) -> Unit) { @@ -39,7 +39,7 @@ sealed class AbstractInsertColumnMapCompleter( infix fun toStringConstant(constant: String) = mappingConsumer.invoke(StringConstantMapping.of(column, constant)) } -class MultiRowInsertColumnMapCompleter( +class MultiRowInsertColumnMapCompleter( column: SqlColumn, mappingConsumer: (AbstractColumnMapping) -> Unit) : AbstractInsertColumnMapCompleter(column, mappingConsumer) { @@ -49,7 +49,7 @@ class MultiRowInsertColumnMapCompleter( fun toRow() = mappingConsumer.invoke(RowMapping.of(column)) } -class SingleRowInsertColumnMapCompleter( +class SingleRowInsertColumnMapCompleter( column: SqlColumn, mappingConsumer: (AbstractColumnMapping) -> Unit) : AbstractInsertColumnMapCompleter(column, mappingConsumer) { @@ -62,14 +62,14 @@ class SingleRowInsertColumnMapCompleter( fun toRow() = mappingConsumer.invoke(RowMapping.of(column)) } -class GeneralInsertColumnSetCompleter( +class GeneralInsertColumnSetCompleter( column: SqlColumn, mappingConsumer: (AbstractColumnMapping) -> Unit) : AbstractInsertColumnMapCompleter(column, mappingConsumer) { - infix fun toValue(value: T & Any) = toValue { value } + infix fun toValue(value: T) = toValue { value } - infix fun toValue(value: () -> T & Any) = mappingConsumer.invoke(ValueMapping.of(column, value)) + infix fun toValue(value: () -> T) = mappingConsumer.invoke(ValueMapping.of(column, value)) infix fun toValueOrNull(value: T?) = toValueOrNull { value } diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinMultiRowInsertBuilder.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinMultiRowInsertBuilder.kt index f97ca8510..b00a62aef 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinMultiRowInsertBuilder.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinMultiRowInsertBuilder.kt @@ -33,7 +33,7 @@ class KotlinMultiRowInsertBuilder (private val rows: Collection): Bu this.table = table } - fun map(column: SqlColumn) = MultiRowInsertColumnMapCompleter(column) { + fun map(column: SqlColumn) = MultiRowInsertColumnMapCompleter(column) { columnMappings.add(it) } @@ -41,7 +41,7 @@ class KotlinMultiRowInsertBuilder (private val rows: Collection): Bu assertNotNull(table, "ERROR.26") //$NON-NLS-1$ return with(MultiRowInsertDSL.Builder()) { withRecords(rows) - withTable(table) + withTable(table!!) withColumnMappings(columnMappings) build() }.build() diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinSubQueryBuilders.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinSubQueryBuilders.kt index 3ae99d435..9439e4058 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinSubQueryBuilders.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinSubQueryBuilders.kt @@ -84,11 +84,11 @@ class KotlinInsertSelectSubQueryBuilder : KotlinBaseSubQueryBuilder(), Buildable assertNotNull(table, "ERROR.29") //$NON-NLS-1$ val dsl = if (columnList == null) { - SqlBuilder.insertInto(table) + SqlBuilder.insertInto(table!!) .withSelectStatement { buildSelectModel() } } else { - SqlBuilder.insertInto(table) - .withColumnList(columnList) + SqlBuilder.insertInto(table!!) + .withColumnList(columnList!!) .withSelectStatement { buildSelectModel() } } diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinUpdateBuilder.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinUpdateBuilder.kt index 91d14cf58..f83e45add 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinUpdateBuilder.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinUpdateBuilder.kt @@ -27,7 +27,7 @@ typealias UpdateCompleter = KotlinUpdateBuilder.() -> Unit class KotlinUpdateBuilder(private val dsl: UpdateDSL) : KotlinBaseBuilder>(), Buildable { - fun set(column: SqlColumn): KotlinSetClauseFinisher = KotlinSetClauseFinisher(column) + fun set(column: SqlColumn): KotlinSetClauseFinisher = KotlinSetClauseFinisher(column) fun orderBy(vararg columns: SortSpecification) { dsl.orderBy(columns.toList()) @@ -47,7 +47,7 @@ class KotlinUpdateBuilder(private val dsl: UpdateDSL) : @MyBatisDslMarker @Suppress("TooManyFunctions") - inner class KotlinSetClauseFinisher(private val column: SqlColumn) { + inner class KotlinSetClauseFinisher(private val column: SqlColumn) { fun equalToNull(): Unit = applyToDsl { set(column).equalToNull() @@ -63,9 +63,9 @@ class KotlinUpdateBuilder(private val dsl: UpdateDSL) : set(column).equalToStringConstant(constant) } - infix fun equalTo(value: T & Any): Unit = equalTo { value } + infix fun equalTo(value: T): Unit = equalTo { value } - infix fun equalTo(value: () -> T & Any): Unit = + infix fun equalTo(value: () -> T): Unit = applyToDsl { set(column).equalTo(value) } diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/CaseDSLs.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/CaseDSLs.kt index 683ac0872..bc04a992d 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/CaseDSLs.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/CaseDSLs.kt @@ -22,6 +22,7 @@ import org.mybatis.dynamic.sql.select.caseexpression.ConditionBasedWhenCondition import org.mybatis.dynamic.sql.select.caseexpression.SearchedCaseWhenCondition import org.mybatis.dynamic.sql.select.caseexpression.SimpleCaseWhenCondition import org.mybatis.dynamic.sql.util.kotlin.GroupingCriteriaCollector +import org.mybatis.dynamic.sql.util.kotlin.assertNotNull import org.mybatis.dynamic.sql.util.kotlin.assertNull class KSearchedCaseDSL : KElseDSL { @@ -34,9 +35,10 @@ class KSearchedCaseDSL : KElseDSL { fun `when`(dslCompleter: SearchedCaseCriteriaCollector.() -> Unit) = SearchedCaseCriteriaCollector().apply(dslCompleter).run { + assertNotNull(thenValue, "ERROR.47") //$NON-NLS-1$ whenConditions.add(SearchedCaseWhenCondition.Builder().withInitialCriterion(initialCriterion) .withSubCriteria(subCriteria) - .withThenValue(thenValue) + .withThenValue(thenValue!!) .build()) } diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/ColumnExtensions.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/ColumnExtensions.kt index 59e24a82b..ab5f81a2a 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/ColumnExtensions.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/ColumnExtensions.kt @@ -20,17 +20,17 @@ import org.mybatis.dynamic.sql.SqlColumn import org.mybatis.dynamic.sql.select.caseexpression.SearchedCaseModel import org.mybatis.dynamic.sql.select.caseexpression.SimpleCaseModel -infix fun DerivedColumn.`as`(alias: String): DerivedColumn = this.`as`(alias) +infix fun DerivedColumn.`as`(alias: String): DerivedColumn = this.`as`(alias) -infix fun SqlColumn.`as`(alias: String): SqlColumn = this.`as`(alias) +infix fun SqlColumn.`as`(alias: String): SqlColumn = this.`as`(alias) infix fun SearchedCaseModel.`as`(alias: String): SearchedCaseModel = this.`as`(alias) -infix fun SimpleCaseModel.`as`(alias: String): SimpleCaseModel = this.`as`(alias) +infix fun SimpleCaseModel.`as`(alias: String): SimpleCaseModel = this.`as`(alias) /** * Adds a qualifier to a column for use with table aliases (typically in joins or sub queries). * This is as close to natural SQL syntax as we can get in Kotlin. Natural SQL would look like * "qualifier.column". With this function we can say "qualifier(column)". */ -operator fun String.invoke(column: SqlColumn): SqlColumn = column.qualifiedWith(this) +operator fun String.invoke(column: SqlColumn): SqlColumn = column.qualifiedWith(this) diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/SqlElements.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/SqlElements.kt index 8be26db50..a7fe899d6 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/SqlElements.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/SqlElements.kt @@ -129,45 +129,45 @@ fun count(column: BasicColumn): Count = SqlBuilder.count(column) fun countDistinct(column: BasicColumn): CountDistinct = SqlBuilder.countDistinct(column) -fun max(column: BindableColumn): Max = SqlBuilder.max(column) +fun max(column: BindableColumn): Max = SqlBuilder.max(column) -fun min(column: BindableColumn): Min = SqlBuilder.min(column) +fun min(column: BindableColumn): Min = SqlBuilder.min(column) -fun avg(column: BindableColumn): Avg = SqlBuilder.avg(column) +fun avg(column: BindableColumn): Avg = SqlBuilder.avg(column) -fun sum(column: BindableColumn): Sum = SqlBuilder.sum(column) +fun sum(column: BindableColumn): Sum = SqlBuilder.sum(column) fun sum(column: BasicColumn): Sum<*> = SqlBuilder.sum(column) -fun sum(column: BindableColumn, condition: VisitableCondition): Sum = SqlBuilder.sum(column, condition) +fun sum(column: BindableColumn, condition: VisitableCondition): Sum = SqlBuilder.sum(column, condition) // constants -fun constant(constant: String): Constant = SqlBuilder.constant(constant) +fun constant(constant: String): Constant = SqlBuilder.constant(constant) fun stringConstant(constant: String): StringConstant = SqlBuilder.stringConstant(constant) -fun value(value: T): BoundValue = SqlBuilder.value(value) +fun value(value: T): BoundValue = SqlBuilder.value(value) // functions -fun add( +fun add( firstColumn: BindableColumn, secondColumn: BasicColumn, vararg subsequentColumns: BasicColumn ): Add = Add.of(firstColumn, secondColumn, subsequentColumns.asList()) -fun divide( +fun divide( firstColumn: BindableColumn, secondColumn: BasicColumn, vararg subsequentColumns: BasicColumn ): Divide = Divide.of(firstColumn, secondColumn, subsequentColumns.asList()) -fun multiply( +fun multiply( firstColumn: BindableColumn, secondColumn: BasicColumn, vararg subsequentColumns: BasicColumn ): Multiply = Multiply.of(firstColumn, secondColumn, subsequentColumns.asList()) -fun subtract( +fun subtract( firstColumn: BindableColumn, secondColumn: BasicColumn, vararg subsequentColumns: BasicColumn @@ -176,147 +176,147 @@ fun subtract( fun cast(receiver: CastDSL.() -> Unit): Cast = invalidIfNull(CastDSL().apply(receiver).cast, "ERROR.43") -fun concat( +fun concat( firstColumn: BindableColumn, vararg subsequentColumns: BasicColumn ): Concat = Concat.of(firstColumn, subsequentColumns.asList()) -fun concatenate( +fun concatenate( firstColumn: BindableColumn, secondColumn: BasicColumn, vararg subsequentColumns: BasicColumn ): Concatenate = Concatenate.of(firstColumn, secondColumn, subsequentColumns.asList()) -fun applyOperator( +fun applyOperator( operator: String, firstColumn: BindableColumn, secondColumn: BasicColumn, vararg subsequentColumns: BasicColumn ): OperatorFunction = OperatorFunction.of(operator, firstColumn, secondColumn, subsequentColumns.asList()) -fun lower(column: BindableColumn): Lower = SqlBuilder.lower(column) +fun lower(column: BindableColumn): Lower = SqlBuilder.lower(column) -fun substring( +fun substring( column: BindableColumn, offset: Int, length: Int ): Substring = SqlBuilder.substring(column, offset, length) -fun upper(column: BindableColumn): Upper = SqlBuilder.upper(column) +fun upper(column: BindableColumn): Upper = SqlBuilder.upper(column) // conditions for all data types -fun isNull(): IsNull = SqlBuilder.isNull() +fun isNull(): IsNull = SqlBuilder.isNull() -fun isNotNull(): IsNotNull = SqlBuilder.isNotNull() +fun isNotNull(): IsNotNull = SqlBuilder.isNotNull() -fun isEqualTo(value: T & Any): IsEqualTo = SqlBuilder.isEqualTo(value) +fun isEqualTo(value: T): IsEqualTo = SqlBuilder.isEqualTo(value) -fun isEqualTo(subQuery: KotlinSubQueryBuilder.() -> Unit): IsEqualToWithSubselect = +fun isEqualTo(subQuery: KotlinSubQueryBuilder.() -> Unit): IsEqualToWithSubselect = SqlBuilder.isEqualTo(KotlinSubQueryBuilder().apply(subQuery)) -fun isEqualTo(column: BasicColumn): IsEqualToColumn = SqlBuilder.isEqualTo(column) +fun isEqualTo(column: BasicColumn): IsEqualToColumn = SqlBuilder.isEqualTo(column) -fun isEqualToWhenPresent(value: T?): IsEqualTo = SqlBuilder.isEqualToWhenPresent(value) +fun isEqualToWhenPresent(value: T?): IsEqualTo = SqlBuilder.isEqualToWhenPresent(value) -fun isNotEqualTo(value: T & Any): IsNotEqualTo = SqlBuilder.isNotEqualTo(value) +fun isNotEqualTo(value: T): IsNotEqualTo = SqlBuilder.isNotEqualTo(value) -fun isNotEqualTo(subQuery: KotlinSubQueryBuilder.() -> Unit): IsNotEqualToWithSubselect = +fun isNotEqualTo(subQuery: KotlinSubQueryBuilder.() -> Unit): IsNotEqualToWithSubselect = SqlBuilder.isNotEqualTo(KotlinSubQueryBuilder().apply(subQuery)) -fun isNotEqualTo(column: BasicColumn): IsNotEqualToColumn = SqlBuilder.isNotEqualTo(column) +fun isNotEqualTo(column: BasicColumn): IsNotEqualToColumn = SqlBuilder.isNotEqualTo(column) -fun isNotEqualToWhenPresent(value: T?): IsNotEqualTo = SqlBuilder.isNotEqualToWhenPresent(value) +fun isNotEqualToWhenPresent(value: T?): IsNotEqualTo = SqlBuilder.isNotEqualToWhenPresent(value) -fun isGreaterThan(value: T & Any): IsGreaterThan = SqlBuilder.isGreaterThan(value) +fun isGreaterThan(value: T): IsGreaterThan = SqlBuilder.isGreaterThan(value) -fun isGreaterThan(subQuery: KotlinSubQueryBuilder.() -> Unit): IsGreaterThanWithSubselect = +fun isGreaterThan(subQuery: KotlinSubQueryBuilder.() -> Unit): IsGreaterThanWithSubselect = SqlBuilder.isGreaterThan(KotlinSubQueryBuilder().apply(subQuery)) -fun isGreaterThan(column: BasicColumn): IsGreaterThanColumn = SqlBuilder.isGreaterThan(column) +fun isGreaterThan(column: BasicColumn): IsGreaterThanColumn = SqlBuilder.isGreaterThan(column) -fun isGreaterThanWhenPresent(value: T?): IsGreaterThan = SqlBuilder.isGreaterThanWhenPresent(value) +fun isGreaterThanWhenPresent(value: T?): IsGreaterThan = SqlBuilder.isGreaterThanWhenPresent(value) -fun isGreaterThanOrEqualTo(value: T & Any): IsGreaterThanOrEqualTo = SqlBuilder.isGreaterThanOrEqualTo(value) +fun isGreaterThanOrEqualTo(value: T): IsGreaterThanOrEqualTo = SqlBuilder.isGreaterThanOrEqualTo(value) -fun isGreaterThanOrEqualTo(subQuery: KotlinSubQueryBuilder.() -> Unit): IsGreaterThanOrEqualToWithSubselect = +fun isGreaterThanOrEqualTo(subQuery: KotlinSubQueryBuilder.() -> Unit): IsGreaterThanOrEqualToWithSubselect = SqlBuilder.isGreaterThanOrEqualTo(KotlinSubQueryBuilder().apply(subQuery)) -fun isGreaterThanOrEqualTo(column: BasicColumn): IsGreaterThanOrEqualToColumn = +fun isGreaterThanOrEqualTo(column: BasicColumn): IsGreaterThanOrEqualToColumn = SqlBuilder.isGreaterThanOrEqualTo(column) -fun isGreaterThanOrEqualToWhenPresent(value: T?): IsGreaterThanOrEqualTo = +fun isGreaterThanOrEqualToWhenPresent(value: T?): IsGreaterThanOrEqualTo = SqlBuilder.isGreaterThanOrEqualToWhenPresent(value) -fun isLessThan(value: T & Any): IsLessThan = SqlBuilder.isLessThan(value) +fun isLessThan(value: T): IsLessThan = SqlBuilder.isLessThan(value) -fun isLessThan(subQuery: KotlinSubQueryBuilder.() -> Unit): IsLessThanWithSubselect = +fun isLessThan(subQuery: KotlinSubQueryBuilder.() -> Unit): IsLessThanWithSubselect = SqlBuilder.isLessThan(KotlinSubQueryBuilder().apply(subQuery)) -fun isLessThan(column: BasicColumn): IsLessThanColumn = SqlBuilder.isLessThan(column) +fun isLessThan(column: BasicColumn): IsLessThanColumn = SqlBuilder.isLessThan(column) -fun isLessThanWhenPresent(value: T?): IsLessThan = SqlBuilder.isLessThanWhenPresent(value) +fun isLessThanWhenPresent(value: T?): IsLessThan = SqlBuilder.isLessThanWhenPresent(value) -fun isLessThanOrEqualTo(value: T & Any): IsLessThanOrEqualTo = SqlBuilder.isLessThanOrEqualTo(value) +fun isLessThanOrEqualTo(value: T): IsLessThanOrEqualTo = SqlBuilder.isLessThanOrEqualTo(value) -fun isLessThanOrEqualTo(subQuery: KotlinSubQueryBuilder.() -> Unit): IsLessThanOrEqualToWithSubselect = +fun isLessThanOrEqualTo(subQuery: KotlinSubQueryBuilder.() -> Unit): IsLessThanOrEqualToWithSubselect = SqlBuilder.isLessThanOrEqualTo(KotlinSubQueryBuilder().apply(subQuery)) -fun isLessThanOrEqualTo(column: BasicColumn): IsLessThanOrEqualToColumn = SqlBuilder.isLessThanOrEqualTo(column) +fun isLessThanOrEqualTo(column: BasicColumn): IsLessThanOrEqualToColumn = SqlBuilder.isLessThanOrEqualTo(column) -fun isLessThanOrEqualToWhenPresent(value: T?): IsLessThanOrEqualTo = +fun isLessThanOrEqualToWhenPresent(value: T?): IsLessThanOrEqualTo = SqlBuilder.isLessThanOrEqualToWhenPresent(value) -fun isIn(vararg values: T & Any): IsIn = isIn(values.asList()) +fun isIn(vararg values: T): IsIn = isIn(values.asList()) @JvmName("isInArray") -fun isIn(values: Array): IsIn = SqlBuilder.isIn(values.asList()) +fun isIn(values: Array): IsIn = SqlBuilder.isIn(values.asList()) -fun isIn(values: Collection): IsIn = SqlBuilder.isIn(values) +fun isIn(values: Collection): IsIn = SqlBuilder.isIn(values) -fun isIn(subQuery: KotlinSubQueryBuilder.() -> Unit): IsInWithSubselect = +fun isIn(subQuery: KotlinSubQueryBuilder.() -> Unit): IsInWithSubselect = SqlBuilder.isIn(KotlinSubQueryBuilder().apply(subQuery)) -fun isInWhenPresent(vararg values: T?): IsInWhenPresent = isInWhenPresent(values.asList()) +fun isInWhenPresent(vararg values: T?): IsInWhenPresent = isInWhenPresent(values.asList()) @JvmName("isInArrayWhenPresent") -fun isInWhenPresent(values: Array?): IsInWhenPresent = SqlBuilder.isInWhenPresent(values?.asList()) +fun isInWhenPresent(values: Array?): IsInWhenPresent = SqlBuilder.isInWhenPresent(values?.asList()) -fun isInWhenPresent(values: Collection?): IsInWhenPresent = SqlBuilder.isInWhenPresent(values) +fun isInWhenPresent(values: Collection?): IsInWhenPresent = SqlBuilder.isInWhenPresent(values) -fun isNotIn(vararg values: T & Any): IsNotIn = isNotIn(values.asList()) +fun isNotIn(vararg values: T): IsNotIn = isNotIn(values.asList()) @JvmName("isNotInArray") -fun isNotIn(values: Array): IsNotIn = SqlBuilder.isNotIn(values.asList()) +fun isNotIn(values: Array): IsNotIn = SqlBuilder.isNotIn(values.asList()) -fun isNotIn(values: Collection): IsNotIn = SqlBuilder.isNotIn(values) +fun isNotIn(values: Collection): IsNotIn = SqlBuilder.isNotIn(values) -fun isNotIn(subQuery: KotlinSubQueryBuilder.() -> Unit): IsNotInWithSubselect = +fun isNotIn(subQuery: KotlinSubQueryBuilder.() -> Unit): IsNotInWithSubselect = SqlBuilder.isNotIn(KotlinSubQueryBuilder().apply(subQuery)) -fun isNotInWhenPresent(vararg values: T?): IsNotInWhenPresent = isNotInWhenPresent(values.asList()) +fun isNotInWhenPresent(vararg values: T?): IsNotInWhenPresent = isNotInWhenPresent(values.asList()) @JvmName("isNotInArrayWhenPresent") -fun isNotInWhenPresent(values: Array?): IsNotInWhenPresent = SqlBuilder.isNotInWhenPresent(values?.asList()) +fun isNotInWhenPresent(values: Array?): IsNotInWhenPresent = SqlBuilder.isNotInWhenPresent(values?.asList()) -fun isNotInWhenPresent(values: Collection?): IsNotInWhenPresent = SqlBuilder.isNotInWhenPresent(values) +fun isNotInWhenPresent(values: Collection?): IsNotInWhenPresent = SqlBuilder.isNotInWhenPresent(values) -fun isBetween(value1: T & Any): BetweenBuilder = BetweenBuilder(value1) +fun isBetween(value1: T): BetweenBuilder = BetweenBuilder(value1) -fun isBetweenWhenPresent(value1: T?): BetweenWhenPresentBuilder = BetweenWhenPresentBuilder(value1) +fun isBetweenWhenPresent(value1: T?): BetweenWhenPresentBuilder = BetweenWhenPresentBuilder(value1) -fun isNotBetween(value1: T & Any): NotBetweenBuilder = NotBetweenBuilder(value1) +fun isNotBetween(value1: T): NotBetweenBuilder = NotBetweenBuilder(value1) -fun isNotBetweenWhenPresent(value1: T?): NotBetweenWhenPresentBuilder = +fun isNotBetweenWhenPresent(value1: T?): NotBetweenWhenPresentBuilder = NotBetweenWhenPresentBuilder(value1) // for string columns, but generic for columns with type handlers -fun isLike(value: T & Any): IsLike = SqlBuilder.isLike(value) +fun isLike(value: T): IsLike = SqlBuilder.isLike(value) -fun isLikeWhenPresent(value: T?): IsLike = SqlBuilder.isLikeWhenPresent(value) +fun isLikeWhenPresent(value: T?): IsLike = SqlBuilder.isLikeWhenPresent(value) -fun isNotLike(value: T & Any): IsNotLike = SqlBuilder.isNotLike(value) +fun isNotLike(value: T): IsNotLike = SqlBuilder.isNotLike(value) -fun isNotLikeWhenPresent(value: T?): IsNotLike = SqlBuilder.isNotLikeWhenPresent(value) +fun isNotLikeWhenPresent(value: T?): IsNotLike = SqlBuilder.isNotLikeWhenPresent(value) // shortcuts for booleans fun isTrue(): IsEqualTo = isEqualTo(true) @@ -392,21 +392,21 @@ fun sortColumn(name: String): SortSpecification = SqlBuilder.sortColumn(name) fun sortColumn(tableAlias: String, column: SqlColumn<*>): SortSpecification = SqlBuilder.sortColumn(tableAlias, column) // DSL Support Classes -class BetweenBuilder(private val value1: T) { +class BetweenBuilder(private val value1: T) { fun and(value2: T): IsBetween = SqlBuilder.isBetween(value1).and(value2) } -class BetweenWhenPresentBuilder(private val value1: T?) { +class BetweenWhenPresentBuilder(private val value1: T?) { fun and(value2: T?): IsBetween { return SqlBuilder.isBetweenWhenPresent(value1).and(value2) } } -class NotBetweenBuilder(private val value1: T) { +class NotBetweenBuilder(private val value1: T) { fun and(value2: T): IsNotBetween = SqlBuilder.isNotBetween(value1).and(value2) } -class NotBetweenWhenPresentBuilder(private val value1: T?) { +class NotBetweenWhenPresentBuilder(private val value1: T?) { fun and(value2: T?): IsNotBetween { return SqlBuilder.isNotBetweenWhenPresent(value1).and(value2) } diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/spring/NamedParameterJdbcTemplateExtensions.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/spring/NamedParameterJdbcTemplateExtensions.kt index 8654abe44..6cfd88151 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/spring/NamedParameterJdbcTemplateExtensions.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/spring/NamedParameterJdbcTemplateExtensions.kt @@ -65,7 +65,7 @@ fun NamedParameterJdbcTemplate.deleteFrom(table: SqlTable, completer: DeleteComp delete(org.mybatis.dynamic.sql.util.kotlin.spring.deleteFrom(table, completer)) // batch insert -fun NamedParameterJdbcTemplate.insertBatch(insertStatement: BatchInsert): IntArray = +fun NamedParameterJdbcTemplate.insertBatch(insertStatement: BatchInsert): IntArray = batchUpdate(insertStatement.insertStatementSQL, BatchInsertUtility.createBatch(insertStatement.records)) fun NamedParameterJdbcTemplate.insertBatch( @@ -81,10 +81,10 @@ fun NamedParameterJdbcTemplate.insertBatch( insertBatch(org.mybatis.dynamic.sql.util.kotlin.spring.insertBatch(records, completer)) // single row insert -fun NamedParameterJdbcTemplate.insert(insertStatement: InsertStatementProvider): Int = +fun NamedParameterJdbcTemplate.insert(insertStatement: InsertStatementProvider): Int = update(insertStatement.insertStatement, BeanPropertySqlParameterSource(insertStatement)) -fun NamedParameterJdbcTemplate.insert( +fun NamedParameterJdbcTemplate.insert( insertStatement: InsertStatementProvider, keyHolder: KeyHolder ): Int = @@ -119,10 +119,10 @@ fun NamedParameterJdbcTemplate.insertMultiple( ): Int = insertMultiple(org.mybatis.dynamic.sql.util.kotlin.spring.insertMultiple(records, completer)) -fun NamedParameterJdbcTemplate.insertMultiple(insertStatement: MultiRowInsertStatementProvider): Int = +fun NamedParameterJdbcTemplate.insertMultiple(insertStatement: MultiRowInsertStatementProvider): Int = update(insertStatement.insertStatement, BeanPropertySqlParameterSource(insertStatement)) -fun NamedParameterJdbcTemplate.insertMultiple( +fun NamedParameterJdbcTemplate.insertMultiple( insertStatement: MultiRowInsertStatementProvider, keyHolder: KeyHolder ): Int = diff --git a/src/main/resources/org/mybatis/dynamic/sql/util/messages.properties b/src/main/resources/org/mybatis/dynamic/sql/util/messages.properties index 92ed4f799..d99bd581e 100644 --- a/src/main/resources/org/mybatis/dynamic/sql/util/messages.properties +++ b/src/main/resources/org/mybatis/dynamic/sql/util/messages.properties @@ -63,4 +63,5 @@ ERROR.43=A Kotlin cast expression must have one, and only one, `as` element ERROR.44={0} conditions must contain at least one value ERROR.45=You cannot call "on" in a Kotlin join expression more than once ERROR.46=At least one join criterion must render +ERROR.47=A Kotlin case statement must specify a "then" clause for every "when" clause INTERNAL.ERROR=Internal Error {0} diff --git a/src/test/java/examples/animal/data/BindingTest.java b/src/test/java/examples/animal/data/BindingTest.java index 33efef5f0..f71a6eb58 100644 --- a/src/test/java/examples/animal/data/BindingTest.java +++ b/src/test/java/examples/animal/data/BindingTest.java @@ -51,6 +51,7 @@ class BindingTest { void setup() throws Exception { Class.forName(JDBC_DRIVER); InputStream is = getClass().getResourceAsStream("/examples/animal/data/CreateAnimalData.sql"); + assert is != null; try (Connection connection = DriverManager.getConnection(JDBC_URL, "sa", "")) { ScriptRunner sr = new ScriptRunner(connection); sr.setLogWriter(null); @@ -66,8 +67,7 @@ void setup() throws Exception { @Test void testBindInSelectList() { - SqlSession sqlSession = sqlSessionFactory.openSession(); - try { + try (SqlSession sqlSession = sqlSessionFactory.openSession()) { Connection connection = sqlSession.getConnection(); PreparedStatement ps = connection.prepareStatement("select brain_weight + ? as calc from AnimalData where id = ?"); @@ -86,15 +86,12 @@ void testBindInSelectList() { assertThat(calculatedWeight).isEqualTo(1.005); } catch (SQLException e) { fail("SQL Exception", e); - } finally { - sqlSession.close(); } } @Test void testBindInWeirdWhere() { - SqlSession sqlSession = sqlSessionFactory.openSession(); - try { + try (SqlSession sqlSession = sqlSessionFactory.openSession()) { Connection connection = sqlSession.getConnection(); PreparedStatement ps = connection.prepareStatement("select brain_weight from AnimalData where brain_weight + ? > ? and id = ?"); @@ -114,8 +111,6 @@ void testBindInWeirdWhere() { assertThat(calculatedWeight).isEqualTo(.005); } catch (SQLException e) { fail("SQL Exception", e); - } finally { - sqlSession.close(); } } } diff --git a/src/test/java/examples/animal/data/OptionalConditionsWithPredicatesAnimalDataTest.java b/src/test/java/examples/animal/data/OptionalConditionsWithPredicatesAnimalDataTest.java index a967052d2..a46190941 100644 --- a/src/test/java/examples/animal/data/OptionalConditionsWithPredicatesAnimalDataTest.java +++ b/src/test/java/examples/animal/data/OptionalConditionsWithPredicatesAnimalDataTest.java @@ -93,6 +93,26 @@ void testAllIgnored() { } } + @Test + void testSelectByNull() { + // this method demonstrates that ignoring the null value warning will still work + try (SqlSession sqlSession = sqlSessionFactory.openSession()) { + AnimalDataMapper mapper = sqlSession.getMapper(AnimalDataMapper.class); + SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) + .from(animalData) + .where(id, isGreaterThan(NULL_INTEGER)) // should be an IDE warning about passing null to a nonnull method + .orderBy(id) + .build() + .render(RenderingStrategies.MYBATIS3); + List animals = mapper.selectMany(selectStatement); + assertAll( + () -> assertThat(selectStatement.getSelectStatement()).isEqualTo("select id, animal_name, body_weight, brain_weight from AnimalData where id > #{parameters.p1,jdbcType=INTEGER} order by id"), + () -> assertThat(selectStatement.getParameters()).containsEntry("p1", null), + () -> assertThat(animals).isEmpty() + ); + } + } + @Test void testIgnoredBetweenRendered() { try (SqlSession sqlSession = sqlSessionFactory.openSession()) { diff --git a/src/test/java/examples/spring/LastNameParameterConverter.java b/src/test/java/examples/spring/LastNameParameterConverter.java index 0914bf4e7..2a45753d7 100644 --- a/src/test/java/examples/spring/LastNameParameterConverter.java +++ b/src/test/java/examples/spring/LastNameParameterConverter.java @@ -15,12 +15,15 @@ */ package examples.spring; +import org.jspecify.annotations.NullMarked; import org.mybatis.dynamic.sql.ParameterTypeConverter; import org.springframework.core.convert.converter.Converter; -public class LastNameParameterConverter implements ParameterTypeConverter, Converter { +@NullMarked +public class LastNameParameterConverter implements ParameterTypeConverter, + Converter { @Override public String convert(LastName source) { - return source == null ? null : source.getName(); + return source.getName(); } } diff --git a/src/test/java/examples/spring/YesNoParameterConverter.java b/src/test/java/examples/spring/YesNoParameterConverter.java index 131c0d84a..f86cc7b0f 100644 --- a/src/test/java/examples/spring/YesNoParameterConverter.java +++ b/src/test/java/examples/spring/YesNoParameterConverter.java @@ -15,12 +15,14 @@ */ package examples.spring; +import org.jspecify.annotations.NullMarked; import org.mybatis.dynamic.sql.ParameterTypeConverter; +@NullMarked public class YesNoParameterConverter implements ParameterTypeConverter { @Override public String convert(Boolean source) { - return source == null ? null : source ? "Yes" : "No"; + return source ? "Yes" : "No"; } } diff --git a/src/test/java/org/mybatis/dynamic/sql/where/condition/FilterAndMapTest.java b/src/test/java/org/mybatis/dynamic/sql/where/condition/FilterAndMapTest.java index 68adb5714..bd5f2e2cd 100644 --- a/src/test/java/org/mybatis/dynamic/sql/where/condition/FilterAndMapTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/where/condition/FilterAndMapTest.java @@ -19,6 +19,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import java.util.List; +import java.util.NoSuchElementException; import java.util.Objects; import org.junit.jupiter.api.Test; @@ -36,7 +37,7 @@ void testTypeConversion() { void testTypeConversionWithNullThrowsException() { IsEqualTo cond = SqlBuilder.isEqualTo((String) null); assertThatExceptionOfType(NumberFormatException.class).isThrownBy(() -> - cond.map(Integer::parseInt) + cond.map(Integer::parseInt) ); } @@ -123,7 +124,7 @@ void testIsEqualMapUnRenderableShouldNotThrowNullPointerException() { IsEqualTo cond = SqlBuilder.isEqualTo("Fred").filter(s -> false); IsEqualTo mapped = cond.map(String::toUpperCase); assertThat(cond.isEmpty()).isTrue(); - assertThat(cond.value()).isNull(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond).isSameAs(mapped); } @@ -156,7 +157,7 @@ void testIsNotEqualMapUnRenderableShouldNotThrowNullPointerException() { IsNotEqualTo cond = SqlBuilder.isNotEqualTo("Fred").filter(s -> false); IsNotEqualTo mapped = cond.map(String::toUpperCase); assertThat(cond.isEmpty()).isTrue(); - assertThat(cond.value()).isNull(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond).isSameAs(mapped); } @@ -189,7 +190,7 @@ void testIsLessThanMapUnRenderableShouldNotThrowNullPointerException() { IsLessThan cond = SqlBuilder.isLessThan("Fred").filter(s -> false); IsLessThan mapped = cond.map(String::toUpperCase); assertThat(cond.isEmpty()).isTrue(); - assertThat(cond.value()).isNull(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond).isSameAs(mapped); } @@ -222,7 +223,7 @@ void testIsLessThanOrEqualMapUnRenderableShouldNotThrowNullPointerException() { IsLessThanOrEqualTo cond = SqlBuilder.isLessThanOrEqualTo("Fred").filter(s -> false); IsLessThanOrEqualTo mapped = cond.map(String::toUpperCase); assertThat(cond.isEmpty()).isTrue(); - assertThat(cond.value()).isNull(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond).isSameAs(mapped); } @@ -255,7 +256,7 @@ void testIsGreaterThanMapUnRenderableShouldNotThrowNullPointerException() { IsGreaterThan cond = SqlBuilder.isGreaterThan("Fred").filter(s -> false); IsGreaterThan mapped = cond.map(String::toUpperCase); assertThat(cond.isEmpty()).isTrue(); - assertThat(cond.value()).isNull(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond).isSameAs(mapped); } @@ -288,7 +289,7 @@ void testIsGreaterThanOrEqualMapUnRenderableShouldNotThrowNullPointerException() IsGreaterThanOrEqualTo cond = SqlBuilder.isGreaterThanOrEqualTo("Fred").filter(s -> false); IsGreaterThanOrEqualTo mapped = cond.map(String::toUpperCase); assertThat(cond.isEmpty()).isTrue(); - assertThat(cond.value()).isNull(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond).isSameAs(mapped); } @@ -321,7 +322,7 @@ void testIsLikeMapUnRenderableShouldNotThrowNullPointerException() { IsLike cond = SqlBuilder.isLike("Fred").filter(s -> false); IsLike mapped = cond.map(String::toUpperCase); assertThat(cond.isEmpty()).isTrue(); - assertThat(cond.value()).isNull(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond).isSameAs(mapped); } @@ -355,7 +356,7 @@ void testIsLikeCaseInsensitiveMapUnRenderableShouldNotThrowNullPointerException( IsLikeCaseInsensitive cond = SqlBuilder.isLikeCaseInsensitive("Fred").filter(s -> false); IsLikeCaseInsensitive mapped = cond.map(String::toUpperCase); assertThat(cond.isEmpty()).isTrue(); - assertThat(cond.value()).isNull(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond).isSameAs(mapped); } @@ -388,7 +389,7 @@ void testIsNotLikeMapUnRenderableShouldNotThrowNullPointerException() { IsNotLike cond = SqlBuilder.isNotLike("Fred").filter(s -> false); IsNotLike mapped = cond.map(String::toUpperCase); assertThat(cond.isEmpty()).isTrue(); - assertThat(cond.value()).isNull(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond).isSameAs(mapped); } @@ -422,7 +423,7 @@ void testIsNotLikeCaseInsensitiveMapUnRenderableShouldNotThrowNullPointerExcepti IsNotLikeCaseInsensitive cond = SqlBuilder.isNotLikeCaseInsensitive("Fred").filter(s -> false); IsNotLikeCaseInsensitive mapped = cond.map(String::toUpperCase); assertThat(cond.isEmpty()).isTrue(); - assertThat(cond.value()).isNull(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond).isSameAs(mapped); } diff --git a/src/test/java/org/mybatis/dynamic/sql/where/condition/SupplierTest.java b/src/test/java/org/mybatis/dynamic/sql/where/condition/SupplierTest.java index 86675e51d..e1362d48f 100644 --- a/src/test/java/org/mybatis/dynamic/sql/where/condition/SupplierTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/where/condition/SupplierTest.java @@ -16,10 +16,13 @@ package org.mybatis.dynamic.sql.where.condition; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import org.junit.jupiter.api.Test; import org.mybatis.dynamic.sql.SqlBuilder; +import java.util.NoSuchElementException; + // series of tests to check that the Supplier based DSL methods function correctly class SupplierTest { @@ -50,8 +53,8 @@ void testIsBetweenWhenPresent() { @Test void testIsBetweenWhenPresentNull() { IsBetween cond = SqlBuilder.isBetweenWhenPresent(() -> (Integer) null).and(() -> null); - assertThat(cond.value1()).isNull(); - assertThat(cond.value2()).isNull(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value1); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value2); assertThat(cond.isEmpty()).isTrue(); } @@ -82,8 +85,8 @@ void testIsNotBetweenWhenPresent() { @Test void testIsNotBetweenWhenPresentNull() { IsNotBetween cond = SqlBuilder.isNotBetweenWhenPresent(() -> (Integer) null).and(() -> null); - assertThat(cond.value1()).isNull(); - assertThat(cond.value2()).isNull(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value1); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value2); assertThat(cond.isEmpty()).isTrue(); } @@ -97,7 +100,7 @@ void testIsEqualToWhenPresent() { @Test void testIsEqualToWhenPresentNull() { IsEqualTo cond = SqlBuilder.isEqualToWhenPresent(() -> null); - assertThat(cond.value()).isNull(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond.isEmpty()).isTrue(); } @@ -125,7 +128,7 @@ void testIsNotEqualToWhenPresent() { @Test void testIsNotEqualToWhenPresentNull() { IsNotEqualTo cond = SqlBuilder.isNotEqualToWhenPresent(() -> null); - assertThat(cond.value()).isNull(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond.isEmpty()).isTrue(); } @@ -153,7 +156,7 @@ void testIsGreaterThanWhenPresent() { @Test void testIsGreaterThanWhenPresentNull() { IsGreaterThan cond = SqlBuilder.isGreaterThanWhenPresent(() -> null); - assertThat(cond.value()).isNull(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond.isEmpty()).isTrue(); } @@ -181,7 +184,7 @@ void testIsGreaterThanOrEqualToWhenPresent() { @Test void testIsGreaterThanOrEqualToWhenPresentNull() { IsGreaterThanOrEqualTo cond = SqlBuilder.isGreaterThanOrEqualToWhenPresent(() -> null); - assertThat(cond.value()).isNull(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond.isEmpty()).isTrue(); } @@ -209,7 +212,7 @@ void testIsLessThanWhenPresent() { @Test void testIsLessThanWhenPresentNull() { IsLessThan cond = SqlBuilder.isLessThanWhenPresent(() -> null); - assertThat(cond.value()).isNull(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond.isEmpty()).isTrue(); } @@ -237,7 +240,7 @@ void testIsLessThanOrEqualToWhenPresent() { @Test void testIsLessThanOrEqualToWhenPresentNull() { IsLessThanOrEqualTo cond = SqlBuilder.isLessThanOrEqualToWhenPresent(() -> null); - assertThat(cond.value()).isNull(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond.isEmpty()).isTrue(); } @@ -279,7 +282,7 @@ void testIsLikeCaseInsensitiveWhenPresent() { @Test void testIsLikeCaseInsensitiveWhenPresentNull() { IsLikeCaseInsensitive cond = SqlBuilder.isLikeCaseInsensitiveWhenPresent(() -> null); - assertThat(cond.value()).isNull(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond.isEmpty()).isTrue(); } @@ -293,7 +296,7 @@ void testIsLikeWhenPresent() { @Test void testIsLikeWhenPresentNull() { IsLike cond = SqlBuilder.isLikeWhenPresent(() -> null); - assertThat(cond.value()).isNull(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond.isEmpty()).isTrue(); } @@ -321,7 +324,7 @@ void testIsNotLikeWhenPresent() { @Test void testIsNotLikeWhenPresentNull() { IsNotLike cond = SqlBuilder.isNotLikeWhenPresent(() -> null); - assertThat(cond.value()).isNull(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond.isEmpty()).isTrue(); } @@ -349,7 +352,7 @@ void testIsNotLikeCaseInsensitiveWhenPresent() { @Test void testIsNotLikeCaseInsensitiveWhenPresentNull() { IsNotLikeCaseInsensitive cond = SqlBuilder.isNotLikeCaseInsensitiveWhenPresent(() -> null); - assertThat(cond.value()).isNull(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value); assertThat(cond.isEmpty()).isTrue(); } } diff --git a/src/test/kotlin/examples/kotlin/animal/data/KCaseExpressionTest.kt b/src/test/kotlin/examples/kotlin/animal/data/KCaseExpressionTest.kt index 4dc81706e..673265487 100644 --- a/src/test/kotlin/examples/kotlin/animal/data/KCaseExpressionTest.kt +++ b/src/test/kotlin/examples/kotlin/animal/data/KCaseExpressionTest.kt @@ -922,6 +922,17 @@ class KCaseExpressionTest { }.withMessage(Messages.getString("ERROR.41")) } + @Test + fun testInvalidMissingThen() { + assertThatExceptionOfType(KInvalidSQLException::class.java).isThrownBy { + case { + `when` { + id isEqualTo 22 + } + } + }.withMessage(Messages.getString("ERROR.47")) + } + @Test fun testInvalidSearchedMissingWhen() { assertThatExceptionOfType(InvalidSqlException::class.java).isThrownBy { diff --git a/src/test/kotlin/examples/kotlin/mybatis3/custom/render/KCustomRenderingTest.kt b/src/test/kotlin/examples/kotlin/mybatis3/custom/render/KCustomRenderingTest.kt index d0c7e7a04..47a6fcaed 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/custom/render/KCustomRenderingTest.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/custom/render/KCustomRenderingTest.kt @@ -304,7 +304,7 @@ class KCustomRenderingTest { } } - private fun dereference(column: SqlColumn, attribute: String) = + private fun dereference(column: SqlColumn, attribute: String) = SqlColumn.of(column.name() + "->>'" + attribute + "'", column.table(), JDBCType.VARCHAR) companion object {