From ef47635d5a27b003937d865ad9067dbd151db888 Mon Sep 17 00:00:00 2001 From: Stuart Marks Date: Wed, 4 Jun 2025 16:14:31 +0000 Subject: [PATCH] 8358015: Fix SequencedMap sequenced view method specifications Reviewed-by: jpai, bchristi --- .../share/classes/java/util/AbstractMap.java | 8 +++ .../share/classes/java/util/SequencedMap.java | 65 +++++++++++++++++-- .../util/SequencedCollection/BasicMap.java | 10 +-- 3 files changed, 71 insertions(+), 12 deletions(-) diff --git a/src/java.base/share/classes/java/util/AbstractMap.java b/src/java.base/share/classes/java/util/AbstractMap.java index 7c0b4d9dd1b..afc5b339354 100644 --- a/src/java.base/share/classes/java/util/AbstractMap.java +++ b/src/java.base/share/classes/java/util/AbstractMap.java @@ -877,6 +877,14 @@ public abstract class AbstractMap implements Map { */ /* non-public */ abstract static class ViewCollection implements Collection { UnsupportedOperationException uoe() { return new UnsupportedOperationException(); } + // convert null entry return values into NSEE + static > T nsee(T entry) { + if (entry == null) { + throw new NoSuchElementException(); + } else { + return entry; + } + } abstract Collection view(); public boolean add(E t) { throw uoe(); } diff --git a/src/java.base/share/classes/java/util/SequencedMap.java b/src/java.base/share/classes/java/util/SequencedMap.java index 6bff204b65d..cf27b82896b 100644 --- a/src/java.base/share/classes/java/util/SequencedMap.java +++ b/src/java.base/share/classes/java/util/SequencedMap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -263,8 +263,15 @@ public interface SequencedMap extends Map { * * @implSpec * The implementation in this interface returns a {@code SequencedSet} instance - * that behaves as follows. Its {@link SequencedSet#add add} and {@link - * SequencedSet#addAll addAll} methods throw {@link UnsupportedOperationException}. + * that behaves as follows. Its {@link SequencedSet#add add}, {@link + * SequencedSet#addAll addAll}, {@link SequencedSet#addFirst addFirst}, and {@link + * SequencedSet#addLast addLast} methods throw {@link UnsupportedOperationException}. + * Its {@link SequencedSet#getFirst getFirst} and {@link SequencedSet#getLast getLast} + * methods are implemented in terms of the {@link #firstEntry firstEntry} and {@link + * #lastEntry lastEntry} methods of this interface, respectively. Its {@link + * SequencedSet#removeFirst removeFirst} and {@link SequencedSet#removeLast removeLast} + * methods are implemented in terms of the {@link #pollFirstEntry pollFirstEntry} and + * {@link #pollLastEntry pollLastEntry} methods of this interface, respectively. * Its {@link SequencedSet#reversed reversed} method returns the {@link * #sequencedKeySet sequencedKeySet} view of the {@link #reversed reversed} view of * this map. Each of its other methods calls the corresponding method of the {@link @@ -286,6 +293,16 @@ public interface SequencedMap extends Map { public int hashCode() { return view().hashCode(); } + public void addFirst(K k) { throw new UnsupportedOperationException(); } + public void addLast(K k) { throw new UnsupportedOperationException(); } + public K getFirst() { return nsee(SequencedMap.this.firstEntry()).getKey(); } + public K getLast() { return nsee(SequencedMap.this.lastEntry()).getKey(); } + public K removeFirst() { + return nsee(SequencedMap.this.pollFirstEntry()).getKey(); + } + public K removeLast() { + return nsee(SequencedMap.this.pollLastEntry()).getKey(); + } } return new SeqKeySet(); } @@ -295,8 +312,15 @@ public interface SequencedMap extends Map { * * @implSpec * The implementation in this interface returns a {@code SequencedCollection} instance - * that behaves as follows. Its {@link SequencedCollection#add add} and {@link - * SequencedCollection#addAll addAll} methods throw {@link UnsupportedOperationException}. + * that behaves as follows. Its {@link SequencedCollection#add add}, {@link + * SequencedCollection#addAll addAll}, {@link SequencedCollection#addFirst addFirst}, and {@link + * SequencedCollection#addLast addLast} methods throw {@link UnsupportedOperationException}. + * Its {@link SequencedCollection#getFirst getFirst} and {@link SequencedCollection#getLast getLast} + * methods are implemented in terms of the {@link #firstEntry firstEntry} and {@link + * #lastEntry lastEntry} methods of this interface, respectively. Its {@link + * SequencedCollection#removeFirst removeFirst} and {@link SequencedCollection#removeLast removeLast} + * methods are implemented in terms of the {@link #pollFirstEntry pollFirstEntry} and + * {@link #pollLastEntry pollLastEntry} methods of this interface, respectively. * Its {@link SequencedCollection#reversed reversed} method returns the {@link * #sequencedValues sequencedValues} view of the {@link #reversed reversed} view of * this map. Its {@link Object#equals equals} and {@link Object#hashCode hashCode} methods @@ -313,6 +337,16 @@ public interface SequencedMap extends Map { public SequencedCollection reversed() { return SequencedMap.this.reversed().sequencedValues(); } + public void addFirst(V v) { throw new UnsupportedOperationException(); } + public void addLast(V v) { throw new UnsupportedOperationException(); } + public V getFirst() { return nsee(SequencedMap.this.firstEntry()).getValue(); } + public V getLast() { return nsee(SequencedMap.this.lastEntry()).getValue(); } + public V removeFirst() { + return nsee(SequencedMap.this.pollFirstEntry()).getValue(); + } + public V removeLast() { + return nsee(SequencedMap.this.pollLastEntry()).getValue(); + } } return new SeqValues(); } @@ -322,8 +356,15 @@ public interface SequencedMap extends Map { * * @implSpec * The implementation in this interface returns a {@code SequencedSet} instance - * that behaves as follows. Its {@link SequencedSet#add add} and {@link - * SequencedSet#addAll addAll} methods throw {@link UnsupportedOperationException}. + * that behaves as follows. Its {@link SequencedSet#add add}, {@link + * SequencedSet#addAll addAll}, {@link SequencedSet#addFirst addFirst}, and {@link + * SequencedSet#addLast addLast} methods throw {@link UnsupportedOperationException}. + * Its {@link SequencedSet#getFirst getFirst} and {@link SequencedSet#getLast getLast} + * methods are implemented in terms of the {@link #firstEntry firstEntry} and {@link + * #lastEntry lastEntry} methods of this interface, respectively. Its {@link + * SequencedSet#removeFirst removeFirst} and {@link SequencedSet#removeLast removeLast} + * methods are implemented in terms of the {@link #pollFirstEntry pollFirstEntry} and + * {@link #pollLastEntry pollLastEntry} methods of this interface, respectively. * Its {@link SequencedSet#reversed reversed} method returns the {@link * #sequencedEntrySet sequencedEntrySet} view of the {@link #reversed reversed} view of * this map. Each of its other methods calls the corresponding method of the {@link @@ -346,6 +387,16 @@ public interface SequencedMap extends Map { public int hashCode() { return view().hashCode(); } + public void addFirst(Map.Entry e) { throw new UnsupportedOperationException(); } + public void addLast(Map.Entry e) { throw new UnsupportedOperationException(); } + public Map.Entry getFirst() { return nsee(SequencedMap.this.firstEntry()); } + public Map.Entry getLast() { return nsee(SequencedMap.this.lastEntry()); } + public Map.Entry removeFirst() { + return nsee(SequencedMap.this.pollFirstEntry()); + } + public Map.Entry removeLast() { + return nsee(SequencedMap.this.pollLastEntry()); + } } return new SeqEntrySet(); } diff --git a/test/jdk/java/util/SequencedCollection/BasicMap.java b/test/jdk/java/util/SequencedCollection/BasicMap.java index 028ae4e42c2..40bc2aa99dd 100644 --- a/test/jdk/java/util/SequencedCollection/BasicMap.java +++ b/test/jdk/java/util/SequencedCollection/BasicMap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -563,12 +563,12 @@ public class BasicMap { SequencedMap objMap = (SequencedMap)(SequencedMap)map; assertThrows(CCE, () -> { objMap.put(new Object(), 99); }); assertThrows(CCE, () -> { objMap.put("x", new Object()); }); - assertThrows(CCE, () -> { objMap.sequencedEntrySet().getFirst().setValue(new Object()); }); - assertThrows(CCE, () -> { objMap.sequencedEntrySet().reversed().getFirst().setValue(new Object()); }); + assertThrows(CCE, () -> { objMap.sequencedEntrySet().iterator().next().setValue(new Object()); }); + assertThrows(CCE, () -> { objMap.sequencedEntrySet().reversed().iterator().next().setValue(new Object()); }); assertThrows(CCE, () -> { objMap.reversed().put(new Object(), 99); }); assertThrows(CCE, () -> { objMap.reversed().put("x", new Object()); }); - assertThrows(CCE, () -> { objMap.reversed().sequencedEntrySet().getFirst().setValue(new Object()); }); - assertThrows(CCE, () -> { objMap.reversed().sequencedEntrySet().reversed().getFirst().setValue(new Object()); }); + assertThrows(CCE, () -> { objMap.reversed().sequencedEntrySet().iterator().next().setValue(new Object()); }); + assertThrows(CCE, () -> { objMap.reversed().sequencedEntrySet().reversed().iterator().next().setValue(new Object()); }); } public void checkEntry(Map.Entry entry, String key, Integer value) {