JDK-4486754 : LOGGING APIs: Expected NullPointerException isn't thrown
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.util.logging
  • Affected Version: 1.4.0,1.4.2,5.0
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS:
    generic,linux,solaris,solaris_7,solaris_8,windows_nt generic,linux,solaris,solaris_7,solaris_8,windows_nt
  • CPU: generic,x86,sparc
  • Submitted: 2001-08-01
  • Updated: 2017-05-16
  • Resolved: 2003-08-30
Related Reports
Duplicate :  
Duplicate :  
Relates :  
Relates :  
Description

Name: elR10090			Date: 08/01/2001



The following is the paragraph that talks about NullPointerException
in logging methods and constructors (java/util/logging/package-summary.html
file in javadoc):

    "Null Pointers
    
    In general, unless otherwise noted in the javadoc, methods and contructors
    will throw NullPointerException if passed a null argument. The one broad
    exception to this rule is that the logging convenience methods in the 
    Logger class (the log, logp, log, severe, warning, config, fine, finer,
    and finest methods) will accept null values for all arguments except for 
    the initial Level argument (if any)."
    
There are few methods that do not follow this rule.

1. XMLFormatter.getTail(Handler) also getHead(Handler)

   The following test shows that XMLFormatter.getTail(null) does not throw 
   NullPointerException.
   
   import java.util.logging.*;
   import java.io.*;

   public class gettail003 {
       final static LogManager logManager = LogManager.getLogManager();
       final static XMLFormatter formatter = new XMLFormatter();

       public static void main (String args[]) {
           System.exit(95 + run(args, System.out));
       }

       public static int run(String args[], PrintStream out) {
           try {
               String tail = formatter.getTail(null);
               out.println("# TEST FAILED.");
               out.println("# Tail is \"" + tail + "\", but NullPointerException expected.");
               return 2;
           } catch (NullPointerException e) {
               return 0;
           }  
       }
   }

   The test outputs

   ## TEST FAILED.
   ## Tail is "</log>
   #", but NullPointerException expected.


2. tracked as 4625722
   
3. LogManager.addPropertyChangeListener(PropertyChangeListener),
   LogManager.removePropertyChangeListener(PropertyChangeListener)  

   The method LogManager.addPropertyChangeListener silently returns if 
   PropertyChangeListener is null. However, the following test shows that 
   LogManager.readConfiguration() throws unspecified NullPointerException 
   if null listener is added. So, I believe the method should reject addition
   of null listener.
   
   import java.util.logging.*;
   import java.io.*;

   public class addpcl003 {
       final static LogManager logManager = LogManager.getLogManager();

       public static void main (String args[]) {
           System.exit(95 + run(args, System.out));
       } 

       public static int run(String args[], PrintStream out) {
           logManager.addPropertyChangeListener(null);       
           try {
               logManager.readConfiguration();
           } catch (IOException e) {
               out.println("# Cannot read configuration.");
               e.printStackTrace(out);
           } catch (NullPointerException e) {
               out.println("# Cannot read configuration.");
               e.printStackTrace(out);
           }
           return 0;
       }     
   }
   
   The test outputs:
   
   # Cannot read configuration.
   java.lang.NullPointerException
        at java.beans.PropertyChangeSupport.firePropertyChange(PropertyChangeSupport.java:255)
        at java.util.logging.LogManager.readConfiguration(LogManager.java:613)
        at java.util.logging.LogManager.readConfiguration(LogManager.java:520)
        at Test.run(Test.java:14)
        at Test.main(Test.java:8)
        
    Since null listener should not be added, LogManager.removePropertyChangeListener(null)
    should also throw the exception.
        
4. There are few methods that have unclear specification about NullPointerException.

   a) removeHandler methods:

          Logger.removeHandler(Handler)
          
      On the one hand, according to the paragraph about "Null Pointers", both
      methods shoud throw NPE. On the other, according to the 
      Logger.removeHandler(Handler) spec (for example)
   
          public void removeHandler(Handler handler) throws SecurityException
          Remove a log Handler. 
          Returns silently if the given Handler is not found. 
          Parameters: handler - a logging Handler
          Throws: SecurityException - if a security manager exists and if the 
                  caller does not have LoggingPermission("control").   
               
       null Handler could be interpreted as "not found Handler" and the method
       should not throw any exception.
       
       The following implementation does not throw NPE for both methods.       
       
  b) see  4653375   
   
5. see 4648829
   
This bug affects the following tests from tesbase_nsk:   

    nsk/logging/XMLFormatter/getTail/gettail003
    nsk/logging/Level/Level/level004
    nsk/logging/LogManager/addPropertyChangeListener/addpcl003
    nsk/logging/LogManager/removePropertyChangeListener/rmpcl003
    nsk/logging/LogManager/removeGlobalHandler/rmglh003
    
All tests will appear in the next release r06 of testbase_nsk 
testbase located at:

    /net/sqesvr.eng/export/vsn/VM/testbase/testbase_nsk.v14

======================================================================

Name: elR10090			Date: 08/06/2001



Alexey Gibadullin, ###@###.###

Three more methods should be included to the item 4.

4. c) The method LogManager.getLogger(String) also has unclear 
      specification about NullPointerException:
      
          public Logger getLogger(String name)
          Method to find a named logger. 
          Note that since untrusted code may create loggers with arbitrary 
          names this method should not be relied on to find Loggers for 
          security sensitive logging. 
          Parameters: name - name of the logger
          Returns: matching logger or null if none is found

      On the one hand, the method can throw NPE if logger name is null
      (according to the "Null Pointers" paragraph). But on the other,
      a logger with null name may not be found and the method can 
      return null without throwing an exception.
  
  
4. d) The methods Logger.getAnonymousLogger(resourceBundleName) and 
      Logger.getLogger(name, resourceBundleName) do not specify any
      behavior for the case when resourceBundleName argument is null.

      The Logger(String, String) constructor says that resourceBundleName
      may be null (if none of the messages require localization) explicitly.
      
      It seems that both methods Logger.getAnonymousLogger(String) and 
      Logger.getLogger(String, String) should have the same statement.


======================================================================

Name: elR10090			Date: 09/13/2001



Alexey Gibadullin, ###@###.###

This bug also affects the following test from testbase_nsk:

    nsk/logging/Level/Level_sis/levelsis005

======================================================================
nsk/logging/LogManager/addPropertyChangeListener/addpcl003
nsk/logging/LogManager/removePropertyChangeListener/rmpcl003

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: tiger FIXED IN: tiger INTEGRATED IN: tiger tiger-b18 VERIFIED IN: tiger
14-06-2004

EVALUATION Some spec cleanup needed. ###@###.### 2003-07-23 Item 1: XMLFormatter.java ----------------- /** * Return the header string for a set of XML formatted records. * * @param h The target handler (can be null) * @return header string */ public String getHead(Handler h) { /** * Return the tail string for a set of XML formatted records. * * @param h The target handler (can be null) * @return tail string */ public String getTail(Handler h) { Item 3: LogManager.java --------------- /** * Add an event listener to be invoked when the logging * properties are re-read. * * @param l event listener * @exception SecurityException if a security manager exists and if * the caller does not have LoggingPermission("control"). * @exception NullPointerException if the PropertyChangeListener is null. */ public void addPropertyChangeListener(PropertyChangeListener l) throws SecurityException { /** * Remove an event listener for property change events. * <P> * Returns silently if the given listener is not found. * * @param l event listener (can be null) * @exception SecurityException if a security manager exists and if * the caller does not have LoggingPermission("control"). */ public void removePropertyChangeListener(PropertyChangeListener l) throws SecurityException { Item 4: a) Logger.java =========== /** * Remove a log Handler. * <P> * Returns silently if the given Handler is not found or is null * * @param handler a logging Handler * @exception SecurityException if a security manager exists and if * the caller does not have LoggingPermission("control"). */ public synchronized void removeHandler(Handler handler) throws SecurityException { c) Logger.java =========== /** * Find or create a logger for a named subsystem. If a logger has * already been created with the given name it is returned. Otherwise * a new logger is created. * <p> * If a new logger is created its log level will be configured * based on the LogManager and it will configured to also send logging * output to its parent loggers Handlers. It will be registered in * the LogManager global namespace. * <p> * If the named Logger already exists and does not yet have a * localization resource bundle then the given resource bundle * name is used. If the named Logger already exists and has * a different resource bundle name then an IllegalArgumentException * is thrown. * <p> * @param name A name for the logger. This should * be a dot-separated name and should normally * be based on the package name or class name * of the subsystem, such as java.net * or javax.swing * @param resourceBundleName name of ResourceBundle to be used for localizing * messages for this logger. * @return a suitable Logger * @throws MissingResourceException if the named ResourceBundle cannot be found. * @throws IllegalArgumentException if the Logger already exists and uses * a different resource bundle name. * @throws NullPointerException if the name is null. */ public static synchronized Logger getLogger(String name, String resourceBundleName) { /** * Find or create a logger for a named subsystem. If a logger has * already been created with the given name it is returned. Otherwise * a new logger is created. * <p> * If a new logger is created its log level will be configured * based on the LogManager configuration and it will configured * to also send logging output to its parent's handlers. It will * be registered in the LogManager global namespace. * * @param name A name for the logger. This should * be a dot-separated name and should normally * be based on the package name or class name * of the subsystem, such as java.net * or javax.swing * @return a suitable Logger * @throws NullPointerException if the name is null. */ public static synchronized Logger getLogger(String name) { d) /** * Create an anonymous Logger. The newly created Logger is not * registered in the LogManager namespace. There will be no * access checks on updates to the logger. * <p> * This factory method is primarily intended for use from applets. * Because the resulting Logger is anonymous it can be kept private * by the creating class. This removes the need for normal security * checks, which in turn allows untrusted applet code to update * the control state of the Logger. For example an applet can do * a setLevel or an addHandler on an anonymous Logger. * <p> * Even although the new logger is anonymous, it is configured * to have the root logger ("") as its parent. This means that * by default it inherits its effective level and handlers * from the root logger. * <p> * @param resourceBundleName name of ResourceBundle to be used for localizing * messages for this logger. * May be null if none of the messages require localization. * @return a newly created private Logger * @throws MissingResourceException if the named ResourceBundle cannot be found. */ public static synchronized Logger getAnonymousLogger(String resourceBundleName) { Spec updated as follows ###@###.### 2003-09-09
09-09-2003