Skip to content

Commit d591816

Browse files
committed
[CALCITE-4284] ImmutableBeans: make reference properties non-nullable by default
1 parent 3dfe5d4 commit d591816

File tree

9 files changed

+67
-72
lines changed

9 files changed

+67
-72
lines changed

core/src/main/java/org/apache/calcite/plan/RelRule.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -144,10 +144,10 @@ default <T extends Object> T as(Class<T> class_) {
144144

145145
/** Description of the rule instance. */
146146
@ImmutableBeans.Property
147-
String description();
147+
@Nullable String description();
148148

149149
/** Sets {@link #description()}. */
150-
Config withDescription(String description);
150+
Config withDescription(@Nullable String description);
151151

152152
/** Creates the operands for the rule instance. */
153153
@ImmutableBeans.Property

core/src/main/java/org/apache/calcite/rel/externalize/RelDotWriter.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,6 @@ public interface WriteOption {
287287
* Predicate for nodes that need to be highlighted.
288288
*/
289289
@ImmutableBeans.Property
290-
Predicate<RelNode> nodePredicate();
290+
@Nullable Predicate<RelNode> nodePredicate();
291291
}
292292
}

core/src/main/java/org/apache/calcite/rel/rules/AggregateReduceFunctionsRule.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -881,7 +881,7 @@ public interface Config extends RelRule.Config {
881881

882882
/** Returns the validated set of functions to reduce, or the default set
883883
* if not specified. */
884-
@NonNull default Set<SqlKind> actualFunctionsToReduce() {
884+
default Set<SqlKind> actualFunctionsToReduce() {
885885
final Set<SqlKind> set =
886886
Util.first(functionsToReduce(), DEFAULT_FUNCTIONS_TO_REDUCE);
887887
set.forEach(AggregateReduceFunctionsRule::validateFunction);

core/src/main/java/org/apache/calcite/sql/parser/SqlParser.java

+6-6
Original file line numberDiff line numberDiff line change
@@ -257,19 +257,19 @@ public interface Config {
257257
/** Sets {@link #identifierMaxLength()}. */
258258
Config withIdentifierMaxLength(int identifierMaxLength);
259259

260-
@ImmutableBeans.Property(required = true)
260+
@ImmutableBeans.Property
261261
Casing quotedCasing();
262262

263263
/** Sets {@link #quotedCasing()}. */
264264
Config withQuotedCasing(Casing casing);
265265

266-
@ImmutableBeans.Property(required = true)
266+
@ImmutableBeans.Property
267267
Casing unquotedCasing();
268268

269269
/** Sets {@link #unquotedCasing()}. */
270270
Config withUnquotedCasing(Casing casing);
271271

272-
@ImmutableBeans.Property(required = true)
272+
@ImmutableBeans.Property
273273
Quoting quoting();
274274

275275
/** Sets {@link #quoting()}. */
@@ -282,7 +282,7 @@ public interface Config {
282282
/** Sets {@link #caseSensitive()}. */
283283
Config withCaseSensitive(boolean caseSensitive);
284284

285-
@ImmutableBeans.Property(required = true)
285+
@ImmutableBeans.Property
286286
SqlConformance conformance();
287287

288288
/** Sets {@link #conformance()}. */
@@ -292,13 +292,13 @@ public interface Config {
292292
boolean allowBangEqual();
293293

294294
/** Returns which character literal styles are supported. */
295-
@ImmutableBeans.Property(required = true)
295+
@ImmutableBeans.Property
296296
Set<CharLiteralStyle> charLiteralStyles();
297297

298298
/** Sets {@link #charLiteralStyles()}. */
299299
Config withCharLiteralStyles(Set<CharLiteralStyle> charLiteralStyles);
300300

301-
@ImmutableBeans.Property(required = true)
301+
@ImmutableBeans.Property
302302
SqlParserImplFactory parserFactory();
303303

304304
/** Sets {@link #parserFactory()}. */

core/src/main/java/org/apache/calcite/sql/validate/SqlValidator.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -877,7 +877,7 @@ public interface Config {
877877

878878
/** Returns the type coercion rules for explicit type coercion. */
879879
@ImmutableBeans.Property
880-
SqlTypeCoercionRule typeCoercionRules();
880+
@Nullable SqlTypeCoercionRule typeCoercionRules();
881881

882882
/**
883883
* Sets the {@link SqlTypeCoercionRule} instance which defines the type conversion matrix
@@ -889,7 +889,7 @@ public interface Config {
889889
* @param rules The {@link SqlTypeCoercionRule} instance,
890890
* see its documentation for how to customize the rules
891891
*/
892-
Config withTypeCoercionRules(SqlTypeCoercionRule rules);
892+
Config withTypeCoercionRules(@Nullable SqlTypeCoercionRule rules);
893893

894894
/** Returns the dialect of SQL (SQL:2003, etc.) this validator recognizes.
895895
* Default is {@link SqlConformanceEnum#DEFAULT}. */

core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -6153,15 +6153,15 @@ public interface Config {
61536153

61546154
/** Returns the factory to create {@link RelBuilder}, never null. Default is
61556155
* {@link RelFactories#LOGICAL_BUILDER}. */
6156-
@ImmutableBeans.Property(required = true)
6156+
@ImmutableBeans.Property
61576157
RelBuilderFactory getRelBuilderFactory();
61586158

61596159
/** Sets {@link #getRelBuilderFactory()}. */
61606160
Config withRelBuilderFactory(RelBuilderFactory factory);
61616161

61626162
/** Returns a function that takes a {@link RelBuilder.Config} and returns
61636163
* another. Default is the identity function. */
6164-
@ImmutableBeans.Property(required = true)
6164+
@ImmutableBeans.Property
61656165
UnaryOperator<RelBuilder.Config> getRelBuilderConfigTransform();
61666166

61676167
/** Sets {@link #getRelBuilderConfigTransform()}.
@@ -6180,7 +6180,7 @@ default Config addRelBuilderConfigTransform(
61806180
/** Returns the hint strategies used to decide how the hints are propagated to
61816181
* the relational expressions. Default is
61826182
* {@link HintStrategyTable#EMPTY}. */
6183-
@ImmutableBeans.Property(required = true)
6183+
@ImmutableBeans.Property
61846184
HintStrategyTable getHintStrategyTable();
61856185

61866186
/** Sets {@link #getHintStrategyTable()}. */

core/src/main/java/org/apache/calcite/util/ImmutableBeans.java

+10-19
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import java.lang.annotation.RetentionPolicy;
3535
import java.lang.annotation.Target;
3636
import java.lang.invoke.MethodHandle;
37+
import java.lang.reflect.AnnotatedElement;
3738
import java.lang.reflect.InvocationHandler;
3839
import java.lang.reflect.Method;
3940
import java.lang.reflect.Modifier;
@@ -118,8 +119,6 @@ private static <T extends Object> Def<T> makeDef(Class<T> beanClass) {
118119
if (property == null) {
119120
continue;
120121
}
121-
final boolean hasNonnull =
122-
hasAnnotation(method, "org.checkerframework.checker.nullness.qual.NonNull");
123122
final Mode mode;
124123
final Object defaultValue = getDefault(method);
125124
final String methodName = method.getName();
@@ -142,9 +141,10 @@ private static <T extends Object> Def<T> makeDef(Class<T> beanClass) {
142141
throw new IllegalArgumentException("method '" + methodName
143142
+ "' has too many parameters");
144143
}
145-
final boolean required = property.required()
146-
|| propertyType.isPrimitive()
147-
|| hasNonnull;
144+
final boolean required = propertyType.isPrimitive()
145+
|| !hasAnnotation(
146+
method.getAnnotatedReturnType(),
147+
"org.checkerframework.checker.nullness.qual.Nullable");
148148
if (required) {
149149
requiredPropertyNames.add(propertyName);
150150
}
@@ -165,7 +165,8 @@ private static <T extends Object> Def<T> makeDef(Class<T> beanClass) {
165165
return v;
166166
}
167167
if (required && defaultValue == null) {
168-
throw new IllegalArgumentException("property '" + propertyName
168+
throw new IllegalArgumentException("property '" + beanClass.getName()
169+
+ "#" + propertyName
169170
+ "' is required and has no default value");
170171
}
171172
return defaultValue2;
@@ -340,9 +341,9 @@ private static Object value(boolean copy, Object o) {
340341

341342
/** Looks for an annotation by class name.
342343
* Useful if you don't want to depend on the class
343-
* (e.g. "org.checkerframework.checker.nullness.qual.NonNull") at compile time. */
344-
private static boolean hasAnnotation(Method method, String className) {
345-
for (Annotation annotation : method.getDeclaredAnnotations()) {
344+
* (e.g. "org.checkerframework.checker.nullness.qual.Nullable") at compile time. */
345+
private static boolean hasAnnotation(AnnotatedElement element, String className) {
346+
for (Annotation annotation : element.getDeclaredAnnotations()) {
346347
if (annotation.annotationType().getName().equals(className)) {
347348
return true;
348349
}
@@ -419,16 +420,6 @@ private interface Handler<T extends Object> {
419420
@Retention(RetentionPolicy.RUNTIME)
420421
@Target(ElementType.METHOD)
421422
public @interface Property {
422-
/** Whether the property is required.
423-
*
424-
* <p>Properties of type {@code int} and {@code boolean} are always
425-
* required.
426-
*
427-
* <p>If a property is required, it cannot be set to null.
428-
* If it has no default value, calling "get" will give a runtime exception.
429-
*/
430-
boolean required() default false;
431-
432423
/** Whether to make immutable copies of property values. */
433424
boolean makeImmutable() default true;
434425
}

core/src/test/java/org/apache/calcite/test/AbstractMaterializedViewTest.java

+6-4
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@
5454

5555
import com.google.common.collect.ImmutableList;
5656

57+
import org.checkerframework.checker.nullness.qual.Nullable;
58+
5759
import java.util.ArrayList;
5860
import java.util.List;
5961
import java.util.function.Function;
@@ -231,8 +233,8 @@ default void noMat() {
231233
}
232234

233235
@ImmutableBeans.Property
234-
CalciteAssert.SchemaSpec getDefaultSchemaSpec();
235-
Sql withDefaultSchemaSpec(CalciteAssert.SchemaSpec spec);
236+
CalciteAssert.@Nullable SchemaSpec getDefaultSchemaSpec();
237+
Sql withDefaultSchemaSpec(CalciteAssert.@Nullable SchemaSpec spec);
236238

237239
@ImmutableBeans.Property
238240
List<Pair<String, String>> getMaterializations();
@@ -243,8 +245,8 @@ default void noMat() {
243245
Sql withQuery(String query);
244246

245247
@ImmutableBeans.Property
246-
Function<String, Boolean> getChecker();
247-
Sql withChecker(Function<String, Boolean> checker);
248+
@Nullable Function<String, Boolean> getChecker();
249+
Sql withChecker(@Nullable Function<String, Boolean> checker);
248250

249251
@ImmutableBeans.Property
250252
AbstractMaterializedViewTest getTester();

core/src/test/java/org/apache/calcite/util/ImmutableBeanTest.java

+36-34
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
import com.google.common.collect.ImmutableMap;
2121
import com.google.common.collect.ImmutableSet;
2222

23-
import org.checkerframework.checker.nullness.qual.NonNull;
23+
import org.checkerframework.checker.nullness.qual.Nullable;
2424
import org.hamcrest.Matcher;
2525
import org.junit.jupiter.api.Test;
2626

@@ -81,7 +81,8 @@ class ImmutableBeanTest {
8181
throw new AssertionError("expected error, got " + v);
8282
} catch (IllegalArgumentException e) {
8383
assertThat(e.getMessage(),
84-
is("property 'IntSansDefault' is required and has no default value"));
84+
is("property 'org.apache.calcite.util.ImmutableBeanTest$Bean2#IntSansDefault'"
85+
+ " is required and has no default value"));
8586
}
8687
assertThat(b.withIntSansDefault(4).getIntSansDefault(), is(4));
8788

@@ -96,8 +97,8 @@ class ImmutableBeanTest {
9697
throw new AssertionError("expected error, got " + v);
9798
} catch (IllegalArgumentException e) {
9899
assertThat(e.getMessage(),
99-
is("property 'BooleanSansDefault' is required and has no default "
100-
+ "value"));
100+
is("property 'org.apache.calcite.util.ImmutableBeanTest$Bean2#BooleanSansDefault'"
101+
+ " is required and has no default value"));
101102
}
102103
assertThat(b.withBooleanSansDefault(false).isBooleanSansDefault(),
103104
is(false));
@@ -115,8 +116,8 @@ class ImmutableBeanTest {
115116
throw new AssertionError("expected error, got " + v);
116117
} catch (IllegalArgumentException e) {
117118
assertThat(e.getMessage(),
118-
is("property 'StringSansDefault' is required and has no default "
119-
+ "value"));
119+
is("property 'org.apache.calcite.util.ImmutableBeanTest$Bean2#StringSansDefault'"
120+
+ " is required and has no default value"));
120121
}
121122
assertThat(b.withStringSansDefault("a").getStringSansDefault(), is("a"));
122123

@@ -126,7 +127,8 @@ class ImmutableBeanTest {
126127
throw new AssertionError("expected error, got " + v);
127128
} catch (IllegalArgumentException e) {
128129
assertThat(e.getMessage(),
129-
is("property 'NonnullString' is required and has no default value"));
130+
is("property 'org.apache.calcite.util.ImmutableBeanTest$Bean2#NonnullString'"
131+
+ " is required and has no default value"));
130132
}
131133
assertThat(b.withNonnullString("a").getNonnullString(), is("a"));
132134

@@ -564,42 +566,42 @@ interface Bean2 {
564566
boolean isBooleanSansDefault();
565567
Bean2 withBooleanSansDefault(boolean x);
566568

567-
@ImmutableBeans.Property(required = true)
569+
@ImmutableBeans.Property
568570
String getStringSansDefault();
569571
Bean2 withStringSansDefault(String x);
570572

571573
@ImmutableBeans.Property
572-
String getOptionalString();
573-
Bean2 withOptionalString(String s);
574+
@Nullable String getOptionalString();
575+
Bean2 withOptionalString(@Nullable String s);
574576

575-
/** Property is required because it has 'Nonnull' annotation. */
577+
/** Property is required because its return type does not have Nullable annotation. */
576578
@ImmutableBeans.Property
577-
@NonNull String getNonnullString();
579+
String getNonnullString();
578580
Bean2 withNonnullString(String s);
579581

580582
@ImmutableBeans.Property
581583
@ImmutableBeans.StringDefault("abc")
582-
@NonNull String getStringWithDefault();
583-
Bean2 withStringWithDefault(String s);
584+
String getStringWithDefault();
585+
Bean2 withStringWithDefault(@Nullable String s);
584586

585587
@ImmutableBeans.Property
586588
@ImmutableBeans.NullDefault
587-
String getStringWithNullDefault();
588-
Bean2 withStringWithNullDefault(String s);
589+
@Nullable String getStringWithNullDefault();
590+
Bean2 withStringWithNullDefault(@Nullable String s);
589591

590592
@ImmutableBeans.Property
591593
@ImmutableBeans.EnumDefault("RED")
592-
@NonNull Color getColorWithDefault();
593-
Bean2 withColorWithDefault(Color color);
594+
Color getColorWithDefault();
595+
Bean2 withColorWithDefault(@Nullable Color color);
594596

595597
@ImmutableBeans.Property
596598
@ImmutableBeans.NullDefault
597-
Color getColorWithNullDefault();
598-
Bean2 withColorWithNullDefault(Color color);
599+
@Nullable Color getColorWithNullDefault();
600+
Bean2 withColorWithNullDefault(@Nullable Color color);
599601

600602
@ImmutableBeans.Property()
601-
Color getColorOptional();
602-
Bean2 withColorOptional(Color color);
603+
@Nullable Color getColorOptional();
604+
Bean2 withColorOptional(@Nullable Color color);
603605
}
604606

605607
/** Red, blue, green. */
@@ -638,33 +640,33 @@ public interface SubBean extends MyBean {
638640
/** A bean that has collection-valued properties. */
639641
public interface CollectionBean {
640642
@ImmutableBeans.Property(makeImmutable = false)
641-
List<String> list();
643+
@Nullable List<String> list();
642644

643-
CollectionBean withList(List<String> list);
645+
CollectionBean withList(@Nullable List<String> list);
644646

645647
@ImmutableBeans.Property(makeImmutable = true)
646-
List<String> immutableList();
648+
@Nullable List<String> immutableList();
647649

648-
CollectionBean withImmutableList(List<String> list);
650+
CollectionBean withImmutableList(@Nullable List<String> list);
649651

650652
@ImmutableBeans.Property(makeImmutable = false)
651-
Set<String> set();
653+
@Nullable Set<String> set();
652654

653-
CollectionBean withSet(Set<String> set);
655+
CollectionBean withSet(@Nullable Set<String> set);
654656

655657
@ImmutableBeans.Property(makeImmutable = true)
656-
Set<String> immutableSet();
658+
@Nullable Set<String> immutableSet();
657659

658-
CollectionBean withImmutableSet(Set<String> set);
660+
CollectionBean withImmutableSet(@Nullable Set<String> set);
659661

660662
@ImmutableBeans.Property(makeImmutable = false)
661-
Map<String, Integer> map();
663+
@Nullable Map<String, Integer> map();
662664

663-
CollectionBean withMap(Map<String, Integer> map);
665+
CollectionBean withMap(@Nullable Map<String, Integer> map);
664666

665667
@ImmutableBeans.Property(makeImmutable = true)
666-
Map<String, Integer> immutableMap();
668+
@Nullable Map<String, Integer> immutableMap();
667669

668-
CollectionBean withImmutableMap(Map<String, Integer> map);
670+
CollectionBean withImmutableMap(@Nullable Map<String, Integer> map);
669671
}
670672
}

0 commit comments

Comments
 (0)