commits@javamail.java.net

[javamail~mercurial:823] Support LogRecord.setMillis being deprecated in JDK 9 - K7091

From: <shannon_at_java.net>
Date: Tue, 26 Apr 2016 22:28:39 +0000

Project: javamail
Repository: mercurial
Revision: 823
Author: shannon
Date: 2016-04-26 21:52:54 UTC
Link:

Log Message:
------------
NPE in Tomcat ClassLoader causes Session.getInstance to fail - bug 7356
Support LogRecord.setMillis being deprecated in JDK 9 - K7091
CompactFormatter preload nested classes for GLASSFISH-21258.
Suppress override warnings on interfaces (JDK-6954234).
MailHandler bytecode verifier should skip loading optional classes.
MailHandlerDemo add missing -custom flag to help text.
MailHandlerDemo deal with readConfiguration side-effects.
MailHandlerDemo add classloader debugging.
Remove missing SummaryNameFormatter references.
SeverityComparator include additional JLS reference.
SeverityComparator revert bitwise inclusive OR.
Add testDeclaredClasses to all tests.
MailHandlerTest add tests for super errormanager.

(From Jason)


Revisions:
----------
822
823


Modified Paths:
---------------
doc/release/CHANGES.txt
mail/src/main/java/javax/mail/Session.java
logging/src/main/java/MailHandlerDemo.java
logging/src/main/java/README.txt
logging/src/main/java/maildemo.properties
mail/src/main/java/com/sun/mail/util/logging/CompactFormatter.java
mail/src/main/java/com/sun/mail/util/logging/DurationFilter.java
mail/src/main/java/com/sun/mail/util/logging/LogManagerProperties.java
mail/src/main/java/com/sun/mail/util/logging/MailHandler.java
mail/src/main/java/com/sun/mail/util/logging/SeverityComparator.java
mail/src/test/java/com/sun/mail/util/logging/AbstractLogging.java
mail/src/test/java/com/sun/mail/util/logging/CollectorFormatterTest.java
mail/src/test/java/com/sun/mail/util/logging/CompactFormatterTest.java
mail/src/test/java/com/sun/mail/util/logging/DurationFilterTest.java
mail/src/test/java/com/sun/mail/util/logging/LogManagerPropertiesTest.java
mail/src/test/java/com/sun/mail/util/logging/MailHandlerTest.java
mail/src/test/java/com/sun/mail/util/logging/SeverityComparatorTest.java


Diffs:
------
diff -r b0d9c4977915 -r d015eeb4439f doc/release/CHANGES.txt
--- a/doc/release/CHANGES.txt Tue Apr 19 15:41:47 2016 -0700
+++ b/doc/release/CHANGES.txt Mon Apr 25 17:10:47 2016 -0700
@@ -25,6 +25,7 @@
 K 7151 InternetAddress.parse fails for valid domain literal address
 K 7238 unsolicited FETCH response *must* invalidate X-GM-LABELS in cache
 K 7332 MimeBodyPart.isMimeType returns false if type header can't be parsed
+K 7356 NPE in Tomcat ClassLoader causes Session.getInstance to fail
 
 
                   CHANGES IN THE 1.5.5 RELEASE

diff -r b0d9c4977915 -r d015eeb4439f mail/src/main/java/javax/mail/Session.java
--- a/mail/src/main/java/javax/mail/Session.java Tue Apr 19 15:41:47 2016 -0700
+++ b/mail/src/main/java/javax/mail/Session.java Mon Apr 25 17:10:47 2016 -0700
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 1997-2015 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997-2016 Oracle and/or its affiliates. All rights reserved.
  *
  * The contents of this file are subject to the terms of either the GNU
  * General Public License Version 2 only ("GPL") or the Common Development
@@ -1229,7 +1229,15 @@
             return AccessController.doPrivileged(
                     new PrivilegedExceptionAction<InputStream>() {
                         public InputStream run() throws IOException {
- return c.getResourceAsStream(name);
+ try {
+ return c.getResourceAsStream(name);
+ } catch (RuntimeException e) {
+ // gracefully handle ClassLoader bugs (Tomcat)
+ IOException ioex = new IOException(
+ "ClassLoader.getResourceAsStream failed");
+ ioex.initCause(e);
+ throw ioex;
+ }
                         }
                     }
             );


diff -r d015eeb4439f -r 3ed6a59fffe8 doc/release/CHANGES.txt
--- a/doc/release/CHANGES.txt Mon Apr 25 17:10:47 2016 -0700
+++ b/doc/release/CHANGES.txt Tue Apr 26 14:52:54 2016 -0700
@@ -19,6 +19,7 @@
                   ----------------------------
 The following bugs have been fixed in the 1.5.6 release.
 
+K 7091 Support LogRecord.setMillis being deprecated in JDK 9
 K 7097 Create common super class for logging tests
 K 7140 NPE by APOP detection when no greeting banner
 K 7150 Make IMAPProtocol.handleLoginResult protected

diff -r d015eeb4439f -r 3ed6a59fffe8 logging/src/main/java/MailHandlerDemo.java
--- a/logging/src/main/java/MailHandlerDemo.java Mon Apr 25 17:10:47 2016 -0700
+++ b/logging/src/main/java/MailHandlerDemo.java Tue Apr 26 14:52:54 2016 -0700
@@ -1,6 +1,6 @@
 /*
- * Copyright (c) 2009-2015 Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2009-2015 Jason Mehrens. All Rights Reserved.
+ * Copyright (c) 2009-2016 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009-2016 Jason Mehrens. All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -65,18 +65,22 @@
     private static final Logger LOGGER = Logger.getLogger(CLASS_NAME);
 
     /**
+ * Runs the demo.
+ *
      * @param args the command line arguments
+ * @throws IOException if there is a problem.
      */
- public static void main(String[] args) {
+ public static void main(String[] args) throws IOException {
         List<String> l = Arrays.asList(args);
         if (l.contains("/?") || l.contains("-?") || l.contains("-help")) {
             LOGGER.info("Usage: java MailHandlerDemo "
- + "[[-all] | [-body] | [-debug] | [-low] | [-simple] "
- + "| [-pushlevel] | [-pushfilter] | [-pushnormal]"
- + "| [-pushonly]] "
+ + "[[-all] | [-body] | [-custom] | [-debug] | [-low] "
+ + "| [-simple] | [-pushlevel] | [-pushfilter] "
+ + "| [-pushnormal] | [-pushonly]] "
                     + "\n\n"
                     + "-all\t\t: Execute all demos.\n"
                     + "-body\t\t: An email with all records and only a body.\n"
+ + "-custom\t\t: An email with attachments and dynamic names.\n"
                     + "-debug\t\t: Output basic debug information about the JVM "
                     + "and log configuration.\n"
                     + "-low\t\t: Generates multiple emails due to low capacity."
@@ -97,7 +101,7 @@
                     + "priority emails when the push level is triggered and "
                     + "normal priority when flushed.\n");
         } else {
- init(l); //may create log messages.
+ final boolean debug = init(l); //may create log messages.
             try {
                 LOGGER.log(Level.FINEST, "This is the finest part of the demo.",
                         new MessagingException("Fake JavaMail issue."));
@@ -122,6 +126,11 @@
             } finally {
                 closeHandlers();
             }
+
+ //Force parse errors. This does have side effects.
+ if (debug && getConfigLocation() != null) {
+ LogManager.getLogManager().readConfiguration();
+ }
         }
     }
 
@@ -144,16 +153,24 @@
         }
 
         try {
+ err.println(prefix + ": java.version="
+ + System.getProperty("java.version"));
             err.println(prefix + ": LOGGER=" + LOGGER.getLevel());
- err.println(prefix + ": JVM id " + ManagementFactory.getRuntimeMXBean().getName());
- err.println(prefix + ": java.security.debug=" + System.getProperty("java.security.debug"));
+ err.println(prefix + ": JVM id "
+ + ManagementFactory.getRuntimeMXBean().getName());
+ err.println(prefix + ": java.security.debug="
+ + System.getProperty("java.security.debug"));
             SecurityManager sm = System.getSecurityManager();
             if (sm != null) {
- err.println(prefix + ": SecurityManager.class=" + sm.getClass().getName());
+ err.println(prefix + ": SecurityManager.class="
+ + sm.getClass().getName());
+ err.println(prefix + ": SecurityManager classLoader="
+ + toString(sm.getClass().getClassLoader()));
                 err.println(prefix + ": SecurityManager.toString=" + sm);
             } else {
                 err.println(prefix + ": SecurityManager.class=null");
                 err.println(prefix + ": SecurityManager.toString=null");
+ err.println(prefix + ": SecurityManager classLoader=null");
             }
 
             String policy = System.getProperty("java.security.policy");
@@ -179,17 +196,23 @@
                 err.println(prefix + ": canRead=" + f.canRead());
                 err.println(prefix + ": lastModified="
                         + new java.util.Date(f.lastModified()));
- //Force any errors. This is only safe if key is present.
- manager.readConfiguration();
             } else {
- err.println(prefix + ": " + key + " is not set as a system property.");
+ err.println(prefix + ": " + key
+ + " is not set as a system property.");
             }
- err.println(prefix + ": LogManager.class=" + manager.getClass().getName());
+ err.println(prefix + ": LogManager.class="
+ + manager.getClass().getName());
+ err.println(prefix + ": LogManager classLoader="
+ + toString(manager.getClass().getClassLoader()));
             err.println(prefix + ": LogManager.toString=" + manager);
- err.println(prefix + ": MailHandler classLoader=" + MailHandler.class.getClassLoader());
- err.println(prefix + ": Context ClassLoader=" + Thread.currentThread().getContextClassLoader());
- err.println(prefix + ": Session ClassLoader=" + Session.class.getClassLoader());
- err.println(prefix + ": DataHandler ClassLoader=" + DataHandler.class.getClassLoader());
+ err.println(prefix + ": MailHandler classLoader="
+ + toString(MailHandler.class.getClassLoader()));
+ err.println(prefix + ": Context ClassLoader="
+ + toString(Thread.currentThread().getContextClassLoader()));
+ err.println(prefix + ": Session ClassLoader="
+ + toString(Session.class.getClassLoader()));
+ err.println(prefix + ": DataHandler ClassLoader="
+ + toString(DataHandler.class.getClassLoader()));
 
             final String p = MailHandler.class.getName();
             key = p.concat(".mail.to");
@@ -237,6 +260,22 @@
     }
 
     /**
+ * Gets the class loader list.
+ *
+ * @param cl the class loader or null.
+ * @return the class loader list.
+ */
+ private static String toString(ClassLoader cl) {
+ StringBuilder buf = new StringBuilder();
+ buf.append(cl);
+ while (cl != null) {
+ cl = cl.getParent();
+ buf.append("<-").append(cl);
+ }
+ return buf.toString();
+ }
+
+ /**
      * Gets a formatting string describing the given handler.
      *
      * @param prefix the output prefix.
@@ -295,6 +334,8 @@
             err.print(prefix + ": ");
             error.printStackTrace(err);
         }
+
+ buf.append(", ").append(toString(h.getClass().getClassLoader()));
         return buf.toString();
     }
 
@@ -500,8 +541,9 @@
      * Sets up the demos that will run.
      *
      * @param l the list of arguments.
+ * @return true if debug is on.
      */
- private static void init(List<String> l) {
+ private static boolean init(List<String> l) {
         l = new ArrayList<String>(l);
         Session session = Session.getInstance(System.getProperties());
         boolean all = l.remove("-all") || l.isEmpty();
@@ -538,7 +580,8 @@
         }
 
         boolean fallback = applyFallbackSettings();
- if (l.remove("-debug") || session.getDebug()) {
+ boolean debug = l.remove("-debug") || session.getDebug();
+ if (debug) {
             checkConfig(CLASS_NAME, session.getDebugOut());
         }
 
@@ -549,6 +592,7 @@
         if (fallback) {
             LOGGER.info("Check your user temp dir for output.");
         }
+ return debug;
     }
 
     /**

diff -r d015eeb4439f -r 3ed6a59fffe8 logging/src/main/java/README.txt
--- a/logging/src/main/java/README.txt Mon Apr 25 17:10:47 2016 -0700
+++ b/logging/src/main/java/README.txt Tue Apr 26 14:52:54 2016 -0700
@@ -58,6 +58,7 @@
                         Options:
                             -all : Execute all demos.
                             -body : An email with all records and only a body.
+ -custom : An email with attachments and dynamic names.
                             -debug : Output basic debug information about the
                                         JVM and log configuration.
                             -low : Generates multiple emails due to low

diff -r d015eeb4439f -r 3ed6a59fffe8 logging/src/main/java/maildemo.properties
--- a/logging/src/main/java/maildemo.properties Mon Apr 25 17:10:47 2016 -0700
+++ b/logging/src/main/java/maildemo.properties Tue Apr 26 14:52:54 2016 -0700
@@ -1,6 +1,6 @@
 #
-# Copyright (c) 2009-2014 Oracle and/or its affiliates. All rights reserved.
-# Copyright (c) 2009-2014 Jason Mehrens. All Rights Reserved.
+# Copyright (c) 2009-2016 Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2009-2016 Jason Mehrens. All Rights Reserved.
 #
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions
@@ -58,8 +58,8 @@
 # No filters.
 #com.sun.mail.util.logging.MailHandler.attachment.filters = null, null
 
-# One formatter and one string.
-#com.sun.mail.util.logging.MailHandler.attachment.names = SummaryNameFormatter, error.xml
+# Formatter class name or strings.
+#com.sun.mail.util.logging.MailHandler.attachment.names = simple.txt, error.xml
 
 
 # Store messages on error by installing the FileErrorManager (demo code).

diff -r d015eeb4439f -r 3ed6a59fffe8 mail/src/main/java/com/sun/mail/util/logging/CompactFormatter.java
--- a/mail/src/main/java/com/sun/mail/util/logging/CompactFormatter.java Mon Apr 25 17:10:47 2016 -0700
+++ b/mail/src/main/java/com/sun/mail/util/logging/CompactFormatter.java Tue Apr 26 14:52:54 2016 -0700
@@ -1,8 +1,8 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 2013-2015 Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2013-2015 Jason Mehrens. All rights reserved.
+ * Copyright (c) 2013-2016 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013-2016 Jason Mehrens. All rights reserved.
  *
  * The contents of this file are subject to the terms of either the GNU
  * General Public License Version 2 only ("GPL") or the Common Development
@@ -65,6 +65,22 @@
  * @since JavaMail 1.5.2
  */
 public class CompactFormatter extends java.util.logging.Formatter {
+ /**
+ * Load any declared classes to workaround GLASSFISH-21258.
+ */
+ static {
+ loadDeclaredClasses();
+ }
+
+ /**
+ * Used to load declared classes encase class loader doesn't allow loading
+ * during JVM termination. This method is used with unit testing.
+ *
+ * @return an array of classes never null.
+ */
+ private static Class<?>[] loadDeclaredClasses() {
+ return new Class<?>[]{Alternate.class};
+ }
 
     /**
      * Holds the java.util.Formatter pattern.
@@ -720,6 +736,7 @@
             this.right = String.valueOf(right);
         }
 
+ @SuppressWarnings("override") //JDK-6954234
         public void formatTo(java.util.Formatter formatter, int flags,
                 int width, int precision) {
 

diff -r d015eeb4439f -r 3ed6a59fffe8 mail/src/main/java/com/sun/mail/util/logging/DurationFilter.java
--- a/mail/src/main/java/com/sun/mail/util/logging/DurationFilter.java Mon Apr 25 17:10:47 2016 -0700
+++ b/mail/src/main/java/com/sun/mail/util/logging/DurationFilter.java Tue Apr 26 14:52:54 2016 -0700
@@ -1,8 +1,8 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2015 Jason Mehrens. All rights reserved.
+ * Copyright (c) 2015-2016 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015-2016 Jason Mehrens. All rights reserved.
  *
  * The contents of this file are subject to the terms of either the GNU
  * General Public License Version 2 only ("GPL") or the Common Development
@@ -211,6 +211,7 @@
      * @return true if allowed; false otherwise.
      * @throws NullPointerException if given record is null.
      */
+ @SuppressWarnings("override") //JDK-6954234
     public boolean isLoggable(final LogRecord record) {
         return accept(record.getMillis());
     }

diff -r d015eeb4439f -r 3ed6a59fffe8 mail/src/main/java/com/sun/mail/util/logging/LogManagerProperties.java
--- a/mail/src/main/java/com/sun/mail/util/logging/LogManagerProperties.java Mon Apr 25 17:10:47 2016 -0700
+++ b/mail/src/main/java/com/sun/mail/util/logging/LogManagerProperties.java Tue Apr 26 14:52:54 2016 -0700
@@ -1,8 +1,8 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 2009-2015 Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2009-2015 Jason Mehrens. All rights reserved.
+ * Copyright (c) 2009-2016 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009-2016 Jason Mehrens. All rights reserved.
  *
  * The contents of this file are subject to the terms of either the GNU
  * General Public License Version 2 only ("GPL") or the Common Development
@@ -735,6 +735,7 @@
     private static ClassLoader[] getClassLoaders() {
         return AccessController.doPrivileged(new PrivilegedAction<ClassLoader[]>() {
 
+ @SuppressWarnings("override") //JDK-6954234
             public ClassLoader[] run() {
                 final ClassLoader[] loaders = new ClassLoader[2];
                 try {

diff -r d015eeb4439f -r 3ed6a59fffe8 mail/src/main/java/com/sun/mail/util/logging/MailHandler.java
--- a/mail/src/main/java/com/sun/mail/util/logging/MailHandler.java Mon Apr 25 17:10:47 2016 -0700
+++ b/mail/src/main/java/com/sun/mail/util/logging/MailHandler.java Tue Apr 26 14:52:54 2016 -0700
@@ -607,6 +607,7 @@
      *
      * @param record description of the log event.
      */
+ @Override
     public void publish(final LogRecord record) {
         /**
          * It is possible for the handler to be closed after the
@@ -679,7 +680,7 @@
             try {
                 final String msg;
                 if (record != null) {
- final SimpleFormatter f = new SimpleFormatter();
+ final Formatter f = createSimpleFormatter();
                     msg = "Log record " + record.getSequenceNumber()
                             + " was not published. "
                             + head(f) + format(f, record) + tail(f, "");
@@ -812,6 +813,7 @@
      * a push.
      * @see #push()
      */
+ @Override
     public void flush() {
         push(false, ErrorManager.FLUSH_FAILURE);
     }
@@ -829,6 +831,7 @@
      * caller does not have <tt>LoggingPermission("control")</tt>.
      * @see #flush()
      */
+ @Override
     public void close() {
         checkAccess(); //Ensure setLevel works before clearing the buffer.
         Message msg = null;
@@ -929,7 +932,7 @@
     /**
      * Sets the error manager on this handler and the super handler. In secure
      * environments the super call may not be allowed which is not a failure
- * condition as it is an attempt to free the unused the error manager.
+ * condition as it is an attempt to free the unused handler error manager.
      *
      * @param em a non null error manager.
      * @throws NullPointerException if the given error manager is null.
@@ -1195,7 +1198,7 @@
         if (password == null) {
             setAuthenticator0((Authenticator) null);
         } else {
- setAuthenticator0(new DefaultAuthenticator(new String(password)));
+ setAuthenticator0(DefaultAuthenticator.of(new String(password)));
         }
     }
 
@@ -1410,7 +1413,7 @@
             final String name = names[i];
             if (name != null) {
                 if (name.length() > 0) {
- formatters[i] = new TailNameFormatter(name);
+ formatters[i] = TailNameFormatter.of(name);
                 } else {
                     throw new IllegalArgumentException(atIndexMsg(i));
                 }
@@ -1503,7 +1506,7 @@
      */
     public final void setSubject(final String subject) {
         if (subject != null) {
- this.setSubject(new TailNameFormatter(subject));
+ this.setSubject(TailNameFormatter.of(subject));
         } else {
             checkAccess();
             throw new NullPointerException();
@@ -1619,6 +1622,7 @@
      * @throws NullPointerException if any of the arguments are null.
      * @since JavaMail 1.4.5
      */
+ @SuppressWarnings({"UseSpecificCatch", "ThrowableResultIgnored"})
     final boolean isMissingContent(Message msg, Throwable t) {
         final Object ccl = getAndSetContextClassLoader(MAILHANDLER_LOADER);
         try {
@@ -1649,6 +1653,7 @@
      * @param code the ErrorManager code.
      * @since JavaMail 1.4.5
      */
+ @SuppressWarnings("UseSpecificCatch")
     private void reportError(Message msg, Exception ex, int code) {
         try { //Use direct call so we do not prefix raw email.
             errorManager.error(toRawString(msg), ex, code);
@@ -1873,7 +1878,7 @@
         } else {
             for (int i = 0; i < expect; ++i) {
                 if (this.attachmentNames[i] == null) {
- this.attachmentNames[i] = new TailNameFormatter(
+ this.attachmentNames[i] = TailNameFormatter.of(
                             toString(this.attachmentFormatters[i]));
                 }
             }
@@ -2172,6 +2177,16 @@
     }
 
     /**
+ * Factory method used to create a java.util.logging.SimpleFormatter.
+ * @return a new SimpleFormatter.
+ * @since JavaMail 1.5.6
+ */
+ private static Formatter createSimpleFormatter() {
+ //Don't force the byte code verifier to load the formatter.
+ return Formatter.class.cast(new SimpleFormatter());
+ }
+
+ /**
      * Checks a string value for null or empty.
      * @param s the string.
      * @return true if the given string is null or zero length.
@@ -2252,18 +2267,18 @@
                         if (a[i] instanceof TailNameFormatter) {
                             final Exception CNFE = new ClassNotFoundException(a[i].toString());
                             reportError("Attachment formatter.", CNFE, ErrorManager.OPEN_FAILURE);
- a[i] = new SimpleFormatter();
+ a[i] = createSimpleFormatter();
                         }
                     } catch (final SecurityException SE) {
                         throw SE; //Avoid catch all.
                     } catch (final Exception E) {
                         reportError(E.getMessage(), E, ErrorManager.OPEN_FAILURE);
- a[i] = new SimpleFormatter();
+ a[i] = createSimpleFormatter();
                     }
                 } else {
                     final Exception NPE = new NullPointerException(atIndexMsg(i));
                     reportError("Attachment formatter.", NPE, ErrorManager.OPEN_FAILURE);
- a[i] = new SimpleFormatter();
+ a[i] = createSimpleFormatter();
                 }
             }
 
@@ -2294,9 +2309,9 @@
                         try {
                             a[i] = LogManagerProperties.newFormatter(names[i]);
                         } catch (final ClassNotFoundException literal) {
- a[i] = new TailNameFormatter(names[i]);
+ a[i] = TailNameFormatter.of(names[i]);
                         } catch (final ClassCastException literal) {
- a[i] = new TailNameFormatter(names[i]);
+ a[i] = TailNameFormatter.of(names[i]);
                         }
                     } catch (final SecurityException SE) {
                         throw SE; //Avoid catch all.
@@ -2336,9 +2351,9 @@
             } catch (final SecurityException SE) {
                 throw SE;
             } catch (final ClassNotFoundException literalAuth) {
- this.auth = new DefaultAuthenticator(name);
+ this.auth = DefaultAuthenticator.of(name);
             } catch (final ClassCastException literalAuth) {
- this.auth = new DefaultAuthenticator(name);
+ this.auth = DefaultAuthenticator.of(name);
             } catch (final Exception E) {
                 reportError(E.getMessage(), E, ErrorManager.OPEN_FAILURE);
             }
@@ -2499,16 +2514,16 @@
                 if (f instanceof TailNameFormatter == false) {
                     formatter = f;
                 } else {
- formatter = new SimpleFormatter();
+ formatter = createSimpleFormatter();
                 }
             } else {
- formatter = new SimpleFormatter();
+ formatter = createSimpleFormatter();
             }
         } catch (final SecurityException SE) {
             throw SE; //Avoid catch all.
         } catch (final Exception E) {
             reportError(E.getMessage(), E, ErrorManager.OPEN_FAILURE);
- formatter = new SimpleFormatter();
+ formatter = createSimpleFormatter();
         }
     }
 
@@ -2599,21 +2614,21 @@
             } catch (final SecurityException SE) {
                 throw SE; //Avoid catch all.
             } catch (final ClassNotFoundException literalSubject) {
- this.subjectFormatter = new TailNameFormatter(name);
+ this.subjectFormatter = TailNameFormatter.of(name);
             } catch (final ClassCastException literalSubject) {
- this.subjectFormatter = new TailNameFormatter(name);
+ this.subjectFormatter = TailNameFormatter.of(name);
             } catch (final Exception E) {
- this.subjectFormatter = new TailNameFormatter(name);
+ this.subjectFormatter = TailNameFormatter.of(name);
                 reportError(E.getMessage(), E, ErrorManager.OPEN_FAILURE);
             }
         } else {
             if (name != null) {
- this.subjectFormatter = new TailNameFormatter(name);
+ this.subjectFormatter = TailNameFormatter.of(name);
             }
         }
 
         if (this.subjectFormatter == null) { //Ensure not null.
- this.subjectFormatter = new TailNameFormatter("");
+ this.subjectFormatter = TailNameFormatter.of("");
         }
     }
 
@@ -3491,7 +3506,7 @@
             chunk = chunk.replaceAll("[\\x00-\\x1F\\x7F]+", "");
             final String charset = getEncodingName();
             final String old = msg.getSubject();
- assert msg instanceof MimeMessage;
+ assert msg instanceof MimeMessage : msg;
             ((MimeMessage) msg).setSubject(old != null ? old.concat(chunk)
                     : chunk, MimeUtility.mimeCharset(charset));
         } catch (final MessagingException ME) {
@@ -3605,7 +3620,7 @@
      */
     private void reportFilterError(final LogRecord record) {
         assert Thread.holdsLock(this);
- final SimpleFormatter f = new SimpleFormatter();
+ final Formatter f = createSimpleFormatter();
         final String msg = "Log record " + record.getSequenceNumber()
                 + " was filtered from all message parts. "
                 + head(f) + format(f, record) + tail(f, "");
@@ -4104,15 +4119,29 @@
     private static final class DefaultAuthenticator extends Authenticator {
 
         /**
+ * Creates an Authenticator for the given password. This method is used
+ * so class verification of assignments in MailHandler doesn't require
+ * loading this class which otherwise can occur when using the
+ * constructor. Default access to avoid generating extra class files.
+ *
+ * @param pass the password.
+ * @return an Authenticator for the password.
+ * @since JavaMail 1.5.6
+ */
+ static Authenticator of(final String pass) {
+ return new DefaultAuthenticator(pass);
+ }
+
+ /**
          * The password to use.
          */
         private final String pass;
 
         /**
- * Creates a new DefaultAuthenticator.
+ * Use the factory method instead of this constructor.
          * @param pass the password.
          */
- DefaultAuthenticator(final String pass) {
+ private DefaultAuthenticator(final String pass) {
             assert pass != null;
             this.pass = pass;
         }
@@ -4142,7 +4171,7 @@
          * Create the action.
          * @param source null for boot class loader, a class loader, a class
          * used to get the class loader, or a source object to get the class
- * loader.
+ * loader. Default access to avoid generating extra class files.
          */
         GetAndSetContext(final Object source) {
             this.source = source;
@@ -4154,6 +4183,7 @@
          * @return the replaced context class loader which can be null or
          * NOT_MODIFIED to indicate that nothing was modified.
          */
+ @SuppressWarnings("override") //JDK-6954234
         public final Object run() {
             final Thread current = Thread.currentThread();
             final ClassLoader ccl = current.getContextClassLoader();
@@ -4186,20 +4216,34 @@
     private static final class TailNameFormatter extends Formatter {
 
         /**
+ * Creates or gets a formatter from the given name. This method is used
+ * so class verification of assignments in MailHandler doesn't require
+ * loading this class which otherwise can occur when using the
+ * constructor. Default access to avoid generating extra class files.
+ *
+ * @param name any not null string.
+ * @return a formatter for that string.
+ * @since JavaMail 1.5.6
+ */
+ static Formatter of(final String name) {
+ return new TailNameFormatter(name);
+ }
+
+ /**
          * The value used as the output.
          */
         private final String name;
 
         /**
- * Creates the formatter with the given name.
- * Default access to avoid extra generated class files.
+ * Use the factory method instead of this constructor.
          * @param name any not null string.
          */
- TailNameFormatter(final String name) {
+ private TailNameFormatter(final String name) {
             assert name != null;
             this.name = name;
         }
 
+ @Override
         public final String format(LogRecord record) {
             return "";
         }

diff -r d015eeb4439f -r 3ed6a59fffe8 mail/src/main/java/com/sun/mail/util/logging/SeverityComparator.java
--- a/mail/src/main/java/com/sun/mail/util/logging/SeverityComparator.java Mon Apr 25 17:10:47 2016 -0700
+++ b/mail/src/main/java/com/sun/mail/util/logging/SeverityComparator.java Tue Apr 26 14:52:54 2016 -0700
@@ -62,10 +62,11 @@
  * {_at_linkplain Level#intValue level}.
  * <li> The expected recovery order of {_at_linkplain LogRecord#getThrown() thrown}
  * property of a LogRecord and its cause chain. This ordering is derived from
- * the JLS 11.5 The Exception Hierarchy. This is performed by
- * {_at_linkplain #apply(java.lang.Throwable) finding} the throwable that best
- * describes the entire cause chain. Once a specific throwable of each chain is
- * identified it is then ranked lowest to highest by the following rules:
+ * the JLS 11.1.1. The Kinds of Exceptions and JLS 11.5 The Exception Hierarchy.
+ * This is performed by {_at_linkplain #apply(java.lang.Throwable) finding} the
+ * throwable that best describes the entire cause chain. Once a specific
+ * throwable of each chain is identified it is then ranked lowest to highest by
+ * the following rules:
  *
  * <ul>
  * <li>All LogRecords with a {_at_code Throwable} defined as
@@ -209,6 +210,7 @@
             }
 
             //Rank the two unidenticial throwables using the rules from
+ //JLS 11.1.1. The Kinds of Exceptions and
             //JLS 11.5 The Exception Hierarchy.
             if (t1 instanceof Error) {
                 return t2 instanceof Error ? 0 : 1;
@@ -216,10 +218,8 @@
                 return t2 instanceof Error ? -1
                         : t2 instanceof RuntimeException ? 0 : 1;
             } else {
- //Bitwise inclusive OR produces tighter bytecode for instanceof
- //and matches with multicatch syntax.
                 return t2 instanceof Error
- | t2 instanceof RuntimeException ? -1 : 0;
+ || t2 instanceof RuntimeException ? -1 : 0;
             }
         }
     }
@@ -233,6 +233,7 @@
      * argument is less than, equal to, or greater than the second.
      * @throws NullPointerException if either argument is null.
      */
+ @SuppressWarnings("override") //JDK-6954234
     public int compare(final LogRecord o1, final LogRecord o2) {
         if (o1 == null || o2 == null) { //Don't allow null.
             throw new NullPointerException(toString(o1, o2));

diff -r d015eeb4439f -r 3ed6a59fffe8 mail/src/test/java/com/sun/mail/util/logging/AbstractLogging.java
--- a/mail/src/test/java/com/sun/mail/util/logging/AbstractLogging.java Mon Apr 25 17:10:47 2016 -0700
+++ b/mail/src/test/java/com/sun/mail/util/logging/AbstractLogging.java Tue Apr 26 14:52:54 2016 -0700
@@ -49,10 +49,14 @@
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Properties;
 import java.util.logging.Level;
 import java.util.logging.LogManager;
+import java.util.logging.LogRecord;
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
@@ -115,6 +119,38 @@
     }
 
     /**
+ * Sets the log record time using milliseconds from the epoch of
+ * 1970-01-01T00:00:00Z. Any nanosecond information is set to zero. This
+ * method is used to support JDK8 when running on JDK9 or newer.
+ *
+ * @param record the log record to adjust.
+ * @param epochMilli the time in milliseconds from epoch.
+ * @throws NullPointerException if the given record is null.
+ */
+ @SuppressWarnings("deprecation") //See JDK-8144262 and K7091.
+ static void setEpochMilli(final LogRecord record, final long epochMilli) {
+ record.setMillis(epochMilli);
+ }
+
+ /**
+ * Determines if the {_at_code java.time} APIs are available for this JVM.
+ *
+ * @return true if the time classes can be loaded.
+ */
+ static boolean hasJavaTimeModule() {
+ try {
+ Class.forName("java.time.Duration");
+ Class.forName("java.time.Instant");
+ Class.forName("java.time.ZonedDateTime");
+ Class.forName("java.time.ZoneId");
+ return true;
+ } catch (final ClassNotFoundException notSupported) {
+ } catch (final LinkageError notSupported) {
+ }
+ return false;
+ }
+
+ /**
      * Fails if any declared types are outside of the logging-mailhandler.jar.
      *
      * @param k the type to check for dependencies.
@@ -165,6 +201,33 @@
     }
 
     /**
+ * Tests that the private static loadDeclaredClasses method of the given
+ * type. Objects used by the MailHandler during a push might require
+ * declaring classes to be loaded on create since a push may happen after a
+ * class loader is shutdown.
+ *
+ * @param k the type to check never null.
+ * @throws Exception if there is a problem.
+ */
+ final void testLoadDeclaredClasses(Class<?> k) throws Exception {
+ Method m = k.getDeclaredMethod("loadDeclaredClasses");
+ assertTrue(Modifier.isStatic(m.getModifiers()));
+ assertTrue(Modifier.isPrivate(m.getModifiers()));
+ assertEquals(Class[].class, m.getReturnType());
+ m.setAccessible(true);
+ Class<?>[] named = (Class<?>[]) m.invoke((Object) null);
+ assertTrue(named.length != 0);
+ HashSet<Class<?>> declared = new HashSet<Class<?>>(
+ Arrays.<Class<?>>asList(k.getDeclaredClasses()));
+ for (Class<?> c : named) {
+ assertEquals(c.toString(), k, c.getEnclosingClass());
+ assertTrue(c.getDeclaredClasses().length == 0);
+ declared.remove(c);
+ }
+ assertTrue(declared.toString(), declared.isEmpty());
+ }
+
+ /**
      * Checks that the given class is visible to the LogManager.
      *
      * @param c the class to check.
@@ -217,8 +280,8 @@
      *
      * @throws InterruptedException if the current thread is interrupted.
      */
- static void tick() throws InterruptedException {
- tick(1L);
+ static void tickMilli() throws InterruptedException {
+ tickMilli(1L);
     }
 
     /**
@@ -230,7 +293,7 @@
      * @throws InterruptedException if the current thread is interrupted.
      */
     @SuppressWarnings("SleepWhileInLoop")
- static void tick(long delay) throws InterruptedException {
+ static void tickMilli(long delay) throws InterruptedException {
         if (delay <= 0L) {
             throw new IllegalArgumentException(Long.toString(delay));
         }

diff -r d015eeb4439f -r 3ed6a59fffe8 mail/src/test/java/com/sun/mail/util/logging/CollectorFormatterTest.java
--- a/mail/src/test/java/com/sun/mail/util/logging/CollectorFormatterTest.java Mon Apr 25 17:10:47 2016 -0700
+++ b/mail/src/test/java/com/sun/mail/util/logging/CollectorFormatterTest.java Tue Apr 26 14:52:54 2016 -0700
@@ -109,6 +109,12 @@
     }
 
     @Test
+ public void testDeclaredClasses() throws Exception {
+ Class<?>[] declared = CollectorFormatter.class.getDeclaredClasses();
+ assertEquals(Arrays.toString(declared), 0, declared.length);
+ }
+
+ @Test
     public void testFormatHead() {
         String msg = "message";
         XMLFormatter xml = new XMLFormatter();
@@ -176,11 +182,11 @@
                 new SeverityComparator());
         LogRecord first = new LogRecord(Level.INFO, "");
         first.setThrown(new Throwable());
- first.setMillis(1L);
+ setEpochMilli(first, 1L);
         f.format(first);
 
         TestFormatterAccept r = new TestFormatterAccept(Level.FINE, f);
- r.setMillis(2L);
+ setEpochMilli(r, 2L);
         r.setThrown(new Throwable());
         f.format(r);
         assertEquals(1, r.inferred);
@@ -204,7 +210,7 @@
         public String getSourceMethodName() {
             if (++inferred == 1) {
                 LogRecord r = new LogRecord(Level.INFO, "");
- r.setMillis(1L);
+ setEpochMilli(r, 1L);
                 f.format(r);
             }
             return super.getSourceMethodName();
@@ -220,7 +226,7 @@
 
         TestFormatAcceptAndUpdate r
                 = new TestFormatAcceptAndUpdate(Level.SEVERE, f);
- r.setMillis(2L);
+ setEpochMilli(r, 2L);
         r.setThrown(new Throwable());
         f.format(r);
         assertEquals(2, r.inferred);
@@ -433,11 +439,11 @@
                 (Formatter) null,
                 (Comparator<LogRecord>) null);
 
- tick(); //Make sure the max not equal to the start time.
+ tickMilli(); //Make sure the max not equal to the start time.
 
         final String min = minF.getTail((Handler) null);
         NumberFormat.getIntegerInstance().parse(min);
- tick();
+ tickMilli();
 
         //Next min is not old min.
         String next = minF.getTail((Handler) null);
@@ -462,23 +468,23 @@
         long min = 100L;
 
         LogRecord r = new LogRecord(Level.SEVERE, msg);
- r.setMillis(min + 1000L);
+ setEpochMilli(r, min + 1000L);
         f.format(r);
 
         r = new LogRecord(Level.SEVERE, msg);
- r.setMillis(min + 2000L);
+ setEpochMilli(r, min + 2000L);
         f.format(r);
 
         r = new LogRecord(Level.SEVERE, msg);
- r.setMillis(min);
+ setEpochMilli(r, min);
         f.format(r);
 
         r = new LogRecord(Level.SEVERE, msg);
- r.setMillis(min + 3000L);
+ setEpochMilli(r, min + 3000L);
         f.format(r);
 
         r = new LogRecord(Level.SEVERE, msg);
- r.setMillis(min + 4000L);
+ setEpochMilli(r, min + 4000L);
         f.format(r);
 
         String result = f.getTail((Handler) null);
@@ -493,7 +499,7 @@
         String now = f.getTail((Handler) null);
         Number num = NumberFormat.getIntegerInstance().parse(now);
         assertFalse(Long.MIN_VALUE == num.longValue());
- tick();
+ tickMilli();
         String next = f.getTail((Handler) null);
         assertFalse(NumberFormat.getIntegerInstance().parse(now).longValue()
                 == Long.MIN_VALUE);
@@ -511,23 +517,23 @@
         long high = 4000L;
 
         LogRecord r = new LogRecord(Level.SEVERE, msg);
- r.setMillis(min + 1000L);
+ setEpochMilli(r, min + 1000L);
         f.format(r);
 
         r = new LogRecord(Level.SEVERE, msg);
- r.setMillis(min + high);
+ setEpochMilli(r, min + high);
         f.format(r);
 
         r = new LogRecord(Level.SEVERE, msg);
- r.setMillis(min + 2000L);
+ setEpochMilli(r, min + 2000L);
         f.format(r);
 
         r = new LogRecord(Level.SEVERE, msg);
- r.setMillis(min);
+ setEpochMilli(r, min);
         f.format(r);
 
         r = new LogRecord(Level.SEVERE, msg);
- r.setMillis(min + 3000L);
+ setEpochMilli(r, min + 3000L);
         f.format(r);
 
         String result = f.getTail((Handler) null);
@@ -541,11 +547,11 @@
                 (Comparator<LogRecord>) null);
 
         LogRecord r = new LogRecord(Level.SEVERE, "");
- r.setMillis(100);
+ setEpochMilli(r, 100);
         f.format(r);
 
         r = new LogRecord(Level.SEVERE, "");
- r.setMillis(200);
+ setEpochMilli(r, 200);
         f.format(r);
 
         //Check that the min and max are different.
@@ -555,7 +561,7 @@
                 (output.length() - fence) - 1));
 
         r = new LogRecord(Level.SEVERE, "");
- r.setMillis(400);
+ setEpochMilli(r, 400);
         f.format(r);
 
         //Previous max is 200 so at this point the min and max better be 400.
@@ -604,18 +610,18 @@
                 + "{8,time,EEE, MMM dd HH:mm:ss:S ZZZ yyyy}\n";
         CollectorFormatter cf = new CollectorFormatter(p);
         LogRecord min = new LogRecord(Level.SEVERE, "");
- min.setMillis(1248203502449L);
+ setEpochMilli(min, 1248203502449L);
         cf.format(min);
 
         int count = 290;
         for (int i = 0; i < count; ++i) {
             LogRecord mid = new LogRecord(Level.SEVERE, "");
- mid.setMillis(min.getMillis());
+ setEpochMilli(mid, min.getMillis());
             cf.format(mid);
         }
 
         LogRecord max = new LogRecord(Level.SEVERE, "");
- max.setMillis(1258723764000L);
+ setEpochMilli(max, 1258723764000L);
         cf.format(max);
         Object[] args = new Object[9];
         args[3] = count + 2L;
@@ -633,17 +639,17 @@
                 + "|86400000<{7,date} and {8,date}}\n";
         CollectorFormatter cf = new CollectorFormatter(p);
         LogRecord min = new LogRecord(Level.SEVERE, "");
- min.setMillis(1248203502449L);
+ setEpochMilli(min, 1248203502449L);
         cf.format(min);
 
         for (int i = 0; i < 71; ++i) {
             LogRecord mid = new LogRecord(Level.SEVERE, "");
- mid.setMillis(min.getMillis());
+ setEpochMilli(mid, min.getMillis());
             cf.format(mid);
         }
 
         LogRecord max = new LogRecord(Level.SEVERE, "");
- max.setMillis(min.getMillis() + 110500);
+ setEpochMilli(max, min.getMillis() + 110500);
         cf.format(max);
 
         String output = cf.getTail((Handler) null);
@@ -652,11 +658,11 @@
         cf.format(min);
         for (int i = 0; i < 114; ++i) {
             LogRecord mid = new LogRecord(Level.SEVERE, "");
- mid.setMillis(min.getMillis());
+ setEpochMilli(mid, min.getMillis());
             cf.format(mid);
         }
 
- max.setMillis(min.getMillis() + 2591000000L);
+ setEpochMilli(max, min.getMillis() + 2591000000L);
         cf.format(max);
 
         output = cf.getTail((Handler) null);
@@ -669,17 +675,17 @@
                 + "|86400000<{7,date} and {8,date}}\n";
         CollectorFormatter cf = new CollectorFormatter(p);
         LogRecord min = new LogRecord(Level.SEVERE, "");
- min.setMillis(1248203502449L);
+ setEpochMilli(min, 1248203502449L);
 
         cf.format(min);
         for (int i = 0; i < 114; ++i) {
             LogRecord mid = new LogRecord(Level.SEVERE, "");
- mid.setMillis(min.getMillis());
+ setEpochMilli(mid, min.getMillis());
             cf.format(mid);
         }
 
         LogRecord max = new LogRecord(Level.SEVERE, "");
- max.setMillis(min.getMillis() + 2591000000L);
+ setEpochMilli(max, min.getMillis() + 2591000000L);
         cf.format(max);
 
         String output = cf.getTail((Handler) null);
@@ -895,11 +901,11 @@
         CollectorFormatter f = new CollectorFormatter("{9}", (Formatter) null,
                 (Comparator<LogRecord>) null);
         LogRecord r = new LogRecord(Level.SEVERE, "");
- r.setMillis(25L);
+ setEpochMilli(r, 25L);
         f.format(r);
 
         r = new LogRecord(Level.SEVERE, "");
- r.setMillis(100L);
+ setEpochMilli(r, 100L);
         f.format(r);
 
         String init = f.getTail((Handler) null);
@@ -914,7 +920,7 @@
 
         String init = f.getTail((Handler) null);
         NumberFormat.getIntegerInstance().parse(init);
- tick();
+ tickMilli();
 
         assertTrue(init.equals(f.getTail((Handler) null)));
     }
@@ -929,7 +935,7 @@
         String init = f.getTail((Handler) null);
         DateFormat df = new SimpleDateFormat(DATE_TIME_FMT);
         Date dt = df.parse(init);
- tick();
+ tickMilli();
 
         assertTrue(init.equals(f.getTail((Handler) null)));
         assertTrue(dt.equals(df.parse(f.getTail((Handler) null))));
@@ -942,7 +948,7 @@
 
         String now = f.getTail((Handler) null);
         NumberFormat.getIntegerInstance().parse(now);
- tick();
+ tickMilli();
 
         assertFalse(now.equals(f.getTail((Handler) null)));
     }
@@ -957,7 +963,7 @@
         String init = f.getTail((Handler) null);
         DateFormat df = new SimpleDateFormat(DATE_TIME_FMT);
         Date dt = df.parse(init);
- tick();
+ tickMilli();
 
         assertFalse(init.equals(f.getTail((Handler) null)));
         assertFalse(dt.equals(df.parse(f.getTail((Handler) null))));
@@ -970,7 +976,7 @@
 
         String up = f.getTail((Handler) null);
         NumberFormat.getIntegerInstance().parse(up);
- tick();
+ tickMilli();
 
         assertFalse(up.equals(f.getTail((Handler) null)));
     }

diff -r d015eeb4439f -r 3ed6a59fffe8 mail/src/test/java/com/sun/mail/util/logging/CompactFormatterTest.java
--- a/mail/src/test/java/com/sun/mail/util/logging/CompactFormatterTest.java Mon Apr 25 17:10:47 2016 -0700
+++ b/mail/src/test/java/com/sun/mail/util/logging/CompactFormatterTest.java Tue Apr 26 14:52:54 2016 -0700
@@ -120,6 +120,11 @@
     }
 
     @Test
+ public void testDeclaredClasses() throws Exception {
+ testLoadDeclaredClasses(CompactFormatter.class);
+ }
+
+ @Test
     public void testFormat() throws Exception {
         final String p = CompactFormatter.class.getName();
         Properties props = new Properties();
@@ -741,7 +746,7 @@
         LogRecord r = new LogRecord(Level.SEVERE, "Encoding failed.");
         r.setSourceClassName("MyClass");
         r.setSourceMethodName("fatal");
- r.setMillis(1258723764000L);
+ setEpochMilli(r, 1258723764000L);
         RuntimeException npe = new NullPointerException();
         StackTraceElement frame = new StackTraceElement("java.lang.String",
                 "getBytes", "String.java", 913);
@@ -758,7 +763,7 @@
         LogRecord r = new LogRecord(Level.SEVERE, "Unable to send notification.");
         r.setSourceClassName("MyClass");
         r.setSourceMethodName("fatal");
- r.setMillis(1258723764000L);
+ setEpochMilli(r, 1258723764000L);
 
         Exception t = new SocketException("Permission denied: connect");
         t = new MessagingException("Couldn't connect to host", t);
@@ -776,7 +781,7 @@
         r.setThreadID(38);
         r.setSourceClassName("MyClass");
         r.setSourceMethodName("fatal");
- r.setMillis(1248203502449L);
+ setEpochMilli(r, 1248203502449L);
 
         Exception t = new SocketException("Permission denied: connect");
 

diff -r d015eeb4439f -r 3ed6a59fffe8 mail/src/test/java/com/sun/mail/util/logging/DurationFilterTest.java
--- a/mail/src/test/java/com/sun/mail/util/logging/DurationFilterTest.java Mon Apr 25 17:10:47 2016 -0700
+++ b/mail/src/test/java/com/sun/mail/util/logging/DurationFilterTest.java Tue Apr 26 14:52:54 2016 -0700
@@ -41,6 +41,7 @@
 package com.sun.mail.util.logging;
 
 import java.lang.reflect.Field;
+import java.util.Arrays;
 import java.util.Properties;
 import java.util.logging.*;
 import org.junit.*;
@@ -75,6 +76,12 @@
     }
 
     @Test
+ public void testDeclaredClasses() throws Exception {
+ Class<?>[] declared = DurationFilter.class.getDeclaredClasses();
+ assertEquals(Arrays.toString(declared), 0, declared.length);
+ }
+
+ @Test
     public void testClone() throws Exception {
         DurationFilterExt source = new DurationFilterExt();
         final Filter clone = source.clone();
@@ -101,13 +108,13 @@
 
         //Allow
         for (int i = 0; i < records; i++) {
- r.setMillis(millis);
+ setEpochMilli(r, millis);
             assertTrue(Integer.toString(i), sf.isLoggable(r));
         }
 
         Filter clone = sf.clone();
         for (int i = 0; i < records; i++) {
- r.setMillis(millis);
+ setEpochMilli(r, millis);
             String m = Integer.toString(i);
             assertFalse(m, sf.isLoggable(r));
             assertTrue(m, clone.isLoggable(r));
@@ -140,7 +147,7 @@
         assertFalse(sf.isLoggable());
         assertFalse(sf.isLoggable(r));
 
- tick(duration + 100); //Cool down and allow.
+ tickMilli(duration + 100); //Cool down and allow.
 
         for (int i = 0; i < records; i++) {
             r = new LogRecord(lvl, "");
@@ -175,7 +182,7 @@
         assertFalse(sf.isIdle());
         assertFalse(sf.isLoggable(r));
 
- tick(duration + 100); //Cool down and allow.
+ tickMilli(duration + 100); //Cool down and allow.
 
         assertTrue(sf.isIdle());
         for (int i = 0; i < records; i++) {
@@ -202,14 +209,14 @@
         for (int i = 0; i < records; i++) {
             ++millis;
             r = new LogRecord(lvl, Long.toString(millis));
- r.setMillis(millis);
+ setEpochMilli(r, millis);
             assertTrue(Integer.toString(i), sf.isLoggable(r));
         }
 
         //Saturate.
         for (int i = 0; i < records * 10; i++) {
             r = new LogRecord(lvl, Long.toString(millis));
- r.setMillis(millis);
+ setEpochMilli(r, millis);
             assertFalse(Integer.toString(i), sf.isLoggable(r));
         }
 
@@ -218,7 +225,7 @@
         for (int i = 0; i < records; i++) {
             ++millis;
             r = new LogRecord(lvl, Long.toString(millis));
- r.setMillis(millis);
+ setEpochMilli(r, millis);
      
[truncated due to length]