-
Bug
-
Resolution: Won't Fix
-
P4
-
None
-
1.1.4, 1.1.5, 1.1.7, 1.2.0, 1.2.2
-
generic, unknown, x86, sparc
-
generic, solaris_2.5, solaris_2.5.1, solaris_2.6, windows_95, windows_nt
Consider a protected field in a class from one package being used in a subclass in another package. The subclass can access that protected field. The compiler, however, refuses to let nested classes of the subclass access them. This seems wrong -- if the subclass and its nested classes can access each other's private fields, it seems bizarre to restrict the nested class from accessing the more-widely-accessible protected fields.
Take, for example, the following classes:
package p;
public class Top {
protected int f;
}
And now its subclass, in the unnamed package:
import p.Top;
class Bad extends Top {
private double d;
void foo() {
Object o = new Object() {
void bar() {
f = 1;
d = 1;
}
};
f = 0;
d = 0;
}
}
If you compile this, you will find the compiler complaining about the anonymous inner class's assignment to the protected field "f", but not its assignment to the private field "d". Both assignments in foo() itself are allowed.
None of this happens if Top is in the same package as Bad, of course.
====
The behavior described above is consistent with the inner classes specification
as currently interpreted by its author. (See comments section.) This issue
is apparently controversial, so I am re-opening this as a specification bug.
Old synopsis was: Nested classes cannot access protected fields in outer class
william.maddox@Eng 1998-03-05
Name: vi73552 Date: 07/01/99
The inner class of a child class is not allowed to access
the protected member of the base class.
1. Create a child class, i.e PhoenixTableUI, that inherits
from BasicTableUI. BasicTableUI contains a protected
attribute named 'table'.
2. In the child class 'PhoenixTableUI' create an inner class
called 'MouseInputHandler' that accesses the protected
attribute, i.e 'table', in the base class.
3. Compile the code with JDK 1.2.1, and you will get the
following compilation error:
Variable table in class javax.swing.plaf.basic.BasicTableUI
not accessible from inner class
com.sempra.phoenix.framework.bean.PhoenixTableUI.MouseInputHandler.
The complete listing of PhoenixTableUI is listed below.
package com.sempra.phoenix.framework.bean;
import javax.swing.plaf.basic.*;
import javax.swing.table.*;
import javax.swing.*;
import javax.swing.event.*;
import java.util.Enumeration;
import java.util.Hashtable;
import java.awt.event.*;
import java.awt.*;
import javax.swing.plaf.*;
import java.util.EventObject;
import javax.swing.text.*;
// Michael: BasicTableUI does not handle custom editors, so modify it
// into PhoenixTableUI
public class PhoenixTableUI extends BasicTableUI
{
//
// The Table's mouse and mouse motion listeners
//
/**
* This inner class is marked "public" due to a compiler bug.
* This class should be treated as a "protected" inner class.
* Instantiate it only within subclasses of BasicTableUI.
*/
public class MouseInputHandler implements MouseInputListener
{
// Workaround for mousePressed bug in AWT 1.1
private boolean phantomMousePressed = false;
// Component recieving mouse events during editing. May not be editorComponent.
private Component dispatchComponent;
// The Table's mouse listener methods.
public void mouseClicked (MouseEvent e) {}
private boolean repostEvent(MouseEvent e)
{
if (dispatchComponent == null)
{
return false;
}
MouseEvent e2 = SwingUtilities.convertMouseEvent(table, e, dispatchComponent);
dispatchComponent.dispatchEvent(e2);
return true;
}
private void setValueIsAdjusting (boolean flag)
{
table.getSelectionModel().setValueIsAdjusting(flag);
table.getColumnModel().getSelectionModel().setValueIsAdjusting(flag);
}
public void mousePressed(MouseEvent e)
{
if (!SwingUtilities. isLeftMouseButton(e))
{
return;
}
if (phantomMousePressed == true)
{
return;
}
phantomMousePressed = true;
Point p = e.getPoint();
int row = table.rowAtPoint(p);
int column = table.columnAtPoint(p);
// The autoscroller can generate drag events outside the Table's range.
if ((column == -1) || (row == -1))
{
return;
}
boolean startedNewEditor = table.editCellAt(row, column, e);
boolean repostEvent;
// Michael: when updateUI is called, table is set to null,
// so check for this condition
if (table == null)
{
repostEvent = startedNewEditor;
}
else
{
repostEvent = table.isEditing() && startedNewEditor;
}
if (repostEvent)
{
Component editorComponent = table.getEditorComponent();
Point p2 = SwingUtilities.convertPoint(table, p, editorComponent);
dispatchComponent = SwingUtilities.getDeepestComponentAt(editorComponent,
p2.x, p2.y);
repostEvent(e);
}
/* Adjust the selection if the event was not forwarded
* to the editor above *or* the editor declares that it
* should change selection even when events are forwarded
* to it.
*/
// Michael: need to check for custom editors
if (!repostEvent || table.getCellEditor().shouldSelectCell(e))
{
PhoenixCellEditor cellEditor = (PhoenixCellEditor)
table.getColumnModel().getColumn(column).getCellEditor();
if (cellEditor == null)
{
table.requestFocus ();
}
else
{
cellEditor.getTableCellEditorComponent ().requestFocus ();
}
setValueIsAdjusting (true);
updateSelection (row, column, e.isControlDown(), e.isShiftDown());
}
}
public void mouseReleased(MouseEvent e)
{
if (!SwingUtilities.isLeftMouseButton(e))
{
return;
}
phantomMousePressed = false;
repostEvent(e);
dispatchComponent = null;
setValueIsAdjusting(false);
}
public void mouseEntered(MouseEvent e)
{
dispatchComponent = null;
}
public void mouseExited(MouseEvent e)
{
dispatchComponent = null;
}
// The Table's mouse motion listener methods.
public void mouseMoved(MouseEvent e)
{
dispatchComponent = null;
}
public void mouseDragged(MouseEvent e)
{
if (!SwingUtilities.isLeftMouseButton(e))
{
return;
}
if (repostEvent(e))
{
return;
}
Point p = e.getPoint();
int row = table.rowAtPoint(p);
int column = table.columnAtPoint(p);
// The autoscroller can generate drag events outside the Table's range.
if ((column == -1) || (row == -1))
{
return;
}
updateSelection(row, column, false, true);
}
}
//
// Factory methods for the Listeners
//
/**
* Creates the mouse listener for the JTable.
*/
protected MouseInputListener createMouseInputListener()
{
return new MouseInputHandler();
}
//
// The installation/uninstall procedures and support
//
public static ComponentUI createUI (JComponent c)
{
return new PhoenixTableUI ();
}
private void updateSelectionModel (ListSelectionModel sm, int index,
boolean toggle, boolean extend)
{
if (!extend)
{
if (!toggle)
{
sm.setSelectionInterval(index, index);
}
else
{
if (sm.isSelectedIndex(index))
{
sm.removeSelectionInterval(index, index);
}
else
{
sm.addSelectionInterval(index, index);
}
}
}
else
{
sm.setLeadSelectionIndex(index);
}
}
private void updateSelection (int rowIndex, int columnIndex,
boolean toggle, boolean extend)
{
// Autoscrolling support.
Rectangle cellRect = table.getCellRect(rowIndex, columnIndex, false);
if (cellRect != null)
{
table.scrollRectToVisible(cellRect);
}
ListSelectionModel rsm = table.getSelectionModel();
ListSelectionModel csm = table.getColumnModel().getSelectionModel();
// Update column selection model
updateSelectionModel(csm, columnIndex, toggle, extend);
// Update row selection model
updateSelectionModel(rsm, rowIndex, toggle, extend);
}
public void installUI(JComponent c)
{
table = (JTable)c;
super.table = table;
rendererPane = new CellRendererPane();
table.add(rendererPane);
installDefaults();
installListeners();
installKeyboardActions();
}
public void uninstallUI(JComponent c)
{
uninstallDefaults();
uninstallListeners();
uninstallKeyboardActions();
table.remove(rendererPane);
rendererPane = null;
table = null;
super.table = null;
}
}
(Review ID: 85088)
======================================================================
From 4196228:
Name: wm38563 Date: 12/09/98
The bug still exists, but the compiler alows
DerivedClass.this.protectedMethod()
in the inner class.
Then java throws an access exception at runtime.
The compiler still complaines about calls to
protectedMethod() in the DerivedClass's InnerClass.
(Review ID: 47287)
======================================================================
Take, for example, the following classes:
package p;
public class Top {
protected int f;
}
And now its subclass, in the unnamed package:
import p.Top;
class Bad extends Top {
private double d;
void foo() {
Object o = new Object() {
void bar() {
f = 1;
d = 1;
}
};
f = 0;
d = 0;
}
}
If you compile this, you will find the compiler complaining about the anonymous inner class's assignment to the protected field "f", but not its assignment to the private field "d". Both assignments in foo() itself are allowed.
None of this happens if Top is in the same package as Bad, of course.
====
The behavior described above is consistent with the inner classes specification
as currently interpreted by its author. (See comments section.) This issue
is apparently controversial, so I am re-opening this as a specification bug.
Old synopsis was: Nested classes cannot access protected fields in outer class
william.maddox@Eng 1998-03-05
Name: vi73552 Date: 07/01/99
The inner class of a child class is not allowed to access
the protected member of the base class.
1. Create a child class, i.e PhoenixTableUI, that inherits
from BasicTableUI. BasicTableUI contains a protected
attribute named 'table'.
2. In the child class 'PhoenixTableUI' create an inner class
called 'MouseInputHandler' that accesses the protected
attribute, i.e 'table', in the base class.
3. Compile the code with JDK 1.2.1, and you will get the
following compilation error:
Variable table in class javax.swing.plaf.basic.BasicTableUI
not accessible from inner class
com.sempra.phoenix.framework.bean.PhoenixTableUI.MouseInputHandler.
The complete listing of PhoenixTableUI is listed below.
package com.sempra.phoenix.framework.bean;
import javax.swing.plaf.basic.*;
import javax.swing.table.*;
import javax.swing.*;
import javax.swing.event.*;
import java.util.Enumeration;
import java.util.Hashtable;
import java.awt.event.*;
import java.awt.*;
import javax.swing.plaf.*;
import java.util.EventObject;
import javax.swing.text.*;
// Michael: BasicTableUI does not handle custom editors, so modify it
// into PhoenixTableUI
public class PhoenixTableUI extends BasicTableUI
{
//
// The Table's mouse and mouse motion listeners
//
/**
* This inner class is marked "public" due to a compiler bug.
* This class should be treated as a "protected" inner class.
* Instantiate it only within subclasses of BasicTableUI.
*/
public class MouseInputHandler implements MouseInputListener
{
// Workaround for mousePressed bug in AWT 1.1
private boolean phantomMousePressed = false;
// Component recieving mouse events during editing. May not be editorComponent.
private Component dispatchComponent;
// The Table's mouse listener methods.
public void mouseClicked (MouseEvent e) {}
private boolean repostEvent(MouseEvent e)
{
if (dispatchComponent == null)
{
return false;
}
MouseEvent e2 = SwingUtilities.convertMouseEvent(table, e, dispatchComponent);
dispatchComponent.dispatchEvent(e2);
return true;
}
private void setValueIsAdjusting (boolean flag)
{
table.getSelectionModel().setValueIsAdjusting(flag);
table.getColumnModel().getSelectionModel().setValueIsAdjusting(flag);
}
public void mousePressed(MouseEvent e)
{
if (!SwingUtilities. isLeftMouseButton(e))
{
return;
}
if (phantomMousePressed == true)
{
return;
}
phantomMousePressed = true;
Point p = e.getPoint();
int row = table.rowAtPoint(p);
int column = table.columnAtPoint(p);
// The autoscroller can generate drag events outside the Table's range.
if ((column == -1) || (row == -1))
{
return;
}
boolean startedNewEditor = table.editCellAt(row, column, e);
boolean repostEvent;
// Michael: when updateUI is called, table is set to null,
// so check for this condition
if (table == null)
{
repostEvent = startedNewEditor;
}
else
{
repostEvent = table.isEditing() && startedNewEditor;
}
if (repostEvent)
{
Component editorComponent = table.getEditorComponent();
Point p2 = SwingUtilities.convertPoint(table, p, editorComponent);
dispatchComponent = SwingUtilities.getDeepestComponentAt(editorComponent,
p2.x, p2.y);
repostEvent(e);
}
/* Adjust the selection if the event was not forwarded
* to the editor above *or* the editor declares that it
* should change selection even when events are forwarded
* to it.
*/
// Michael: need to check for custom editors
if (!repostEvent || table.getCellEditor().shouldSelectCell(e))
{
PhoenixCellEditor cellEditor = (PhoenixCellEditor)
table.getColumnModel().getColumn(column).getCellEditor();
if (cellEditor == null)
{
table.requestFocus ();
}
else
{
cellEditor.getTableCellEditorComponent ().requestFocus ();
}
setValueIsAdjusting (true);
updateSelection (row, column, e.isControlDown(), e.isShiftDown());
}
}
public void mouseReleased(MouseEvent e)
{
if (!SwingUtilities.isLeftMouseButton(e))
{
return;
}
phantomMousePressed = false;
repostEvent(e);
dispatchComponent = null;
setValueIsAdjusting(false);
}
public void mouseEntered(MouseEvent e)
{
dispatchComponent = null;
}
public void mouseExited(MouseEvent e)
{
dispatchComponent = null;
}
// The Table's mouse motion listener methods.
public void mouseMoved(MouseEvent e)
{
dispatchComponent = null;
}
public void mouseDragged(MouseEvent e)
{
if (!SwingUtilities.isLeftMouseButton(e))
{
return;
}
if (repostEvent(e))
{
return;
}
Point p = e.getPoint();
int row = table.rowAtPoint(p);
int column = table.columnAtPoint(p);
// The autoscroller can generate drag events outside the Table's range.
if ((column == -1) || (row == -1))
{
return;
}
updateSelection(row, column, false, true);
}
}
//
// Factory methods for the Listeners
//
/**
* Creates the mouse listener for the JTable.
*/
protected MouseInputListener createMouseInputListener()
{
return new MouseInputHandler();
}
//
// The installation/uninstall procedures and support
//
public static ComponentUI createUI (JComponent c)
{
return new PhoenixTableUI ();
}
private void updateSelectionModel (ListSelectionModel sm, int index,
boolean toggle, boolean extend)
{
if (!extend)
{
if (!toggle)
{
sm.setSelectionInterval(index, index);
}
else
{
if (sm.isSelectedIndex(index))
{
sm.removeSelectionInterval(index, index);
}
else
{
sm.addSelectionInterval(index, index);
}
}
}
else
{
sm.setLeadSelectionIndex(index);
}
}
private void updateSelection (int rowIndex, int columnIndex,
boolean toggle, boolean extend)
{
// Autoscrolling support.
Rectangle cellRect = table.getCellRect(rowIndex, columnIndex, false);
if (cellRect != null)
{
table.scrollRectToVisible(cellRect);
}
ListSelectionModel rsm = table.getSelectionModel();
ListSelectionModel csm = table.getColumnModel().getSelectionModel();
// Update column selection model
updateSelectionModel(csm, columnIndex, toggle, extend);
// Update row selection model
updateSelectionModel(rsm, rowIndex, toggle, extend);
}
public void installUI(JComponent c)
{
table = (JTable)c;
super.table = table;
rendererPane = new CellRendererPane();
table.add(rendererPane);
installDefaults();
installListeners();
installKeyboardActions();
}
public void uninstallUI(JComponent c)
{
uninstallDefaults();
uninstallListeners();
uninstallKeyboardActions();
table.remove(rendererPane);
rendererPane = null;
table = null;
super.table = null;
}
}
(Review ID: 85088)
======================================================================
From 4196228:
Name: wm38563 Date: 12/09/98
The bug still exists, but the compiler alows
DerivedClass.this.protectedMethod()
in the inner class.
Then java throws an access exception at runtime.
The compiler still complaines about calls to
protectedMethod() in the DerivedClass's InnerClass.
(Review ID: 47287)
======================================================================
- duplicates
-
JDK-4251285 Inner class of child class not allowed to access protected attrib of base class
- Closed
-
JDK-4094994 Protected superclass members are not accessible to enclosed inner classes.
- Closed
-
JDK-4196228 RC2 clarification of 4116802
- Closed
-
JDK-4333902 javac incorrectly denies access to protected inner class from subclass
- Closed