--- old/src/java.base/share/classes/java/net/DatagramSocket.java 2020-02-14 09:51:54.000000000 +0000 +++ new/src/java.base/share/classes/java/net/DatagramSocket.java 2020-02-14 09:51:54.000000000 +0000 @@ -25,6 +25,7 @@ package java.net; +import java.io.FileDescriptor; import java.io.IOException; import java.io.UncheckedIOException; import java.nio.channels.DatagramChannel; @@ -124,6 +125,7 @@ /* * The implementation of this DatagramSocket. */ + @SuppressWarnings("deprecation") private final DatagramSocketImpl impl; /** @@ -252,7 +254,7 @@ * the subclass wishes to use on the DatagramSocket. * @since 1.4 */ - protected DatagramSocket(DatagramSocketImpl impl) { + protected DatagramSocket(@SuppressWarnings("deprecation")DatagramSocketImpl impl) { if (impl == null) throw new NullPointerException(); this.impl = impl; @@ -283,13 +285,6 @@ * @since 1.4 */ public DatagramSocket(SocketAddress bindaddr) throws SocketException { - // Special case initialization for the DatagramChannel socket adaptor. - if (this instanceof sun.nio.ch.DatagramSocketAdaptor) { - this.impl = null; // no DatagramSocketImpl - this.oldImpl = false; - return; - } - // create a datagram socket. boolean multicast = (this instanceof MulticastSocket); this.impl = createImpl(multicast); @@ -363,7 +358,7 @@ * Return true if the given DatagramSocketImpl is an "old" impl. An old impl * is one that doesn't implement the abstract methods added in Java SE 1.4. */ - private static boolean checkOldImpl(DatagramSocketImpl impl) { + private static boolean checkOldImpl(@SuppressWarnings("deprecation")DatagramSocketImpl impl) { // DatagramSocketImpl.peekData() is a protected method, therefore we need to use // getDeclaredMethod, therefore we need permission to access the member try { @@ -388,6 +383,7 @@ * Creates a DatagramSocketImpl. * @param multicast true if the DatagramSocketImpl is for a MulticastSocket */ + @SuppressWarnings("deprecation") private static DatagramSocketImpl createImpl(boolean multicast) throws SocketException { DatagramSocketImpl impl; DatagramSocketImplFactory factory = DatagramSocket.factory; @@ -408,7 +404,7 @@ * @throws SocketException if creating the socket fails * @since 1.4 */ - final DatagramSocketImpl getImpl() throws SocketException { + final @SuppressWarnings("deprecation")DatagramSocketImpl getImpl() throws SocketException { if (!created) { synchronized (this) { if (!created) { @@ -1503,7 +1499,7 @@ return options; } try { - DatagramSocketImpl impl = getImpl(); + @SuppressWarnings("deprecation")DatagramSocketImpl impl = getImpl(); options = Collections.unmodifiableSet(impl.supportedOptions()); } catch (IOException e) { options = Collections.emptySet(); @@ -1512,4 +1508,57 @@ return options; } } + + /** + * An instance of a {@code DatagramSocketImpl} whose methods all throw an + * {@UncheckedIOException}. + * + *

Suitable for use by subclasses of {@code DatagramSocket} and + * {@code MulticastSocket}, that wish to provide their own complete + * implementation, without delegating to the enclosing {@code impl} class. + * For example: + * + *

{@code
+     * class CustomDatagramSocket extends DatagramSocket {
+     *         CustomDatagramSocket() {
+     *             super(DatagramSocket.THROWING_DGRM_IMPL);
+     *         }
+     *
+     *         // override of all methods of DatagramSocket ...
+     *     }
+     * }
+ */ + // TODO: find a better name + @SuppressWarnings("deprecation") + protected static final DatagramSocketImpl THROWING_DGRM_IMPL = new DatagramSocketImpl() { + private final void throwUncheckedIOException() { + throw new UncheckedIOException(new IOException("unimplemented")); + } + @Override protected void create() { throwUncheckedIOException(); } + @Override protected void bind(int p, InetAddress a) { throwUncheckedIOException(); } + @Override protected void send(DatagramPacket p) { throwUncheckedIOException(); } + @Override protected void connect(InetAddress a, int p) { throwUncheckedIOException(); } + @Override protected void disconnect() { throwUncheckedIOException(); } + @Override protected int getLocalPort() { throwUncheckedIOException(); return 0; } + @Override protected FileDescriptor getFileDescriptor() { throwUncheckedIOException(); return null; } + @Override protected int peek(InetAddress i) { throwUncheckedIOException(); return 0; } + @Override protected int peekData(DatagramPacket p) { throwUncheckedIOException(); return 0; } + @Override protected void receive(DatagramPacket p) { throwUncheckedIOException(); } + @Override protected void setTTL(byte ttl) { throwUncheckedIOException(); } + @Override protected byte getTTL() { throwUncheckedIOException(); return 0; } + @Override protected void setTimeToLive(int ttl) { throwUncheckedIOException(); } + @Override protected int getTimeToLive() { throwUncheckedIOException(); return 0; } + @Override protected void join(InetAddress a) { throwUncheckedIOException(); } + @Override protected void leave(InetAddress a) { throwUncheckedIOException(); } + @Override protected void joinGroup(SocketAddress a, + NetworkInterface b) { throwUncheckedIOException(); } + @Override protected void leaveGroup(SocketAddress a, + NetworkInterface b) { throwUncheckedIOException(); } + @Override protected void close() { throwUncheckedIOException(); } + @Override public void setOption(int o, Object v) { throwUncheckedIOException(); } + @Override public Object getOption(int o) { throwUncheckedIOException(); return null; } + @Override protected void setOption(SocketOption n, T v) { throwUncheckedIOException(); } + @Override protected T getOption(SocketOption n) { throwUncheckedIOException(); return null; } + @Override protected Set> supportedOptions() { throwUncheckedIOException(); return null; } + }; } --- old/src/java.base/share/classes/java/net/MulticastSocket.java 2020-02-14 09:51:59.000000000 +0000 +++ new/src/java.base/share/classes/java/net/MulticastSocket.java 2020-02-14 09:51:58.000000000 +0000 @@ -30,6 +30,7 @@ import java.nio.channels.MulticastChannel; import java.util.Collections; import java.util.Enumeration; +import java.util.Objects; import java.util.Set; /** @@ -218,10 +219,6 @@ public MulticastSocket(SocketAddress bindaddr) throws IOException { super((SocketAddress) null); - // No further initialization when this is a DatagramChannel socket adaptor - if (this instanceof sun.nio.ch.DatagramSocketAdaptor) - return; - // Enable SO_REUSEADDR before binding setReuseAddress(true); @@ -237,6 +234,19 @@ } /** + * Creates an unbound multicast socket with the given + * {@code DatagramSocketImpl}. + * + * @param impl an instance of a {@code DatagramSocketImpl} + * the subclass wishes to use for the MulticastSocket + * @throws NullPointerException if the given {@code impl} is {@code null} + * @since 15 + */ + protected MulticastSocket(@SuppressWarnings("deprecation")DatagramSocketImpl impl) { + super(Objects.requireNonNull(impl)); + } + + /** * The lock on the socket's TTL. This is for set/getTTL and * send(packet,ttl). */ @@ -819,7 +829,7 @@ return options; } try { - DatagramSocketImpl impl = getImpl(); + @SuppressWarnings("deprecation")DatagramSocketImpl impl = getImpl(); options = Collections.unmodifiableSet(impl.supportedOptions()); } catch (SocketException ex) { options = Collections.emptySet(); --- old/src/java.base/share/classes/java/net/DatagramSocketImpl.java 2020-02-14 09:52:04.000000000 +0000 +++ new/src/java.base/share/classes/java/net/DatagramSocketImpl.java 2020-02-14 09:52:03.000000000 +0000 @@ -35,7 +35,7 @@ * @author Pavani Diwanji * @since 1.1 */ - +@Deprecated(since="15") public abstract class DatagramSocketImpl implements SocketOptions { /** --- old/src/java.base/share/classes/java/net/DatagramSocketImplFactory.java 2020-02-14 09:52:07.000000000 +0000 +++ new/src/java.base/share/classes/java/net/DatagramSocketImplFactory.java 2020-02-14 09:52:07.000000000 +0000 @@ -41,5 +41,6 @@ * @return a new instance of {@code DatagramSocketImpl}. * @see java.net.DatagramSocketImpl */ + @SuppressWarnings("deprecation") DatagramSocketImpl createDatagramSocketImpl(); } --- old/src/java.base/share/classes/java/net/AbstractPlainDatagramSocketImpl.java 2020-02-14 09:52:10.000000000 +0000 +++ new/src/java.base/share/classes/java/net/AbstractPlainDatagramSocketImpl.java 2020-02-14 09:52:10.000000000 +0000 @@ -46,6 +46,7 @@ * @author Pavani Diwanji */ +@SuppressWarnings("deprecation") abstract class AbstractPlainDatagramSocketImpl extends DatagramSocketImpl { /* timeout value for receive() */ --- old/src/java.base/share/classes/sun/nio/ch/DatagramSocketAdaptor.java 2020-02-14 09:52:13.000000000 +0000 +++ new/src/java.base/share/classes/sun/nio/ch/DatagramSocketAdaptor.java 2020-02-14 09:52:13.000000000 +0000 @@ -74,7 +74,7 @@ private volatile int timeout; private DatagramSocketAdaptor(DatagramChannelImpl dc) throws IOException { - super(/*SocketAddress*/null); + super(DatagramSocket.THROWING_DGRM_IMPL); this.dc = dc; } --- old/src/java.base/unix/classes/java/net/DefaultDatagramSocketImplFactory.java 2020-02-14 09:52:16.000000000 +0000 +++ new/src/java.base/unix/classes/java/net/DefaultDatagramSocketImplFactory.java 2020-02-14 09:52:16.000000000 +0000 @@ -58,11 +58,11 @@ * @param isMulticast true if this impl if for a MutlicastSocket * @return a new instance of a DatagramSocketImpl. */ + @SuppressWarnings("deprecation") static DatagramSocketImpl createDatagramSocketImpl(boolean isMulticast /*unused on unix*/) throws SocketException { if (prefixImplClass != null) { try { - @SuppressWarnings("deprecation") DatagramSocketImpl result = (DatagramSocketImpl)prefixImplClass.newInstance(); return result; } catch (Exception e) { --- /dev/null 2020-02-14 09:52:19.000000000 +0000 +++ new/test/jdk/java/net/DatagramSocketImpl/NoWarningSubclasses.java 2020-02-14 09:52:18.000000000 +0000 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 1998, 2019, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8765432 + * @summary Ensures that there is a warning-free way to compile subclasses + * of DatagramSocket and MulticastSocket + * @compile -Xlint:all -Werror NoWarningSubclasses.java + */ + +import java.net.DatagramSocket; +import java.net.MulticastSocket; + +public class NoWarningSubclasses { + + static class TestDatagramSocket extends DatagramSocket { + TestDatagramSocket() { + super(DatagramSocket.THROWING_DGRM_IMPL); + } + } + + static class TestMulticastSocket extends MulticastSocket { + TestMulticastSocket() { + super(DatagramSocket.THROWING_DGRM_IMPL); + } + } +}