Index: /trunk/src/org/openstreetmap/josm/tools/PlatformHook.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/tools/PlatformHook.java	(revision 12218)
+++ /trunk/src/org/openstreetmap/josm/tools/PlatformHook.java	(revision 12219)
@@ -2,4 +2,7 @@
 package org.openstreetmap.josm.tools;
 
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Dimension;
 import java.awt.GraphicsEnvironment;
 import java.io.BufferedReader;
@@ -13,7 +16,14 @@
 import java.security.cert.CertificateException;
 import java.security.cert.X509Certificate;
+import java.text.DateFormat;
+import java.util.Date;
 import java.util.List;
 
+import javax.swing.JOptionPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.ExtendedDialog;
 import org.openstreetmap.josm.io.CertificateAmendment.CertAmend;
+import org.openstreetmap.josm.tools.date.DateUtils;
 
 /**
@@ -224,3 +234,69 @@
      */
     List<File> getDefaultProj4NadshiftDirectories();
+
+    /**
+     * Determines if the JVM is OpenJDK-based.
+     * @return {@code true} if {@code java.home} contains "openjdk", {@code false} otherwise
+     * @since 12219
+     */
+    default boolean isOpenJDK() {
+        String javaHome = System.getProperty("java.home");
+        return javaHome != null && javaHome.contains("openjdk");
+    }
+
+    /**
+     * Asks user to update its version of Java.
+     * @param updVersion target update version
+     * @param url download URL
+     * @param major true for a migration towards a major version of Java (8->9), false otherwise
+     * @param eolDate the EOL/expiration date
+     * @since 12219
+     */
+    default void askUpdateJava(String updVersion, String url, String eolDate, boolean major) {
+        ExtendedDialog ed = new ExtendedDialog(
+                Main.parent,
+                tr("Outdated Java version"),
+                new String[]{tr("OK"), tr("Update Java"), tr("Cancel")});
+        // Check if the dialog has not already been permanently hidden by user
+        if (!ed.toggleEnable("askUpdateJava"+updVersion).toggleCheckState()) {
+            ed.setButtonIcons(new String[]{"ok", "java", "cancel"}).setCancelButton(3);
+            ed.setMinimumSize(new Dimension(480, 300));
+            ed.setIcon(JOptionPane.WARNING_MESSAGE);
+            StringBuilder content = new StringBuilder(tr("You are running version {0} of Java.",
+                    "<b>"+System.getProperty("java.version")+"</b>")).append("<br><br>");
+            if ("Sun Microsystems Inc.".equals(System.getProperty("java.vendor")) && !isOpenJDK()) {
+                content.append("<b>").append(tr("This version is no longer supported by {0} since {1} and is not recommended for use.",
+                        "Oracle", eolDate)).append("</b><br><br>");
+            }
+            content.append("<b>")
+                   .append(major ?
+                        tr("JOSM will soon stop working with this version; we highly recommend you to update to Java {0}.", updVersion) :
+                        tr("You may face critical Java bugs; we highly recommend you to update to Java {0}.", updVersion))
+                   .append("</b><br><br>")
+                   .append(tr("Would you like to update now ?"));
+            ed.setContent(content.toString());
+
+            if (ed.showDialog().getValue() == 2) {
+                try {
+                    openUrl(url);
+                } catch (IOException e) {
+                    Main.warn(e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Checks if the running version of Java has expired, proposes to user to update it if needed.
+     * @since 12219
+     */
+    default void checkExpiredJava() {
+        Date expiration = Utils.getJavaExpirationDate();
+        if (expiration != null && expiration.before(new Date())) {
+            String version = Utils.getJavaLatestVersion();
+            askUpdateJava(version != null ? version : "latest",
+                    Main.pref.get("java.update.url", "https://www.java.com/download"),
+                    DateUtils.getDateFormat(DateFormat.MEDIUM).format(expiration), false);
+        }
+    }
 }
Index: /trunk/src/org/openstreetmap/josm/tools/PlatformHookOsx.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/tools/PlatformHookOsx.java	(revision 12218)
+++ /trunk/src/org/openstreetmap/josm/tools/PlatformHookOsx.java	(revision 12219)
@@ -79,4 +79,5 @@
             Main.warn("Failed to register with OSX: " + ex);
         }
+        checkExpiredJava();
     }
 
Index: /trunk/src/org/openstreetmap/josm/tools/PlatformHookUnixoid.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/tools/PlatformHookUnixoid.java	(revision 12218)
+++ /trunk/src/org/openstreetmap/josm/tools/PlatformHookUnixoid.java	(revision 12219)
@@ -5,5 +5,4 @@
 
 import java.awt.Desktop;
-import java.awt.Dimension;
 import java.awt.event.KeyEvent;
 import java.io.BufferedReader;
@@ -20,15 +19,9 @@
 import java.util.Locale;
 
-import javax.swing.JOptionPane;
-
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.gui.ExtendedDialog;
-import org.openstreetmap.josm.gui.util.GuiHelper;
 
 /**
- * {@code PlatformHook} base implementation.
- *
- * Don't write (Main.platform instanceof PlatformHookUnixoid) because other platform
- * hooks are subclasses of this class.
+ * {@code PlatformHook} implementation for Unix systems.
+ * @since 1023
  */
 public class PlatformHookUnixoid implements PlatformHook {
@@ -97,14 +90,4 @@
             return false;
         }
-    }
-
-    /**
-     * Determines if the JVM is OpenJDK-based.
-     * @return {@code true} if {@code java.home} contains "openjdk", {@code false} otherwise
-     * @since 6951
-     */
-    public static boolean isOpenJDK() {
-        String javaHome = System.getProperty("java.home");
-        return javaHome != null && javaHome.contains("openjdk");
     }
 
@@ -200,5 +183,5 @@
     }
 
-    protected String buildOSDescription() {
+    private String buildOSDescription() {
         String osName = System.getProperty("os.name");
         if ("Linux".equalsIgnoreCase(osName)) {
@@ -246,5 +229,5 @@
     }
 
-    protected static class LinuxReleaseInfo {
+    private static class LinuxReleaseInfo {
         private final String path;
         private final String descriptionField;
@@ -254,13 +237,13 @@
         private final String prefix;
 
-        public LinuxReleaseInfo(String path, String descriptionField, String idField, String releaseField) {
+        LinuxReleaseInfo(String path, String descriptionField, String idField, String releaseField) {
             this(path, descriptionField, idField, releaseField, false, null);
         }
 
-        public LinuxReleaseInfo(String path) {
+        LinuxReleaseInfo(String path) {
             this(path, null, null, null, true, null);
         }
 
-        public LinuxReleaseInfo(String path, String prefix) {
+        LinuxReleaseInfo(String path, String prefix) {
             this(path, null, null, null, true, prefix);
         }
@@ -275,5 +258,6 @@
         }
 
-        @Override public String toString() {
+        @Override
+        public String toString() {
             return "ReleaseInfo [path=" + path + ", descriptionField=" + descriptionField +
                     ", idField=" + idField + ", releaseField=" + releaseField + ']';
@@ -331,39 +315,4 @@
     }
 
-    // Method unused, but kept for translation already done. To reuse during Java 9 migration
-    protected void askUpdateJava(final String version, final String url) {
-        GuiHelper.runInEDTAndWait(() -> {
-            ExtendedDialog ed = new ExtendedDialog(
-                    Main.parent,
-                    tr("Outdated Java version"),
-                    new String[]{tr("OK"), tr("Update Java"), tr("Cancel")});
-            // Check if the dialog has not already been permanently hidden by user
-            if (!ed.toggleEnable("askUpdateJava9").toggleCheckState()) {
-                ed.setButtonIcons(new String[]{"ok", "java", "cancel"}).setCancelButton(3);
-                ed.setMinimumSize(new Dimension(480, 300));
-                ed.setIcon(JOptionPane.WARNING_MESSAGE);
-                StringBuilder content = new StringBuilder(tr("You are running version {0} of Java.", "<b>"+version+"</b>"))
-                        .append("<br><br>");
-                if ("Sun Microsystems Inc.".equals(System.getProperty("java.vendor")) && !isOpenJDK()) {
-                    content.append("<b>").append(tr("This version is no longer supported by {0} since {1} and is not recommended for use.",
-                            "Oracle", tr("April 2015"))).append("</b><br><br>"); // TODO: change date once Java 8 EOL is announced
-                }
-                content.append("<b>")
-                       .append(tr("JOSM will soon stop working with this version; we highly recommend you to update to Java {0}.", "8"))
-                       .append("</b><br><br>")
-                       .append(tr("Would you like to update now ?"));
-                ed.setContent(content.toString());
-
-                if (ed.showDialog().getValue() == 2) {
-                    try {
-                        openUrl(url);
-                    } catch (IOException e) {
-                        Main.warn(e);
-                    }
-                }
-            }
-        });
-    }
-
     /**
      * Get the dot directory <code>~/.josm</code>.
Index: /trunk/src/org/openstreetmap/josm/tools/PlatformHookWindows.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/tools/PlatformHookWindows.java	(revision 12218)
+++ /trunk/src/org/openstreetmap/josm/tools/PlatformHookWindows.java	(revision 12219)
@@ -180,4 +180,9 @@
             }
         }
+    }
+
+    @Override
+    public void startupHook() {
+        checkExpiredJava();
     }
 
Index: /trunk/src/org/openstreetmap/josm/tools/Utils.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/tools/Utils.java	(revision 12218)
+++ /trunk/src/org/openstreetmap/josm/tools/Utils.java	(revision 12219)
@@ -32,5 +32,7 @@
 import java.security.PrivilegedAction;
 import java.text.Bidi;
+import java.text.DateFormat;
 import java.text.MessageFormat;
+import java.text.ParseException;
 import java.util.AbstractCollection;
 import java.util.AbstractList;
@@ -39,4 +41,5 @@
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Date;
 import java.util.Iterator;
 import java.util.List;
@@ -1646,3 +1649,36 @@
         return Integer.parseInt(version.substring(bPos > -1 ? bPos + 1 : pPos + 1, version.length()));
     }
+
+    /**
+     * Returns the JRE expiration date.
+     * @return the JRE expiration date, or null
+     * @since 12219
+     */
+    public static Date getJavaExpirationDate() {
+        try {
+            Object value = Class.forName("com.sun.deploy.config.BuiltInProperties").getDeclaredField("JRE_EXPIRATION_DATE").get(null);
+            if (value instanceof String) {
+                return DateFormat.getDateInstance(3, Locale.US).parse((String) value);
+            }
+        } catch (IllegalArgumentException | ReflectiveOperationException | SecurityException | ParseException e) {
+            Main.debug(e);
+        }
+        return null;
+    }
+
+    /**
+     * Returns the latest version of Java, from Oracle website.
+     * @return the latest version of Java, from Oracle website
+     * @since 12219
+     */
+    public static String getJavaLatestVersion() {
+        try {
+            return HttpClient.create(
+                    new URL(Main.pref.get("java.baseline.version.url", "http://javadl-esd-secure.oracle.com/update/baseline.version")))
+                    .connect().fetchContent().split("\n")[0];
+        } catch (IOException e) {
+            Main.error(e);
+        }
+        return null;
+    }
 }
