Skip to content

Commit d9de9b4

Browse files
committed
add custom contract annotation
1 parent 94efefc commit d9de9b4

File tree

4 files changed

+56
-12
lines changed

4 files changed

+56
-12
lines changed

build.gradle

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import java.text.SimpleDateFormat
1+
import net.ltgt.gradle.errorprone.CheckSeverity
22
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
33
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
4-
import net.ltgt.gradle.errorprone.CheckSeverity
4+
5+
import java.text.SimpleDateFormat
56

67
plugins {
78
id 'java'
@@ -257,6 +258,7 @@ tasks.withType(JavaCompile) {
257258
// end state has us with this config turned on - eg all classes
258259
//
259260
//option("NullAway:AnnotatedPackages", "graphql")
261+
option("NullAway:CustomContractAnnotations", "graphql.Contract")
260262
option("NullAway:OnlyNullMarked", "true")
261263
option("NullAway:JSpecifyMode", "true")
262264
}

src/main/java/graphql/Assert.java

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package graphql;
22

3+
import org.jspecify.annotations.NullMarked;
4+
import org.jspecify.annotations.Nullable;
5+
36
import java.util.Collection;
47
import java.util.function.Supplier;
58
import java.util.regex.Pattern;
@@ -8,6 +11,7 @@
811

912
@SuppressWarnings("TypeParameterUnusedInFormals")
1013
@Internal
14+
@NullMarked
1115
public class Assert {
1216

1317
public static <T> T assertNotNullWithNPE(T object, Supplier<String> msg) {
@@ -17,71 +21,82 @@ public static <T> T assertNotNullWithNPE(T object, Supplier<String> msg) {
1721
throw new NullPointerException(msg.get());
1822
}
1923

20-
public static <T> T assertNotNull(T object) {
24+
@Contract("null -> fail")
25+
public static <T> T assertNotNull(@Nullable T object) {
2126
if (object != null) {
2227
return object;
2328
}
2429
return throwAssert("Object required to be not null");
2530
}
2631

27-
public static <T> T assertNotNull(T object, Supplier<String> msg) {
32+
@Contract("null,_ -> fail")
33+
public static <T> T assertNotNull(@Nullable T object, Supplier<String> msg) {
2834
if (object != null) {
2935
return object;
3036
}
3137
return throwAssert(msg.get());
3238
}
3339

34-
public static <T> T assertNotNull(T object, String constantMsg) {
40+
@Contract("null,_ -> fail")
41+
public static <T> T assertNotNull(@Nullable T object, String constantMsg) {
3542
if (object != null) {
3643
return object;
3744
}
3845
return throwAssert(constantMsg);
3946
}
4047

41-
public static <T> T assertNotNull(T object, String msgFmt, Object arg1) {
48+
@Contract("null,_,_ -> fail")
49+
public static <T> T assertNotNull(@Nullable T object, String msgFmt, Object arg1) {
4250
if (object != null) {
4351
return object;
4452
}
4553
return throwAssert(msgFmt, arg1);
4654
}
4755

48-
public static <T> T assertNotNull(T object, String msgFmt, Object arg1, Object arg2) {
56+
@Contract("null,_,_,_ -> fail")
57+
public static <T> T assertNotNull(@Nullable T object, String msgFmt, Object arg1, Object arg2) {
4958
if (object != null) {
5059
return object;
5160
}
5261
return throwAssert(msgFmt, arg1, arg2);
5362
}
5463

55-
public static <T> T assertNotNull(T object, String msgFmt, Object arg1, Object arg2, Object arg3) {
64+
@Contract("null,_,_,_,_ -> fail")
65+
public static <T> T assertNotNull(@Nullable T object, String msgFmt, Object arg1, Object arg2, Object arg3) {
5666
if (object != null) {
5767
return object;
5868
}
5969
return throwAssert(msgFmt, arg1, arg2, arg3);
6070
}
6171

6272

63-
public static <T> void assertNull(T object, Supplier<String> msg) {
73+
@Contract("!null,_ -> fail")
74+
public static <T> void assertNull(@Nullable T object, Supplier<String> msg) {
6475
if (object == null) {
6576
return;
6677
}
6778
throwAssert(msg.get());
6879
}
6980

70-
public static <T> void assertNull(T object) {
81+
@Contract("!null -> fail")
82+
public static <T> void assertNull(@Nullable Object object) {
7183
if (object == null) {
7284
return;
7385
}
7486
throwAssert("Object required to be null");
7587
}
7688

89+
@Contract("-> fail")
7790
public static <T> T assertNeverCalled() {
7891
return throwAssert("Should never been called");
7992
}
8093

94+
@Contract("_,_-> fail")
8195
public static <T> T assertShouldNeverHappen(String format, Object... args) {
8296
return throwAssert("Internal error: should never happen: %s", format(format, args));
8397
}
8498

99+
@Contract("-> fail")
85100
public static <T> T assertShouldNeverHappen() {
86101
return throwAssert("Internal error: should never happen");
87102
}
@@ -93,6 +108,7 @@ public static <T> Collection<T> assertNotEmpty(Collection<T> collection) {
93108
return collection;
94109
}
95110

111+
// @Contract("null,_-> fail")
96112
public static <T> Collection<T> assertNotEmpty(Collection<T> collection, Supplier<String> msg) {
97113
if (collection == null || collection.isEmpty()) {
98114
throwAssert(msg.get());
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package graphql;
2+
3+
import java.lang.annotation.Documented;
4+
import java.lang.annotation.ElementType;
5+
import java.lang.annotation.Target;
6+
7+
/**
8+
* Custom contract annotation used for jspecify and NullAway checks.
9+
*
10+
* This is the same as Spring does: we don't want any additional dependencies, therefore we define our own Contract annotation.
11+
*
12+
* @see <a href="https://raw.githubusercontent.com/spring-projects/spring-framework/refs/heads/main/spring-core/src/main/java/org/springframework/lang/Contract.java">Spring Framework Contract</a>
13+
* @see <a href="https://github.com/JetBrains/java-annotations/blob/master/src/jvmMain/java/org/jetbrains/annotations/Contract.java">org.jetbrains.annotations.Contract</a>
14+
* @see <a href="https://github.com/uber/NullAway/wiki/Configuration#custom-contract-annotations">
15+
* NullAway custom contract annotations</a>
16+
*/
17+
@Documented
18+
@Target(ElementType.METHOD)
19+
public @interface Contract {
20+
21+
/**
22+
* Describing the contract between call arguments and the returned value.
23+
*/
24+
String value() default "";
25+
26+
}

src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -305,8 +305,8 @@ public void deferredOnFieldValue(String resultKey, FieldValueInfo fieldValueInfo
305305
CallStack callStack = getCallStack(parameters);
306306
boolean ready = callStack.lock.callLocked(() -> {
307307
callStack.deferredFragmentRootFieldsFetched.add(fieldValueInfo);
308-
AlternativeCallContext alternativeCallContext = Assert.assertNotNull(parameters.getDeferredCallContext());
309-
return callStack.deferredFragmentRootFieldsFetched.size() == alternativeCallContext.getFields();
308+
Assert.assertNotNull(parameters.getDeferredCallContext());
309+
return callStack.deferredFragmentRootFieldsFetched.size() == parameters.getDeferredCallContext().getFields();
310310
});
311311
if (ready) {
312312
int curLevel = parameters.getPath().getLevel();

0 commit comments

Comments
 (0)