commits@javamail.java.net

[javamail~mercurial:601] MailHandler fine grain locking for isLoggable (JDK-6823527)

From: <shannon_at_java.net>
Date: Fri, 11 Oct 2013 23:34:19 +0000

Project: javamail
Repository: mercurial
Revision: 601
Author: shannon
Date: 2013-10-11 22:45:09 UTC
Link:

Log Message:
------------
add support for the IMAP ID extension - bug 6137
MailHandler fine grain locking for isLoggable (JDK-6823527)
MailHandlerTest suppress possible NPE warnings.
LogManagerProperties fixed import order.
Fixed -Xlint:all warnings.

(From Jason)


Revisions:
----------
600
601


Modified Paths:
---------------
doc/release/CHANGES.txt
mail/src/main/java/com/sun/mail/iap/Argument.java
mail/src/main/java/com/sun/mail/imap/IMAPFolder.java
mail/src/main/java/com/sun/mail/imap/IMAPStore.java
mail/src/main/java/com/sun/mail/imap/protocol/IMAPProtocol.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/test/java/com/sun/mail/util/logging/MailHandlerTest.java


Added Paths:
------------
mail/src/main/java/com/sun/mail/imap/protocol/ID.java


Diffs:
------
diff -r 64bc7c736dc9 -r 18da2b1c2511 doc/release/CHANGES.txt
--- a/doc/release/CHANGES.txt Fri Oct 04 16:21:20 2013 -0700
+++ b/doc/release/CHANGES.txt Fri Oct 11 15:36:01 2013 -0700
@@ -31,6 +31,7 @@
 K 6108 When using XGWTRUSTEDAPP mechanism, LOGIN should not be issued if no
         authzid is specified
 K 6125 support empty IMAP ENVELOPE address list instead of NIL
+K 6137 JavaMail should support the IMAP ID extension
 
 
                   CHANGES IN THE 1.5.0 RELEASE

diff -r 64bc7c736dc9 -r 18da2b1c2511 mail/src/main/java/com/sun/mail/iap/Argument.java
--- a/mail/src/main/java/com/sun/mail/iap/Argument.java Fri Oct 04 16:21:20 2013 -0700
+++ b/mail/src/main/java/com/sun/mail/iap/Argument.java Fri Oct 11 15:36:01 2013 -0700
@@ -98,6 +98,39 @@
     }
 
     /**
+ * Write out given string as an NSTRING, depending on the type
+ * of the characters inside the string. The string should
+ * contain only ASCII characters. <p>
+ *
+ * @param s String to write out
+ * @since JavaMail 1.5.1
+ */
+ public Argument writeNString(String s) {
+ if (s == null)
+ items.add(new NString(null));
+ else
+ items.add(new NString(ASCIIUtility.getBytes(s)));
+ return this;
+ }
+
+ /**
+ * Convert the given string into bytes in the specified
+ * charset, and write the bytes out as an NSTRING
+ *
+ * @since JavaMail 1.5.1
+ */
+ public Argument writeNString(String s, String charset)
+ throws UnsupportedEncodingException {
+ if (s == null)
+ items.add(new NString(null));
+ else if (charset == null) // convenience
+ writeString(s);
+ else
+ items.add(new NString(s.getBytes(charset)));
+ return this;
+ }
+
+ /**
      * Write out given byte[] as a Literal.
      * @param b byte[] to write out
      */
@@ -180,6 +213,8 @@
                 os.writeBytes(((Number)o).toString());
             } else if (o instanceof AString) {
                 astring(((AString)o).bytes, protocol);
+ } else if (o instanceof NString) {
+ nstring(((NString)o).bytes, protocol);
             } else if (o instanceof byte[]) {
                 literal((byte[])o, protocol);
             } else if (o instanceof ByteArrayOutputStream) {
@@ -199,6 +234,23 @@
      */
     private void astring(byte[] bytes, Protocol protocol)
                         throws IOException, ProtocolException {
+ nastring(bytes, protocol, false);
+ }
+
+ /**
+ * Write out given String as either NIL, QuotedString, or Literal.
+ */
+ private void nstring(byte[] bytes, Protocol protocol)
+ throws IOException, ProtocolException {
+ if (bytes == null) {
+ DataOutputStream os = (DataOutputStream)protocol.getOutputStream();
+ os.writeBytes("NIL");
+ } else
+ nastring(bytes, protocol, true);
+ }
+
+ private void nastring(byte[] bytes, Protocol protocol, boolean doQuote)
+ throws IOException, ProtocolException {
         DataOutputStream os = (DataOutputStream)protocol.getOutputStream();
         int len = bytes.length;
 
@@ -209,7 +261,7 @@
         }
 
         // if 0 length, send as quoted-string
- boolean quote = len == 0 ? true: false;
+ boolean quote = len == 0 ? true : doQuote;
         boolean escape = false;
          
         byte b;
@@ -316,3 +368,11 @@
         bytes = b;
     }
 }
+
+class NString {
+ byte[] bytes;
+
+ NString(byte[] b) {
+ bytes = b;
+ }
+}

diff -r 64bc7c736dc9 -r 18da2b1c2511 mail/src/main/java/com/sun/mail/imap/IMAPFolder.java
--- a/mail/src/main/java/com/sun/mail/imap/IMAPFolder.java Fri Oct 04 16:21:20 2013 -0700
+++ b/mail/src/main/java/com/sun/mail/imap/IMAPFolder.java Fri Oct 11 15:36:01 2013 -0700
@@ -45,6 +45,7 @@
 import java.util.Hashtable;
 import java.util.List;
 import java.util.ArrayList;
+import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.logging.Level;
 import java.io.*;
@@ -2875,6 +2876,31 @@
     }
 
     /**
+ * Send the IMAP ID command (if supported by the server) and return
+ * the result from the server. The ID command identfies the client
+ * to the server and returns information about the server to the client.
+ * See <A HREF="http://www.ietf.org/rfc/rfc2971.txt">RFC 2971</A>.
+ * The returned Map is unmodifiable.
+ *
+ * @param clientParams a Map of keys and values identifying the client
+ * @return a Map of keys and values identifying the server
+ * @exception MessagingException if the server doesn't support the
+ * ID extension
+ * @since JavaMail 1.5.1
+ */
+ public Map<String, String> id(final Map<String, String> clientParams)
+ throws MessagingException {
+ checkOpened();
+ return (Map<String,String>)doOptionalCommand("ID not supported",
+ new ProtocolCommand() {
+ public Object doCommand(IMAPProtocol p)
+ throws ProtocolException {
+ return p.id(clientParams);
+ }
+ });
+ }
+
+ /**
      * The response handler. This is the callback routine that is
      * invoked by the protocol layer.
      */

diff -r 64bc7c736dc9 -r 18da2b1c2511 mail/src/main/java/com/sun/mail/imap/IMAPStore.java
--- a/mail/src/main/java/com/sun/mail/imap/IMAPStore.java Fri Oct 04 16:21:20 2013 -0700
+++ b/mail/src/main/java/com/sun/mail/imap/IMAPStore.java Fri Oct 11 15:36:01 2013 -0700
@@ -48,6 +48,8 @@
 import java.io.IOException;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
+import java.util.Map;
+import java.util.HashMap;
 import java.util.logging.Level;
 
 import javax.mail.*;
@@ -70,6 +72,12 @@
  * Refer to <A HREF="http://www.ietf.org/rfc/rfc2087.txt">RFC 2087</A>
  * for more information. <p>
  *
+ * The {_at_link #id id} method supports the IMAP ID extension;
+ * see <A HREF="http://www.ietf.org/rfc/rfc2971.txt">RFC 2971</A>.
+ * The fields ID_NAME, ID_VERSION, etc. represent the suggested field names
+ * in RFC 2971 section 3.3 and may be used as keys in the Map containing
+ * client values or server values. <p>
+ *
  * See the <a href="package-summary.html">com.sun.mail.imap</a> package
  * documentation for further information on the IMAP protocol provider. <p>
  *
@@ -161,6 +169,18 @@
      */
     public static final int RESPONSE = 1000;
 
+ public static final String ID_NAME = "name";
+ public static final String ID_VERSION = "version";
+ public static final String ID_OS = "os";
+ public static final String ID_OS_VERSION = "os-version";
+ public static final String ID_VENDOR = "vendor";
+ public static final String ID_SUPPORT_URL = "support-url";
+ public static final String ID_ADDRESS = "address";
+ public static final String ID_DATE = "date";
+ public static final String ID_COMMAND = "command";
+ public static final String ID_ARGUMENTS = "arguments";
+ public static final String ID_ENVIRONMENT = "environment";
+
     protected final String name; // name of this protocol
     protected final int defaultPort; // default IMAP port
     protected final boolean isSSL; // use SSL?
@@ -716,8 +736,12 @@
         preLogin(p);
 
         // issue special ID command to Yahoo! Mail IMAP server
- if (guid != null)
- p.id(guid);
+ // http://en.wikipedia.org/wiki/Yahoo%21_Mail#Free_IMAP_and_SMTPs_access
+ if (guid != null) {
+ Map<String,String> gmap = new HashMap<String,String>();
+ gmap.put("GUID", guid);
+ p.id(gmap);
+ }
 
         /*
          * Put a special "marker" in the capabilities list so we can
@@ -1963,6 +1987,40 @@
     }
 
     /**
+ * Send the IMAP ID command (if supported by the server) and return
+ * the result from the server. The ID command identfies the client
+ * to the server and returns information about the server to the client.
+ * See <A HREF="http://www.ietf.org/rfc/rfc2971.txt">RFC 2971</A>.
+ * The returned Map is unmodifiable.
+ *
+ * @param clientParams a Map of keys and values identifying the client
+ * @return a Map of keys and values identifying the server
+ * @exception MessagingException if the server doesn't support the
+ * ID extension
+ * @since JavaMail 1.5.1
+ */
+ public synchronized Map<String, String> id(Map<String, String> clientParams)
+ throws MessagingException {
+ checkConnected();
+ Map<String, String> serverParams = null;
+
+ IMAPProtocol p = null;
+ try {
+ p = getStoreProtocol();
+ serverParams = p.id(clientParams);
+ } catch (BadCommandException bex) {
+ throw new MessagingException("ID not supported", bex);
+ } catch (ConnectionException cex) {
+ throw new StoreClosedException(this, cex.getMessage());
+ } catch (ProtocolException pex) {
+ throw new MessagingException(pex.getMessage(), pex);
+ } finally {
+ releaseStoreProtocol(p);
+ }
+ return serverParams;
+ }
+
+ /**
      * Handle notifications and alerts.
      * Response must be an OK, NO, BAD, or BYE response.
      */

diff -r 64bc7c736dc9 -r 18da2b1c2511 mail/src/main/java/com/sun/mail/imap/protocol/ID.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mail/src/main/java/com/sun/mail/imap/protocol/ID.java Fri Oct 11 15:36:01 2013 -0700
@@ -0,0 +1,118 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2013 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
+ * and Distribution License("CDDL") (collectively, the "License"). You
+ * may not use this file except in compliance with the License. You can
+ * obtain a copy of the License at
+ * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
+ * or packager/legal/LICENSE.txt. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at packager/legal/LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above. However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package com.sun.mail.imap.protocol;
+
+import java.util.*;
+import com.sun.mail.iap.*;
+
+/**
+ * This class represents the response to the ID command. <p>
+ *
+ * See <A HREF="http://www.ietf.org/rfc/rfc2971.txt">RFC 2971</A>.
+ *
+ * @since JavaMail 1.5.1
+ * @author Bill Shannon
+ */
+
+public class ID {
+
+ private Map<String, String> serverParams = null;
+
+ /**
+ * Parse the server parameter list out of the response.
+ */
+ public ID(Response r) throws ProtocolException {
+ // id_response ::= "ID" SPACE id_params_list
+ // id_params_list ::= "(" #(string SPACE nstring) ")" / nil
+ // ;; list of field value pairs
+
+ r.skipSpaces();
+ int c = r.peekByte();
+ if (c == 'N' || c == 'n') // assume NIL
+ return;
+
+ if (c != '(')
+ throw new ProtocolException("Missing '(' at start of ID");
+
+ serverParams = new HashMap<String, String>();
+
+ String[] v = r.readStringList();
+ if (v != null) {
+ for (int i = 0; i < v.length; i += 2) {
+ String name = v[i];
+ if (name == null)
+ throw new ProtocolException("ID field name null");
+ if (i + 1 >= v.length)
+ throw new ProtocolException("ID field without value: " +
+ name);
+ String value = v[i + 1];
+ serverParams.put(name, value);
+ }
+ }
+ serverParams = Collections.unmodifiableMap(serverParams);
+ }
+
+ /**
+ * Return the parsed server params.
+ */
+ Map<String, String> getServerParams() {
+ return serverParams;
+ }
+
+ /**
+ * Convert the client parameters into an argument list for the ID command.
+ */
+ static Argument getArgumentList(Map<String,String> clientParams) {
+ Argument arg = new Argument();
+ if (clientParams == null) {
+ arg.writeString("NIL");
+ return arg;
+ }
+ Argument list = new Argument();
+ // add params to list
+ for (Map.Entry<String, String> e : clientParams.entrySet()) {
+ list.writeNString(e.getKey());
+ list.writeNString(e.getValue());
+ }
+ arg.writeArgument(list);
+ return arg;
+ }
+}

diff -r 64bc7c736dc9 -r 18da2b1c2511 mail/src/main/java/com/sun/mail/imap/protocol/IMAPProtocol.java
--- a/mail/src/main/java/com/sun/mail/imap/protocol/IMAPProtocol.java Fri Oct 04 16:21:20 2013 -0700
+++ b/mail/src/main/java/com/sun/mail/imap/protocol/IMAPProtocol.java Fri Oct 11 15:36:01 2013 -0700
@@ -819,23 +819,15 @@
     /**
      * ID Command, for Yahoo! Mail IMAP server.
      *
- * See <A HREF="http://en.wikipedia.org/wiki/Yahoo%21_Mail#Free_IMAP_and_SMTPs_access">
- * http://en.wikipedia.org/wiki/Yahoo%21_Mail#Free_IMAP_and_SMTPs_access</A>
- *
+ * @deprecated As of JavaMail 1.5.1, replaced by
+ * {_at_link #id(Map<String,String>)}
      * @since JavaMail 1.4.4
      */
     public void id(String guid) throws ProtocolException {
- /*
- * XXX - need to be able to write a string instead
- * of an astring for the following to work.
- Argument garg = new Argument();
- garg.writeString("GUID");
- garg.writeString(guid);
- Argument args = new Argument();
- args.writeArgument(garg);
- simpleCommand("ID", args);
- */
- simpleCommand("ID (\"GUID\" \"" + guid + "\")", null);
+ // support this for now, but remove it soon
+ Map<String,String> gmap = new HashMap<String,String>();
+ gmap.put("GUID", guid);
+ id(gmap);
     }
 
     /**
@@ -2685,4 +2677,41 @@
             // nothing to do, hope to detect it again later
         }
     }
+
+ /**
+ * ID Command.
+ *
+ * @see "RFC 2971"
+ * @since JavaMail 1.5.1
+ */
+ public Map<String, String> id(Map<String, String> clientParams)
+ throws ProtocolException {
+ if (!hasCapability("ID"))
+ throw new BadCommandException("ID not supported");
+
+ Response[] r = command("ID", ID.getArgumentList(clientParams));
+
+ ID id = null;
+ Response response = r[r.length-1];
+
+ // Grab ID response
+ if (response.isOK()) { // command succesful
+ for (int i = 0, len = r.length; i < len; i++) {
+ if (!(r[i] instanceof IMAPResponse))
+ continue;
+
+ IMAPResponse ir = (IMAPResponse)r[i];
+ if (ir.keyEquals("ID")) {
+ if (id == null)
+ id = new ID(ir);
+ r[i] = null;
+ }
+ }
+ }
+
+ // dispatch remaining untagged responses
+ notifyResponseHandlers(r);
+ handleResult(response);
+ return id == null ? null : id.getServerParams();
+ }
 }


diff -r 18da2b1c2511 -r 3b2083eeddb4 mail/src/main/java/com/sun/mail/util/logging/LogManagerProperties.java
--- a/mail/src/main/java/com/sun/mail/util/logging/LogManagerProperties.java Fri Oct 11 15:36:01 2013 -0700
+++ b/mail/src/main/java/com/sun/mail/util/logging/LogManagerProperties.java Fri Oct 11 15:45:09 2013 -0700
@@ -47,8 +47,8 @@
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.*;
+import java.util.logging.*;
 import java.util.logging.Formatter;
-import java.util.logging.*;
 import javax.mail.Authenticator;
 
 /**
@@ -369,7 +369,7 @@
     private static Class<?> findClass(String name) throws ClassNotFoundException {
         ClassLoader[] loaders = getClassLoaders();
         assert loaders.length == 2 : loaders.length;
- Class clazz;
+ Class<?> clazz;
         if (loaders[0] != null) {
             try {
                 clazz = Class.forName(name, false, loaders[0]);
@@ -573,7 +573,7 @@
      * @return the property names
      */
     @Override
- public Enumeration propertyNames() {
+ public Enumeration<?> propertyNames() {
         assert false;
         return super.propertyNames();
     }

diff -r 18da2b1c2511 -r 3b2083eeddb4 mail/src/main/java/com/sun/mail/util/logging/MailHandler.java
--- a/mail/src/main/java/com/sun/mail/util/logging/MailHandler.java Fri Oct 11 15:36:01 2013 -0700
+++ b/mail/src/main/java/com/sun/mail/util/logging/MailHandler.java Fri Oct 11 15:45:09 2013 -0700
@@ -456,9 +456,11 @@
     private Filter pushFilter;
     /**
      * Holds the filters for each attachment. Filters are optional for
- * each attachment.
+ * each attachment. This is declared volatile because this is treated as
+ * copy-on-write. VO_VOLATILE_REFERENCE_TO_ARRAY is a false positive.
      */
- private Filter[] attachmentFilters;
+ @SuppressWarnings("VolatileArrayField")
+ private volatile Filter[] attachmentFilters;
     /**
      * Holds the formatters that create the content for each attachment.
      * Each formatter maps directly to an attachment. The formatters
@@ -1416,12 +1418,13 @@
     }
 
     /**
- * Gets the attachment filters under a lock. The attachment filters
- * are treated as copy-on-write, so the returned array must never be
- * modified or published outside this class.
+ * Gets the attachment filters using a happens-before relationship between
+ * this method and setAttachmentFilters. The attachment filters are treated
+ * as copy-on-write, so the returned array must never be modified or
+ * published outside this class.
      * @return a read only array of filters.
      */
- private synchronized Filter[] readOnlyAttachmentFilters() {
+ private Filter[] readOnlyAttachmentFilters() {
         return this.attachmentFilters;
     }
 
@@ -1508,6 +1511,7 @@
      * @param len the new size.
      * @return new copy
      */
+ @SuppressWarnings("unchecked")
     private static <T> T[] copyOf(final T[] a, final int len) {
         return (T[]) copyOf(a, len, a.getClass());
     }
@@ -1520,6 +1524,7 @@
      * @param type the array type.
      * @return new copy
      */
+ @SuppressWarnings("unchecked")
     private static <T,U> T[] copyOf(U[] a, int len, Class<? extends T[]> type) {
         final T[] copy = (T[]) Array.newInstance(type.getComponentType(), len);
         System.arraycopy(a, 0, copy, 0, Math.min(len, a.length));
@@ -2770,7 +2775,7 @@
      * @throws NullPointerException if level is null.
      * @since JavaMail 1.4.5
      */
- private String descriptionFrom(Comparator c, Level l, Filter f) {
+ private String descriptionFrom(Comparator<?> c, Level l, Filter f) {
         return "Sorted using "+ (c == null ? "no comparator"
                 : c.getClass().getName()) + ", pushed when "+ l.getName()
                 + ", and " + (f == null ? "no push filter"
@@ -3057,8 +3062,8 @@
 
     private void setMailer(final Message msg) {
         try {
- final Class mail = MailHandler.class;
- final Class k = getClass();
+ final Class<?> mail = MailHandler.class;
+ final Class<?> k = getClass();
             String value;
             if (k == mail) {
                 value = mail.getName();
@@ -3407,6 +3412,7 @@
             } else if (source instanceof Class) {
                 loader = ((Class) source).getClassLoader();
             } else {
+ assert !(source instanceof Class) : source;
                 loader = source.getClass().getClassLoader();
             }
 

diff -r 18da2b1c2511 -r 3b2083eeddb4 mail/src/test/java/com/sun/mail/util/logging/MailHandlerTest.java
--- a/mail/src/test/java/com/sun/mail/util/logging/MailHandlerTest.java Fri Oct 11 15:36:01 2013 -0700
+++ b/mail/src/test/java/com/sun/mail/util/logging/MailHandlerTest.java Fri Oct 11 15:45:09 2013 -0700
@@ -663,6 +663,8 @@
                 fail("Doesn't match the memory handler.");
             }
         }
+
+ assert instance != null;
         instance.setFilter((Filter) null);
 
 
@@ -1396,6 +1398,7 @@
             }
         }
 
+ assert em != null;
         for (int i = 0; i < em.exceptions.size(); i++) {
             Throwable t = em.exceptions.get(i);
             if (t instanceof MessagingException == false) {
@@ -2898,6 +2901,7 @@
         try {
             assertEquals(2, instance.getAttachmentFormatters().length);
             Filter[] filters = new Filter[]{null, null};
+ assert filters != null; //Suppress broken NPE hint with assert.
             assertEquals(instance.getAttachmentFormatters().length, filters.length);
             instance.setAttachmentFilters(filters);
         } catch (RuntimeException re) {
@@ -5470,36 +5474,36 @@
         final LogManager manager = LogManager.getLogManager();
         synchronized (manager) {
             try {
- initGoodTest(MailHandler.class, new Class[0], new Object[0]);
- initBadTest(MailHandler.class, new Class[0], new Object[0]);
+ initGoodTest(MailHandler.class, new Class<?>[0], new Object[0]);
+ initBadTest(MailHandler.class, new Class<?>[0], new Object[0]);
                 initGoodTest(MailHandler.class,
- new Class[]{Integer.TYPE}, new Object[]{10});
+ new Class<?>[]{Integer.TYPE}, new Object[]{10});
                 initBadTest(MailHandler.class,
- new Class[]{Integer.TYPE}, new Object[]{100});
+ new Class<?>[]{Integer.TYPE}, new Object[]{100});
                 initGoodTest(MailHandler.class,
- new Class[]{Properties.class},
+ new Class<?>[]{Properties.class},
                         new Object[]{new Properties()});
                 initBadTest(MailHandler.class,
- new Class[]{Properties.class},
+ new Class<?>[]{Properties.class},
                         new Object[]{new Properties()});
 
 
                 //Test subclass properties.
                 initGoodTest(MailHandlerExt.class,
- new Class[0], new Object[0]);
+ new Class<?>[0], new Object[0]);
                 initBadTest(MailHandlerExt.class,
- new Class[0], new Object[0]);
+ new Class<?>[0], new Object[0]);
 
                 initGoodTest(MailHandlerExt.class,
- new Class[]{Integer.TYPE}, new Object[]{10});
+ new Class<?>[]{Integer.TYPE}, new Object[]{10});
                 initBadTest(MailHandlerExt.class,
- new Class[]{Integer.TYPE}, new Object[]{100});
+ new Class<?>[]{Integer.TYPE}, new Object[]{100});
 
                 initGoodTest(MailHandlerExt.class,
- new Class[]{Properties.class},
+ new Class<?>[]{Properties.class},
                         new Object[]{new Properties()});
                 initBadTest(MailHandlerExt.class,
- new Class[]{Properties.class},
+ new Class<?>[]{Properties.class},
                         new Object[]{new Properties()});
             } finally {
                 manager.reset();
@@ -5520,7 +5524,7 @@
     }
 
     private void initGoodTest(Class<? extends MailHandler> type,
- Class[] types, Object[] params) throws Exception {
+ Class<?>[] types, Object[] params) throws Exception {
 
         final String p = type.getName();
         Properties props = createInitProperties(p);
@@ -5618,7 +5622,7 @@
     }
 
     private void initBadTest(Class<? extends MailHandler> type,
- Class[] types, Object[] params) throws Exception {
+ Class<?>[] types, Object[] params) throws Exception {
         final String encoding = System.getProperty("file.encoding", "8859_1");
         final PrintStream err = System.err;
         ByteArrayOutputStream oldErrors = new ByteArrayOutputStream();
@@ -5691,6 +5695,7 @@
             System.setErr(err);
         }
 
+ assert h != null;
         assertEquals(ErrorManager.class, h.getErrorManager().getClass());
         assertTrue(h.getCapacity() != 10);
         assertTrue(h.getCapacity() != -10);