Skip to content

Commit 543e0fd

Browse files
committed
Two value conditions do not expect null values
1 parent e6eef01 commit 543e0fd

File tree

8 files changed

+119
-48
lines changed

8 files changed

+119
-48
lines changed

src/main/java/org/mybatis/dynamic/sql/AbstractTwoValueCondition.java

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,22 +21,20 @@
2121
import java.util.function.Predicate;
2222
import java.util.function.Supplier;
2323

24-
import org.jspecify.annotations.Nullable;
25-
2624
public abstract class AbstractTwoValueCondition<T> implements VisitableCondition<T> {
27-
protected final @Nullable T value1;
28-
protected final @Nullable T value2;
25+
protected final T value1;
26+
protected final T value2;
2927

30-
protected AbstractTwoValueCondition(@Nullable T value1, @Nullable T value2) {
28+
protected AbstractTwoValueCondition(T value1, T value2) {
3129
this.value1 = value1;
3230
this.value2 = value2;
3331
}
3432

35-
public @Nullable T value1() {
33+
public T value1() {
3634
return value1;
3735
}
3836

39-
public @Nullable T value2() {
37+
public T value2() {
4038
return value2;
4139
}
4240

src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -764,11 +764,11 @@ static <T> IsLessThanOrEqualTo<T> isLessThanOrEqualToWhenPresent(Supplier<@Nulla
764764
}
765765

766766
@SafeVarargs
767-
static <T> IsIn<T> isIn(@Nullable T... values) {
767+
static <T> IsIn<T> isIn(T... values) {
768768
return IsIn.of(values);
769769
}
770770

771-
static <T> IsIn<T> isIn(Collection<@Nullable T> values) {
771+
static <T> IsIn<T> isIn(Collection<T> values) {
772772
return IsIn.of(values);
773773
}
774774

@@ -786,11 +786,11 @@ static <T> IsInWhenPresent<T> isInWhenPresent(@Nullable Collection<@Nullable T>
786786
}
787787

788788
@SafeVarargs
789-
static <T> IsNotIn<T> isNotIn(@Nullable T... values) {
789+
static <T> IsNotIn<T> isNotIn(T... values) {
790790
return IsNotIn.of(values);
791791
}
792792

793-
static <T> IsNotIn<T> isNotIn(Collection<@Nullable T> values) {
793+
static <T> IsNotIn<T> isNotIn(Collection<T> values) {
794794
return IsNotIn.of(values);
795795
}
796796

@@ -807,11 +807,11 @@ static <T> IsNotInWhenPresent<T> isNotInWhenPresent(@Nullable Collection<@Nullab
807807
return values == null ? IsNotInWhenPresent.empty() : IsNotInWhenPresent.of(values);
808808
}
809809

810-
static <T> IsBetween.Builder<T> isBetween(@Nullable T value1) {
810+
static <T> IsBetween.Builder<T> isBetween(T value1) {
811811
return IsBetween.isBetween(value1);
812812
}
813813

814-
static <T> IsBetween.Builder<T> isBetween(Supplier<@Nullable T> valueSupplier1) {
814+
static <T> IsBetween.Builder<T> isBetween(Supplier<T> valueSupplier1) {
815815
return isBetween(valueSupplier1.get());
816816
}
817817

@@ -823,11 +823,11 @@ static <T> IsBetween.WhenPresentBuilder<T> isBetweenWhenPresent(Supplier<@Nullab
823823
return isBetweenWhenPresent(valueSupplier1.get());
824824
}
825825

826-
static <T> IsNotBetween.Builder<T> isNotBetween(@Nullable T value1) {
826+
static <T> IsNotBetween.Builder<T> isNotBetween(T value1) {
827827
return IsNotBetween.isNotBetween(value1);
828828
}
829829

830-
static <T> IsNotBetween.Builder<T> isNotBetween(Supplier<@Nullable T> valueSupplier1) {
830+
static <T> IsNotBetween.Builder<T> isNotBetween(Supplier<T> valueSupplier1) {
831831
return isNotBetween(valueSupplier1.get());
832832
}
833833

src/main/java/org/mybatis/dynamic/sql/where/condition/AndGatherer.java

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@
1717

1818
import java.util.function.Supplier;
1919

20-
import org.jspecify.annotations.Nullable;
21-
2220
/**
2321
* Utility class supporting the "and" part of a between condition. This class supports builders, so it is mutable.
2422
*
@@ -30,21 +28,19 @@
3028
* the type of condition being built
3129
*/
3230
public abstract class AndGatherer<T, R> {
33-
protected final @Nullable T value1;
34-
protected @Nullable T value2;
31+
protected final T value1;
3532

36-
protected AndGatherer(@Nullable T value1) {
33+
protected AndGatherer(T value1) {
3734
this.value1 = value1;
3835
}
3936

40-
public R and(@Nullable T value2) {
41-
this.value2 = value2;
42-
return build();
37+
public R and(T value2) {
38+
return build(value2);
4339
}
4440

45-
public R and(Supplier<@Nullable T> valueSupplier2) {
41+
public R and(Supplier<T> valueSupplier2) {
4642
return and(valueSupplier2.get());
4743
}
4844

49-
protected abstract R build();
45+
protected abstract R build(T value2);
5046
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright 2016-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.mybatis.dynamic.sql.where.condition;
17+
18+
import java.util.function.Supplier;
19+
20+
import org.jspecify.annotations.Nullable;
21+
22+
/**
23+
* Utility class supporting the "and" part of a between when present condition. This class supports builders,
24+
* so it is mutable.
25+
*
26+
* @author Jeff Butler
27+
*
28+
* @param <T>
29+
* the type of field for the between condition
30+
* @param <R>
31+
* the type of condition being built
32+
*/
33+
public abstract class AndWhenPresentGatherer<T, R> {
34+
protected final @Nullable T value1;
35+
36+
protected AndWhenPresentGatherer(@Nullable T value1) {
37+
this.value1 = value1;
38+
}
39+
40+
public R and(@Nullable T value2) {
41+
return build(value2);
42+
}
43+
44+
public R and(Supplier<@Nullable T> valueSupplier2) {
45+
return and(valueSupplier2.get());
46+
}
47+
48+
protected abstract R build(@Nullable T value2);
49+
}

src/main/java/org/mybatis/dynamic/sql/where/condition/IsBetween.java

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
*/
1616
package org.mybatis.dynamic.sql.where.condition;
1717

18-
import java.util.Objects;
18+
import java.util.NoSuchElementException;
1919
import java.util.function.BiPredicate;
2020
import java.util.function.Function;
2121
import java.util.function.Predicate;
@@ -24,7 +24,17 @@
2424
import org.mybatis.dynamic.sql.AbstractTwoValueCondition;
2525

2626
public class IsBetween<T> extends AbstractTwoValueCondition<T> {
27-
private static final IsBetween<?> EMPTY = new IsBetween<>(null, null) {
27+
private static final IsBetween<?> EMPTY = new IsBetween<Object>(-1, -1) {
28+
@Override
29+
public Object value1() {
30+
throw new NoSuchElementException("No value present"); //$NON-NLS-1$
31+
}
32+
33+
@Override
34+
public Object value2() {
35+
throw new NoSuchElementException("No value present"); //$NON-NLS-1$
36+
}
37+
2838
@Override
2939
public boolean isEmpty() {
3040
return true;
@@ -37,7 +47,7 @@ public static <T> IsBetween<T> empty() {
3747
return t;
3848
}
3949

40-
protected IsBetween(@Nullable T value1, @Nullable T value2) {
50+
protected IsBetween(T value1, T value2) {
4151
super(value1, value2);
4252
}
4353

@@ -88,7 +98,7 @@ public <R> IsBetween<R> map(Function<? super T, ? extends R> mapper) {
8898
return map(mapper, mapper);
8999
}
90100

91-
public static <T> Builder<T> isBetween(@Nullable T value1) {
101+
public static <T> Builder<T> isBetween(T value1) {
92102
return new Builder<>(value1);
93103
}
94104

@@ -97,24 +107,28 @@ public static <T> WhenPresentBuilder<T> isBetweenWhenPresent(@Nullable T value1)
97107
}
98108

99109
public static class Builder<T> extends AndGatherer<T, IsBetween<T>> {
100-
private Builder(@Nullable T value1) {
110+
private Builder(T value1) {
101111
super(value1);
102112
}
103113

104114
@Override
105-
protected IsBetween<T> build() {
115+
protected IsBetween<T> build(T value2) {
106116
return new IsBetween<>(value1, value2);
107117
}
108118
}
109119

110-
public static class WhenPresentBuilder<T> extends AndGatherer<T, IsBetween<T>> {
120+
public static class WhenPresentBuilder<T> extends AndWhenPresentGatherer<T, IsBetween<T>> {
111121
private WhenPresentBuilder(@Nullable T value1) {
112122
super(value1);
113123
}
114124

115125
@Override
116-
protected IsBetween<T> build() {
117-
return new IsBetween<>(value1, value2).filter(Objects::nonNull);
126+
protected IsBetween<T> build(@Nullable T value2) {
127+
if (value1 == null || value2 == null) {
128+
return IsBetween.empty();
129+
} else {
130+
return new IsBetween<>(value1, value2);
131+
}
118132
}
119133
}
120134
}

src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotBetween.java

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
*/
1616
package org.mybatis.dynamic.sql.where.condition;
1717

18-
import java.util.Objects;
18+
import java.util.NoSuchElementException;
1919
import java.util.function.BiPredicate;
2020
import java.util.function.Function;
2121
import java.util.function.Predicate;
@@ -24,7 +24,17 @@
2424
import org.mybatis.dynamic.sql.AbstractTwoValueCondition;
2525

2626
public class IsNotBetween<T> extends AbstractTwoValueCondition<T> {
27-
private static final IsNotBetween<?> EMPTY = new IsNotBetween<>(null, null) {
27+
private static final IsNotBetween<?> EMPTY = new IsNotBetween<Object>(-1, -1) {
28+
@Override
29+
public Object value1() {
30+
throw new NoSuchElementException("No value present"); //$NON-NLS-1$
31+
}
32+
33+
@Override
34+
public Object value2() {
35+
throw new NoSuchElementException("No value present"); //$NON-NLS-1$
36+
}
37+
2838
@Override
2939
public boolean isEmpty() {
3040
return true;
@@ -37,7 +47,7 @@ public static <T> IsNotBetween<T> empty() {
3747
return t;
3848
}
3949

40-
protected IsNotBetween(@Nullable T value1, @Nullable T value2) {
50+
protected IsNotBetween(T value1, T value2) {
4151
super(value1, value2);
4252
}
4353

@@ -89,7 +99,7 @@ public <R> IsNotBetween<R> map(Function<? super T, ? extends R> mapper) {
8999
return map(mapper, mapper);
90100
}
91101

92-
public static <T> Builder<T> isNotBetween(@Nullable T value1) {
102+
public static <T> Builder<T> isNotBetween(T value1) {
93103
return new Builder<>(value1);
94104
}
95105

@@ -99,25 +109,29 @@ public static <T> WhenPresentBuilder<T> isNotBetweenWhenPresent(@Nullable T valu
99109

100110
public static class Builder<T> extends AndGatherer<T, IsNotBetween<T>> {
101111

102-
private Builder(@Nullable T value1) {
112+
private Builder(T value1) {
103113
super(value1);
104114
}
105115

106116
@Override
107-
protected IsNotBetween<T> build() {
117+
protected IsNotBetween<T> build(T value2) {
108118
return new IsNotBetween<>(value1, value2);
109119
}
110120
}
111121

112-
public static class WhenPresentBuilder<T> extends AndGatherer<T, IsNotBetween<T>> {
122+
public static class WhenPresentBuilder<T> extends AndWhenPresentGatherer<T, IsNotBetween<T>> {
113123

114124
private WhenPresentBuilder(@Nullable T value1) {
115125
super(value1);
116126
}
117127

118128
@Override
119-
protected IsNotBetween<T> build() {
120-
return new IsNotBetween<>(value1, value2).filter(Objects::nonNull);
129+
protected IsNotBetween<T> build(@Nullable T value2) {
130+
if (value1 == null || value2 == null) {
131+
return IsNotBetween.empty();
132+
} else {
133+
return new IsNotBetween<>(value1, value2);
134+
}
121135
}
122136
}
123137
}

src/test/java/issues/gh105/Issue105Test.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -527,7 +527,7 @@ void testBetweenTransformWithNull() {
527527

528528
SelectStatementProvider selectStatement = select(id, firstName, lastName)
529529
.from(person)
530-
.where(age, isBetween(1).and((Integer) null).filter(Predicates.bothPresent()).map(i1 -> i1 + 1, i2 -> i2 + 2))
530+
.where(age, isBetweenWhenPresent(1).and((Integer) null).filter(Predicates.bothPresent()).map(i1 -> i1 + 1, i2 -> i2 + 2))
531531
.configureStatement(c -> c.setNonRenderingWhereClauseAllowed(true))
532532
.build()
533533
.render(RenderingStrategies.MYBATIS3);

src/test/java/org/mybatis/dynamic/sql/where/condition/SupplierTest.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ void testIsBetweenWhenPresent() {
5353
@Test
5454
void testIsBetweenWhenPresentNull() {
5555
IsBetween<Integer> cond = SqlBuilder.isBetweenWhenPresent(() -> (Integer) null).and(() -> null);
56-
assertThat(cond.value1()).isNull();
57-
assertThat(cond.value2()).isNull();
56+
assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value1);
57+
assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value2);
5858
assertThat(cond.isEmpty()).isTrue();
5959
}
6060

@@ -85,8 +85,8 @@ void testIsNotBetweenWhenPresent() {
8585
@Test
8686
void testIsNotBetweenWhenPresentNull() {
8787
IsNotBetween<Integer> cond = SqlBuilder.isNotBetweenWhenPresent(() -> (Integer) null).and(() -> null);
88-
assertThat(cond.value1()).isNull();
89-
assertThat(cond.value2()).isNull();
88+
assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value1);
89+
assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(cond::value2);
9090
assertThat(cond.isEmpty()).isTrue();
9191
}
9292

0 commit comments

Comments
 (0)