Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4063734

(reflect) Allow privileged code to override access control when using reflection

XMLWordPrintable

    • Icon: Enhancement Enhancement
    • Resolution: Fixed
    • Icon: P4 P4
    • 1.2.0
    • 1.1.3
    • core-libs
    • 1.2beta1
    • sparc
    • solaris_2.5.1, solaris_2.6
    • Not verified

        Let's say we have a GUI class with many buttons. To handle the button
      actions, we create one inner class per button. Let's also say we want
      sub-classes of this GUI class to be able to override the button
      actions. The easiest way is to create one protected method per action
      listener inner class. Each inner class action listener just calls one
      protected method.

      This approach works fine, but it creates a huge number of inner
      classes (and a lot of .class files). With the reflection package, I
      can write one inner class which is given a Method object. When the
      action listener is called, it calls the invoke() method of the Method
      object.

      This would be great, and it works fine if the GUI class and its
      sub-class are in the same package. If the GUI class is in a package
      and the sub-class is in a top-level application, for example, the code
      fails with an .IllegalAccessException.

      Here is some code which demonstrates the problem. There are two java
      files: Main.java and MyFrame.java. Also included is a Makefile.

      1) Create a directory.
      2) Place Main.java and Makefile in this directory.
      3) Create a sub-directory called COM in this directory.
      4) Place MyFrame.java in this sub-directory.
      5) Run 'make build'.
      6) Run 'make run'.
      7) When the Frame appears, select File / Test.
      8) This should produce the output:

      invoke-problem» make run
      Received unexpected exception:
      java.lang.IllegalAccessException: Main$MyOtherFrame

      As an interesting exercise, make the following modifications:

      1) Move MyFrame.java to the same directory as Main.java.
      2) Edit MyFrame.java to remove the "package COM;" statement.
      3) Change "COM/MyFrame" in Makefile to "MyFrame".
      4) Run 'make build'.
      5) Run 'make run'.
      6) When the Frame appears, select File / Test.
      7) The output is now:

      invoke-problem» make run
      Goodbye!
      Hello!

      This should be the output in BOTH cases. With this error, it
      is difficult to take advantage of the reflections package from user
      packages. The work-around in this case is to create a lot of inner
      classes.


      ########## Makefile ###########
      CLASSPATH = .

      JAVAC = javac

      JAVA = java

      JAR = jar

      RM = /usr/bin/rm -f

      SRCS = COM/MyFrame.java Main.java


      build:
      $(JAVAC) -verbose $(SRCS)


      run:
      @JAVA_HOME=$(JAVA_HOME); export JAVA_HOME; CLASSPATH=$(CLASSPATH); export CLASSPATH; $(JAVA) Main

      clean:
      $(RM) *.class COM/*.class

      ######## Main.java #######
      import COM.*;

      import java.io.*;
      import java.awt.*;

      final class Main
      {

      Main()
      {
      MyFrame frame1 = createAppFrame();
      }

      //**********************************************************************
      // Package Public
      //**********************************************************************

      public static void
      main(
      String[] args)
      {
      new Main();
      }

      MyFrame
      createAppFrame()
      {
      MyOtherFrame frame = new MyOtherFrame();

      frame.setSize(300,200);
      frame.setVisible(true);

      return frame;
      }

      //**********************************************************************
      // Inner Classes
      //**********************************************************************

      //**********************************************************************
      // Class MyOtherFrame
      //**********************************************************************

      class MyOtherFrame
      extends MyFrame
      {

      MyOtherFrame()
      {
      super();

      addFileMenu();
      }

      //----------------------------------------------------------------------

      protected void
      sayHello()
      {
      System.out.println("Goodbye!");
      super.sayHello();
      }

      }

      //**********************************************************************
      // End Inner Classes
      //**********************************************************************

      }
      ######## COM/MyFrame.java ################
      package COM;

      import java.lang.reflect.Method;
      import java.awt.*;
      import java.awt.event.*;

      public abstract class MyFrame
      extends Frame
      {

      public
      MyFrame()
      {
      menuBar = new MenuBar();
      setMenuBar(menuBar);

      // Add a window listener

      addWindowListener(new MyFrameWindowListener());
      }

      protected void
      sayHello()
      {
      System.out.println("Hello!");
      }

      protected void
      addFileMenu()
      {
      Menu fileMenu = new Menu("File");
      menuBar.add(fileMenu);

      fileMenu.add(addMenuButton("sayHello"));
      }

      private MenuItem
      addMenuButton(
      String methodName)
      {
      MenuItem item = new MenuItem("Test");

      try {
      item.addActionListener(
      new MenuButtonListener(getClass().
      getDeclaredMethod(methodName, null)));
      }
      catch (Exception exception) {
      System.out.println("Received unexpected exception:");
      System.out.println(exception);
      }

      return item;
      }

      private MenuBar menuBar;

      //**********************************************************************
      // Inner Classes
      //**********************************************************************

      //**********************************************************************
      // MenuButtonListener
      //**********************************************************************

      private final class MenuButtonListener
      implements ActionListener
      {

      MenuButtonListener(
      Method method)
      {
      this.method = method;
      }

      public void
      actionPerformed(
      ActionEvent e)
      {
      try {
      method.invoke(MyFrame.this, null);
      }
      catch (Exception exception) {
      System.out.println("Received unexpected exception:");
      System.out.println(exception);
      }
      }

      private Method method;

      }

      //**********************************************************************
      // MyFrameWindowListener
      //**********************************************************************

      // The window was opened or closed.

      private final class MyFrameWindowListener
      extends WindowAdapter
      {

      public void
      windowClosing(
      WindowEvent e)
      {
      e.getWindow().setVisible(false);
      }

      }

      //**********************************************************************
      // End Inner Classes
      //**********************************************************************

      }

      ################ dir structure ###########
      find . -name '*' -print
      ./Makefile
      ./COM
      ./COM/MyFrame.java
      ./Main.java

      ################ build ##############
      quebec% make build
      javac COM/MyFrame.java Main.java

      ################ running the application #########
      quebec% make run

      (A java application windows pops up with one 'File'
      menu. Mouse pointing to File->test causes the following error:

      "Received unexpected exception:
       java.lang.IllegalAccessException: Main$MyOtherFrame"

            apalanissunw Anand Palaniswamy (Inactive)
            duke J. Duke
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: