typetools / typetools/checker-framework
KeyFor annotation lost in stream
Open
@smillst is already working on this.
Since May 20, 2021.
- Dominant language
- Java
- Stars
- 1.1k
- Forks
- 440
- Avg merge
- 1d 12h
- Merged PRs (30d)
- 134
Description
In the below code I get a nullness warning when accessing endTimes inside the stream even though cattegoryInfo is marked as having the same keys as endTimes. It looks like the call to entrySet doesn't pass along the KeyFor annotation of the generic type. When I separate the call to entrySet to be a separate variable I cannot annotate the variable with a KeyFor{{"endtimes"}) without checker giving a warning.
This is using checker 3.13.0 and OpenJDK 11.
/home/jpschewe/projects/checker-bugs/src/main/java/net/mtu/eggplant/checker/keyfor_stream/KeyForStream.java:43: error: [argument] incompatible argument for parameter endTime of FinalistDBRow.
endTimes.get(entry.getKey()),
^
found : @Initialized @Nullable LocalTime
required: @Initialized @NonNull LocalTime
FinalistDBRow.java
package net.mtu.eggplant.checker.keyfor_stream;
import java.time.LocalTime;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public final class FinalistDBRow {
public FinalistDBRow(final LocalTime time,
final LocalTime endTime,
final Map<String, Integer> categories) {
this.time = time;
this.endTime = endTime;
this.categories = Collections.unmodifiableMap(new HashMap<>(categories));
}
private final LocalTime time;
private final LocalTime endTime;
private final Map<String, Integer> categories;
}
KeyForStream.java
package net.mtu.eggplant.checker.keyfor_stream;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.stream.Collectors;
import java.time.LocalTime;
import org.checkerframework.checker.nullness.qual.KeyFor;
import static org.checkerframework.checker.nullness.util.NullnessUtil.castNonNull;
public class KeyForStream {
public void method(final Connection connection) throws SQLException {
try (
PreparedStatement getSchedule = connection.prepareStatement("SELECT category, judge_time, judge_end_time, team_number FROM finalist_schedule WHERE tournament = ? AND division = ?")) {
getSchedule.setInt(1, 5);
getSchedule.setString(2, "awardGroup");
final Map<LocalTime, LocalTime> endTimes = new HashMap<>();
final Map<@KeyFor("endTimes") LocalTime, Map<String, Integer>> categoryInfo = new HashMap<>();
try (ResultSet schedule = getSchedule.executeQuery()) {
while (schedule.next()) {
final String categoryName = castNonNull(schedule.getString(1));
final LocalTime judgeTime = castNonNull(schedule.getTime(2)).toLocalTime();
final LocalTime judgeEndTime = castNonNull(schedule.getTime(3)).toLocalTime();
final Integer teamNumber = Integer.valueOf(schedule.getInt(4));
endTimes.put(judgeTime, judgeEndTime);
categoryInfo.computeIfAbsent(judgeTime, k -> new HashMap<>()).put(categoryName, teamNumber);
} // foreach result
} // allocate ResultSet
final List<FinalistDBRow> rows = categoryInfo.entrySet().stream() //
.map(entry -> new FinalistDBRow(entry.getKey(),
endTimes.get(entry.getKey()),
entry.getValue())) //
.collect(Collectors.toList());
}
}
}
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.