Skip to content

Commit e576f74

Browse files
authored
Merge pull request #120 from strykeforce/kotlin-support
Add nullability annotations to Java client library
2 parents 6f48105 + 6d6eab1 commit e576f74

File tree

14 files changed

+105
-76
lines changed

14 files changed

+105
-76
lines changed

client/build.gradle.kts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,14 @@ repositories {
1414
}
1515

1616
dependencies {
17-
val wpiVersion = "2022.2.1"
18-
val slf4jVersion = "1.7.33"
17+
val wpiVersion = "2022.4.1"
18+
val slf4jVersion = "1.7.36"
1919
val junitVersion = "5.8.2"
2020
// This dependency is used internally, and not exposed to consumers on their own compile classpath.
2121
implementation("com.squareup.moshi:moshi:1.13.0")
2222
implementation("edu.wpi.first.ntcore:ntcore-java:$wpiVersion")
2323
implementation("org.slf4j:slf4j-api:$slf4jVersion")
24-
implementation("org.jetbrains:annotations:22.0.0")
24+
implementation("org.jetbrains:annotations:23.0.0")
2525

2626

2727
// Use JUnit Jupiter API for testing.
@@ -33,7 +33,7 @@ dependencies {
3333
testRuntimeOnly("edu.wpi.first.ntcore:ntcore-jni:$wpiVersion:osxx86-64")
3434
testRuntimeOnly("edu.wpi.first.ntcore:ntcore-jni:$wpiVersion:linuxx86-64")
3535
testRuntimeOnly("edu.wpi.first.wpiutil:wpiutil-java:$wpiVersion")
36-
testRuntimeOnly("ch.qos.logback:logback-classic:1.2.10")
36+
testRuntimeOnly("ch.qos.logback:logback-classic:1.2.11")
3737
}
3838

3939
java {

client/src/main/java/org/strykeforce/deadeye/Deadeye.java

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,13 @@
4141
public class Deadeye<T extends TargetData> {
4242

4343
static final Logger logger = LoggerFactory.getLogger(Deadeye.class);
44-
private static volatile Link link;
45-
private final NetworkTable cameraTable;
46-
private final String id;
47-
private final DeadeyeJsonAdapter<T> jsonAdapter;
48-
private TargetDataListener<T> targetDataListener;
49-
private T targetData;
44+
private static volatile @Nullable Link link;
45+
private final @NotNull NetworkTable cameraTable;
46+
private final @NotNull String id;
47+
private final @NotNull DeadeyeJsonAdapter<T> jsonAdapter;
48+
private @NotNull TargetDataListener<T> targetDataListener = data -> {
49+
};
50+
private @NotNull T targetData;
5051

5152
/**
5253
* Constructs an instance of {@code Deadeye} and initializes a connection to the associated
@@ -55,11 +56,10 @@ public class Deadeye<T extends TargetData> {
5556
* @param id the camera id, i.e. the Deadeye unit letter followed by the camera number, for
5657
* example "A0".
5758
* @param cls the {@code TargetData} Java class corresponding to the Deadeye pipeline type.
58-
* @throws NullPointerException if the {@code cls} is {@code null}
5959
* @throws IllegalArgumentException if the {@code id} is not a letter followed by a 0-4 digit
6060
* @throws IllegalArgumentException if the {@code cls} is not a valid {@code TargetData} class
6161
*/
62-
public Deadeye(String id, Class<T> cls) {
62+
public Deadeye(@NotNull String id, @NotNull Class<T> cls) {
6363
this(id, cls, NetworkTableInstance.getDefault(), null);
6464
}
6565

@@ -78,13 +78,12 @@ public Deadeye(String id, Class<T> cls) {
7878
* @param linkAddress the IP address the Deadeye daemon should send data to. If null, this client
7979
* will reuse a previously configured address or attempt to automatically
8080
* detect the correct IP address.
81-
* @throws NullPointerException if the {@code cls} is {@code null}
8281
* @throws IllegalArgumentException if the {@code id} is not a letter followed by a 0-4 digit
8382
* @throws IllegalArgumentException if the {@code cls} is not a valid {@code TargetData} class
8483
* @throws IllegalArgumentException if the {@code linkAddress} supplied more than once and does
8584
* not match address already in use
8685
*/
87-
public Deadeye(String id, Class<T> cls, String linkAddress) {
86+
public Deadeye(@NotNull String id, @NotNull Class<T> cls, @Nullable String linkAddress) {
8887
this(id, cls, NetworkTableInstance.getDefault(), linkAddress);
8988
}
9089

@@ -98,11 +97,10 @@ public Deadeye(String id, Class<T> cls, String linkAddress) {
9897
* example "A0".
9998
* @param cls the {@code TargetData} Java class corresponding to the Deadeye pipeline type.
10099
* @param nti the NetworkTables instance to connect through.
101-
* @throws NullPointerException if the {@code cls} or {@code nti} is {@code null}
102100
* @throws IllegalArgumentException if the {@code id} is not a letter followed by a 0-4 digit
103101
* @throws IllegalArgumentException if the {@code cls} is not a valid {@code TargetData} class
104102
*/
105-
public Deadeye(String id, Class<T> cls, NetworkTableInstance nti) {
103+
public Deadeye(@NotNull String id, @NotNull Class<T> cls, @NotNull NetworkTableInstance nti) {
106104
this(id, cls, nti, null);
107105
}
108106

@@ -121,14 +119,15 @@ public Deadeye(String id, Class<T> cls, NetworkTableInstance nti) {
121119
* @param nti the NetworkTables instance to connect through.
122120
* @param linkAddress the IP address the Deadeye daemon should send data to. If null, this client
123121
* will attempt to automatically detect the correct IP address.
124-
* @throws NullPointerException if the {@code cls} or {@code nti} is {@code null}
125122
* @throws IllegalArgumentException if the {@code id} is not a letter followed by a 0-4 digit
126123
* @throws IllegalArgumentException if the {@code cls} is not a valid {@code TargetData} class
127124
* @throws IllegalArgumentException if the {@code linkAddress} supplied more than once and does
128125
* not match address already in use
129126
*/
130127
@SuppressWarnings("unchecked")
131-
public Deadeye(String id, Class<T> cls, NetworkTableInstance nti, String linkAddress) {
128+
public Deadeye(
129+
@NotNull String id, @NotNull Class<T> cls, @NotNull NetworkTableInstance nti,
130+
@Nullable String linkAddress) {
132131
Objects.requireNonNull(cls, "cls must not be null");
133132
Objects.requireNonNull(nti, "nti must not be null");
134133
if (!Pattern.matches("^[A-Za-z][0-4]$", id)) {
@@ -143,6 +142,7 @@ public Deadeye(String id, Class<T> cls, NetworkTableInstance nti, String linkAdd
143142
}
144143
}
145144

145+
Link link = Objects.requireNonNull(Deadeye.link);
146146
if (linkAddress != null && !link.getAddress().equals(linkAddress)) {
147147
throw new IllegalArgumentException(
148148
"supplied linkAddress does not match address already in use");
@@ -191,6 +191,7 @@ static JsonAdapter<Capture> getCaptureJsonAdapter() {
191191
*
192192
* @return the associated {@code TargetDataListener}.
193193
*/
194+
@NotNull
194195
public TargetDataListener<T> getTargetDataListener() {
195196
return targetDataListener;
196197
}
@@ -201,7 +202,7 @@ public TargetDataListener<T> getTargetDataListener() {
201202
*
202203
* @param targetDataListener class to receive target data
203204
*/
204-
public void setTargetDataListener(TargetDataListener<T> targetDataListener) {
205+
public void setTargetDataListener(@NotNull TargetDataListener<T> targetDataListener) {
205206
this.targetDataListener = targetDataListener;
206207
}
207208

@@ -215,16 +216,15 @@ public void setTargetDataListener(TargetDataListener<T> targetDataListener) {
215216
*/
216217
public void handleTargetData(BufferedSource source) throws IOException {
217218
targetData = jsonAdapter.fromJson(source);
218-
if (targetDataListener != null) {
219-
targetDataListener.onTargetData(targetData);
220-
}
219+
targetDataListener.onTargetData(targetData);
221220
}
222221

223222
/**
224223
* Gets the most recent {@code TargetData} received by this {@code Deadeye} instance.
225224
*
226225
* @return the last valid target data update.
227226
*/
227+
@NotNull
228228
public T getTargetData() {
229229
return targetData;
230230
}
@@ -323,7 +323,12 @@ public Capture getCapture() {
323323
return new Capture();
324324
}
325325

326-
Link getLink() {
326+
/**
327+
* Provide Link for testing.
328+
*
329+
* @return the {@code Link} or {@code null} if a Deadeye unit has not been initialized yet
330+
*/
331+
@Nullable Link getLink() {
327332
return link;
328333
}
329334

@@ -356,7 +361,7 @@ public Info(boolean logging, String pipeline, String version) {
356361
}
357362

358363
@Override
359-
public boolean equals(Object o) {
364+
public boolean equals(@Nullable Object o) {
360365
if (this == o) {
361366
return true;
362367
}
@@ -375,7 +380,7 @@ public int hashCode() {
375380
}
376381

377382
@Override
378-
public String toString() {
383+
public @NotNull String toString() {
379384
return "Info{"
380385
+ "logging="
381386
+ logging
@@ -417,7 +422,9 @@ public static class Capture {
417422
@Json(name = "h")
418423
public final int height;
419424

420-
public Capture() {this("ERROR",0,0,0);}
425+
public Capture() {
426+
this("ERROR", 0, 0, 0);
427+
}
421428

422429
public Capture(String type, int frameRate, int width, int height) {
423430
this.type = type;
@@ -427,7 +434,7 @@ public Capture(String type, int frameRate, int width, int height) {
427434
}
428435

429436
@Override
430-
public boolean equals(Object o) {
437+
public boolean equals(@Nullable Object o) {
431438
if (this == o) {
432439
return true;
433440
}
@@ -445,7 +452,7 @@ public int hashCode() {
445452
}
446453

447454
@Override
448-
public String toString() {
455+
public @NotNull String toString() {
449456
return "Capture{" +
450457
"type='" + type + '\'' +
451458
", frameRate=" + frameRate +

client/src/main/java/org/strykeforce/deadeye/DeadeyeJsonAdapter.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import okio.BufferedSource;
44

55
import java.io.IOException;
6+
import org.jetbrains.annotations.NotNull;
67

78
/**
89
* A {@code TargetData} class implements {@code DeadeyeJsonAdapter} to enable
@@ -17,13 +18,13 @@ public interface DeadeyeJsonAdapter<T extends TargetData> {
1718
* @return a new {@code TargetData} object, initialized with supplied JSON.
1819
* @throws IOException if a deserialization error occurs.
1920
*/
20-
T fromJson(BufferedSource source) throws IOException;
21+
@NotNull T fromJson(@NotNull BufferedSource source) throws IOException;
2122

2223
/**
2324
* Serializes this {@code TargetData} to JSON.
2425
* @param targetData the object to serialize.
2526
* @return this object in JSON format.
2627
* @throws IOException if a serialization error occurs.
2728
*/
28-
String toJson(T targetData) throws IOException;
29+
@NotNull String toJson(@NotNull T targetData) throws IOException;
2930
}

client/src/main/java/org/strykeforce/deadeye/Link.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ public void run() {
9090
*
9191
* @return the configured client address.
9292
*/
93-
public String getAddress() {
93+
String getAddress() {
9494
return address;
9595
}
9696

client/src/main/java/org/strykeforce/deadeye/LinkConfig.java

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,16 @@
1616
import java.util.Objects;
1717
import java.util.stream.Collectors;
1818
import org.jetbrains.annotations.NotNull;
19+
import org.jetbrains.annotations.Nullable;
1920

2021
class LinkConfig {
2122

2223
static final LinkConfig DEFAULT = new LinkConfig("10.27.67.2", 5800, true);
2324
final int port;
2425
final boolean enabled;
25-
final String address;
26+
final @Nullable String address;
2627

27-
LinkConfig(@NotNull String address, int port, boolean enabled) {
28+
LinkConfig(@Nullable String address, int port, boolean enabled) {
2829
this.address = address;
2930
this.port = port;
3031
this.enabled = enabled;
@@ -48,6 +49,7 @@ static LinkConfig getConfig(@NotNull NetworkTable deadeyeTable) {
4849
Link.logger.warn("more than one entry unsupported, using first:\n\t{}", json);
4950
}
5051

52+
// only use first config for now
5153
var config = configs.get(0);
5254
if (config.address == null || config.port == 0 || !config.address.equals(
5355
addressToInetAddress(config.address).getHostAddress())) {
@@ -84,6 +86,7 @@ static List<InetAddress> getSiteLocalAddresses() {
8486
}
8587
}
8688

89+
@NotNull
8790
static InetAddress addressToInetAddress(String address) {
8891
InetAddress inetAddress = null;
8992
var invalid = true;
@@ -110,7 +113,7 @@ static private InetAddress getDefaultInetAddress() {
110113
}
111114
}
112115

113-
LinkConfig withAddress(String address) {
116+
@NotNull LinkConfig withAddress(@NotNull String address) {
114117
return new LinkConfig(address, this.port, this.enabled);
115118
}
116119

@@ -137,7 +140,7 @@ boolean isValid() {
137140
return addressValid && portValid;
138141
}
139142

140-
void save(NetworkTable deadeyeTable) {
143+
void save(@NotNull NetworkTable deadeyeTable) {
141144
JsonAdapter<List<LinkConfig>> jsonAdapter = getConfigJsonAdapter();
142145
deadeyeTable.getEntry(Link.LINK_ENTRY)
143146
.setString(jsonAdapter.toJson(Collections.singletonList(this)));
@@ -152,8 +155,9 @@ public boolean equals(Object o) {
152155
if (o == null || getClass() != o.getClass()) {
153156
return false;
154157
}
155-
LinkConfig config = (LinkConfig) o;
156-
return port == config.port && enabled == config.enabled && address.equals(config.address);
158+
LinkConfig that = (LinkConfig) o;
159+
return port == that.port && enabled == that.enabled && Objects.equals(address,
160+
that.address);
157161
}
158162

159163
@Override
@@ -162,7 +166,7 @@ public int hashCode() {
162166
}
163167

164168
@Override
165-
public String toString() {
169+
public @NotNull String toString() {
166170
return "LinkConfig{" +
167171
"port=" + port +
168172
", enabled=" + enabled +

client/src/main/java/org/strykeforce/deadeye/MinAreaRectTargetData.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import okio.Buffer;
99
import okio.BufferedSource;
1010
import org.jetbrains.annotations.NotNull;
11+
import org.jetbrains.annotations.Nullable;
1112

1213
/**
1314
* A <code>MinAreaRectTargetData</code> represents data returned from a Deadeye
@@ -89,18 +90,19 @@ public MinAreaRectTargetData(
8990
*
9091
* @return the area of the bounding box.
9192
*/
93+
@SuppressWarnings("unused")
9294
public double area() {
9395
return width * height;
9496
}
9597

9698
@SuppressWarnings("rawtypes")
9799
@Override
98-
public DeadeyeJsonAdapter getJsonAdapter() {
100+
public @NotNull DeadeyeJsonAdapter getJsonAdapter() {
99101
return new JsonAdapterImpl();
100102
}
101103

102104
@Override
103-
public boolean equals(Object o) {
105+
public boolean equals(@Nullable Object o) {
104106
if (this == o) {
105107
return true;
106108
}
@@ -126,7 +128,7 @@ public int hashCode() {
126128
}
127129

128130
@Override
129-
public String toString() {
131+
public @NotNull String toString() {
130132
return "MinAreaRectTargetData{"
131133
+ "angle="
132134
+ angle
@@ -161,9 +163,9 @@ private static class JsonAdapterImpl implements DeadeyeJsonAdapter<MinAreaRectTa
161163
private static final JsonReader.Options OPTIONS = JsonReader.Options.of("id", "sn", "v", "d");
162164

163165
@Override
164-
public MinAreaRectTargetData fromJson(BufferedSource source) throws IOException {
166+
public @NotNull MinAreaRectTargetData fromJson(@NotNull BufferedSource source) throws IOException {
165167
JsonReader reader = JsonReader.of(source);
166-
String id = null;
168+
String id = "Z0";
167169
int serial = -1;
168170
boolean valid = false;
169171
double[] data = new double[DATA_LENGTH];
@@ -208,7 +210,7 @@ public MinAreaRectTargetData fromJson(BufferedSource source) throws IOException
208210
}
209211

210212
@Override
211-
public String toJson(MinAreaRectTargetData targetData) throws IOException {
213+
public @NotNull String toJson(@NotNull MinAreaRectTargetData targetData) throws IOException {
212214
Buffer buffer = new Buffer();
213215
JsonWriter writer = JsonWriter.of(buffer);
214216
writer.beginObject();

0 commit comments

Comments
 (0)