提交 d81d6a4a 编写于 作者: M mullan

Merge

...@@ -38,6 +38,7 @@ import java.util.*; ...@@ -38,6 +38,7 @@ import java.util.*;
import sun.awt.*; import sun.awt.*;
import sun.lwawt.macosx.*; import sun.lwawt.macosx.*;
import sun.print.*; import sun.print.*;
import sun.security.util.SecurityConstants;
public abstract class LWToolkit extends SunToolkit implements Runnable { public abstract class LWToolkit extends SunToolkit implements Runnable {
...@@ -502,7 +503,7 @@ public abstract class LWToolkit extends SunToolkit implements Runnable { ...@@ -502,7 +503,7 @@ public abstract class LWToolkit extends SunToolkit implements Runnable {
public Clipboard getSystemClipboard() { public Clipboard getSystemClipboard() {
SecurityManager security = System.getSecurityManager(); SecurityManager security = System.getSecurityManager();
if (security != null) { if (security != null) {
security.checkSystemClipboardAccess(); security.checkPermission(SecurityConstants.AWT.ACCESS_CLIPBOARD_PERMISSION);
} }
synchronized (this) { synchronized (this) {
......
...@@ -87,6 +87,7 @@ class KQueueArrayWrapper { ...@@ -87,6 +87,7 @@ class KQueueArrayWrapper {
private int incomingInterruptFD; private int incomingInterruptFD;
static { static {
IOUtil.load();
initStructSizes(); initStructSizes();
String datamodel = java.security.AccessController.doPrivileged( String datamodel = java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction("sun.arch.data.model") new sun.security.action.GetPropertyAction("sun.arch.data.model")
......
...@@ -246,9 +246,4 @@ class KQueueSelectorImpl ...@@ -246,9 +246,4 @@ class KQueueSelectorImpl
} }
return this; return this;
} }
static {
Util.load();
}
} }
...@@ -28,6 +28,12 @@ ...@@ -28,6 +28,12 @@
#include "util.h" #include "util.h"
#include "SDE.h" #include "SDE.h"
#ifdef __APPLE__
/* use setjmp/longjmp versions that do not save/restore the signal mask */
#define setjmp _setjmp
#define longjmp _longjmp
#endif
/** /**
* This SourceDebugExtension code does not * This SourceDebugExtension code does not
* allow concurrent translation - due to caching method. * allow concurrent translation - due to caching method.
......
...@@ -35,6 +35,7 @@ import java.text.BreakIterator; ...@@ -35,6 +35,7 @@ import java.text.BreakIterator;
import javax.swing.text.AttributeSet; import javax.swing.text.AttributeSet;
import javax.accessibility.*; import javax.accessibility.*;
import java.awt.im.InputMethodRequests; import java.awt.im.InputMethodRequests;
import sun.security.util.SecurityConstants;
/** /**
* The <code>TextComponent</code> class is the superclass of * The <code>TextComponent</code> class is the superclass of
...@@ -728,7 +729,7 @@ public class TextComponent extends Component implements Accessible { ...@@ -728,7 +729,7 @@ public class TextComponent extends Component implements Accessible {
SecurityManager sm = System.getSecurityManager(); SecurityManager sm = System.getSecurityManager();
if (sm == null) return true; if (sm == null) return true;
try { try {
sm.checkSystemClipboardAccess(); sm.checkPermission(SecurityConstants.AWT.ACCESS_CLIPBOARD_PERMISSION);
return true; return true;
} catch (SecurityException e) {} } catch (SecurityException e) {}
return false; return false;
......
...@@ -1270,12 +1270,8 @@ public abstract class Toolkit { ...@@ -1270,12 +1270,8 @@ public abstract class Toolkit {
* <p> * <p>
* Each actual implementation of this method should first check if there * Each actual implementation of this method should first check if there
* is a security manager installed. If there is, the method should call * is a security manager installed. If there is, the method should call
* the security manager's <code>checkSystemClipboardAccess</code> method * the security manager's {@link SecurityManager#checkPermission
* to ensure it's ok to to access the system clipboard. If the default * checkPermission} method to check {@code AWTPermission("accessClipboard")}.
* implementation of <code>checkSystemClipboardAccess</code> is used (that
* is, that method is not overriden), then this results in a call to the
* security manager's <code>checkPermission</code> method with an <code>
* AWTPermission("accessClipboard")</code> permission.
* *
* @return the system Clipboard * @return the system Clipboard
* @exception HeadlessException if GraphicsEnvironment.isHeadless() * @exception HeadlessException if GraphicsEnvironment.isHeadless()
...@@ -1318,14 +1314,9 @@ public abstract class Toolkit { ...@@ -1318,14 +1314,9 @@ public abstract class Toolkit {
* system selection <code>Clipboard</code> as described above. * system selection <code>Clipboard</code> as described above.
* <p> * <p>
* Each actual implementation of this method should first check if there * Each actual implementation of this method should first check if there
* is a <code>SecurityManager</code> installed. If there is, the method * is a security manager installed. If there is, the method should call
* should call the <code>SecurityManager</code>'s * the security manager's {@link SecurityManager#checkPermission
* <code>checkSystemClipboardAccess</code> method to ensure that client * checkPermission} method to check {@code AWTPermission("accessClipboard")}.
* code has access the system selection. If the default implementation of
* <code>checkSystemClipboardAccess</code> is used (that is, if the method
* is not overridden), then this results in a call to the
* <code>SecurityManager</code>'s <code>checkPermission</code> method with
* an <code>AWTPermission("accessClipboard")</code> permission.
* *
* @return the system selection as a <code>Clipboard</code>, or * @return the system selection as a <code>Clipboard</code>, or
* <code>null</code> if the native platform does not support a * <code>null</code> if the native platform does not support a
...@@ -1699,25 +1690,20 @@ public abstract class Toolkit { ...@@ -1699,25 +1690,20 @@ public abstract class Toolkit {
* therefore not assume that the EventQueue instance returned * therefore not assume that the EventQueue instance returned
* by this method will be shared by other applets or the system. * by this method will be shared by other applets or the system.
* *
* <p>First, if there is a security manager, its * <p> If there is a security manager then its
* <code>checkAwtEventQueueAccess</code> * {@link SecurityManager#checkPermission checkPermission} method
* method is called. * is called to check {@code AWTPermission("accessEventQueue")}.
* If the default implementation of <code>checkAwtEventQueueAccess</code>
* is used (that is, that method is not overriden), then this results in
* a call to the security manager's <code>checkPermission</code> method
* with an <code>AWTPermission("accessEventQueue")</code> permission.
* *
* @return the <code>EventQueue</code> object * @return the <code>EventQueue</code> object
* @throws SecurityException * @throws SecurityException
* if a security manager exists and its <code>{@link * if a security manager is set and it denies access to
* java.lang.SecurityManager#checkAwtEventQueueAccess}</code> * the {@code EventQueue}
* method denies access to the <code>EventQueue</code>
* @see java.awt.AWTPermission * @see java.awt.AWTPermission
*/ */
public final EventQueue getSystemEventQueue() { public final EventQueue getSystemEventQueue() {
SecurityManager security = System.getSecurityManager(); SecurityManager security = System.getSecurityManager();
if (security != null) { if (security != null) {
security.checkAwtEventQueueAccess(); security.checkPermission(SecurityConstants.AWT.CHECK_AWT_EVENTQUEUE_PERMISSION);
} }
return getSystemEventQueueImpl(); return getSystemEventQueueImpl();
} }
......
...@@ -195,10 +195,9 @@ public class Window extends Container implements Accessible { ...@@ -195,10 +195,9 @@ public class Window extends Container implements Accessible {
/** /**
* This represents the warning message that is * This represents the warning message that is
* to be displayed in a non secure window. ie : * to be displayed in a non secure window. ie :
* a window that has a security manager installed for * a window that has a security manager installed that denies
* which calling SecurityManager.checkTopLevelWindow() * {@code AWTPermission("showWindowWithoutWarningBanner")}.
* is false. This message can be displayed anywhere in * This message can be displayed anywhere in the window.
* the window.
* *
* @serial * @serial
* @see #getWarningString * @see #getWarningString
...@@ -417,11 +416,10 @@ public class Window extends Container implements Accessible { ...@@ -417,11 +416,10 @@ public class Window extends Container implements Accessible {
* Constructs a new, initially invisible window in default size with the * Constructs a new, initially invisible window in default size with the
* specified {@code GraphicsConfiguration}. * specified {@code GraphicsConfiguration}.
* <p> * <p>
* If there is a security manager, this method first calls * If there is a security manager, then it is invoked to check
* the security manager's {@code checkTopLevelWindow} * {@code AWTPermission("showWindowWithoutWarningBanner")}
* method with {@code this} * to determine whether or not the window must be displayed with
* as its argument to determine whether or not the window * a warning banner.
* must be displayed with a warning banner.
* *
* @param gc the {@code GraphicsConfiguration} of the target screen * @param gc the {@code GraphicsConfiguration} of the target screen
* device. If {@code gc} is {@code null}, the system default * device. If {@code gc} is {@code null}, the system default
...@@ -432,7 +430,6 @@ public class Window extends Container implements Accessible { ...@@ -432,7 +430,6 @@ public class Window extends Container implements Accessible {
* {@code GraphicsEnvironment.isHeadless()} returns {@code true} * {@code GraphicsEnvironment.isHeadless()} returns {@code true}
* *
* @see java.awt.GraphicsEnvironment#isHeadless * @see java.awt.GraphicsEnvironment#isHeadless
* @see java.lang.SecurityManager#checkTopLevelWindow
*/ */
Window(GraphicsConfiguration gc) { Window(GraphicsConfiguration gc) {
init(gc); init(gc);
...@@ -511,25 +508,16 @@ public class Window extends Container implements Accessible { ...@@ -511,25 +508,16 @@ public class Window extends Container implements Accessible {
/** /**
* Constructs a new, initially invisible window in the default size. * Constructs a new, initially invisible window in the default size.
* * <p>
* <p>First, if there is a security manager, its * If there is a security manager set, it is invoked to check
* {@code checkTopLevelWindow} * {@code AWTPermission("showWindowWithoutWarningBanner")}.
* method is called with {@code this} * If that check fails with a {@code SecurityException} then a warning
* as its argument * banner is created.
* to see if it's ok to display the window without a warning banner.
* If the default implementation of {@code checkTopLevelWindow}
* is used (that is, that method is not overriden), then this results in
* a call to the security manager's {@code checkPermission} method
* with an {@code AWTPermission("showWindowWithoutWarningBanner")}
* permission. It that method raises a SecurityException,
* {@code checkTopLevelWindow} returns false, otherwise it
* returns true. If it returns false, a warning banner is created.
* *
* @exception HeadlessException when * @exception HeadlessException when
* {@code GraphicsEnvironment.isHeadless()} returns {@code true} * {@code GraphicsEnvironment.isHeadless()} returns {@code true}
* *
* @see java.awt.GraphicsEnvironment#isHeadless * @see java.awt.GraphicsEnvironment#isHeadless
* @see java.lang.SecurityManager#checkTopLevelWindow
*/ */
Window() throws HeadlessException { Window() throws HeadlessException {
GraphicsEnvironment.checkHeadless(); GraphicsEnvironment.checkHeadless();
...@@ -541,11 +529,10 @@ public class Window extends Container implements Accessible { ...@@ -541,11 +529,10 @@ public class Window extends Container implements Accessible {
* {@code Frame} as its owner. The window will not be focusable * {@code Frame} as its owner. The window will not be focusable
* unless its owner is showing on the screen. * unless its owner is showing on the screen.
* <p> * <p>
* If there is a security manager, this method first calls * If there is a security manager set, it is invoked to check
* the security manager's {@code checkTopLevelWindow} * {@code AWTPermission("showWindowWithoutWarningBanner")}.
* method with {@code this} * If that check fails with a {@code SecurityException} then a warning
* as its argument to determine whether or not the window * banner is created.
* must be displayed with a warning banner.
* *
* @param owner the {@code Frame} to act as owner or {@code null} * @param owner the {@code Frame} to act as owner or {@code null}
* if this window has no owner * if this window has no owner
...@@ -555,7 +542,6 @@ public class Window extends Container implements Accessible { ...@@ -555,7 +542,6 @@ public class Window extends Container implements Accessible {
* {@code GraphicsEnvironment.isHeadless} returns {@code true} * {@code GraphicsEnvironment.isHeadless} returns {@code true}
* *
* @see java.awt.GraphicsEnvironment#isHeadless * @see java.awt.GraphicsEnvironment#isHeadless
* @see java.lang.SecurityManager#checkTopLevelWindow
* @see #isShowing * @see #isShowing
*/ */
public Window(Frame owner) { public Window(Frame owner) {
...@@ -570,11 +556,10 @@ public class Window extends Container implements Accessible { ...@@ -570,11 +556,10 @@ public class Window extends Container implements Accessible {
* unless its nearest owning {@code Frame} or {@code Dialog} * unless its nearest owning {@code Frame} or {@code Dialog}
* is showing on the screen. * is showing on the screen.
* <p> * <p>
* If there is a security manager, this method first calls * If there is a security manager set, it is invoked to check
* the security manager's {@code checkTopLevelWindow} * {@code AWTPermission("showWindowWithoutWarningBanner")}.
* method with {@code this} * If that check fails with a {@code SecurityException} then a
* as its argument to determine whether or not the window * warning banner is created.
* must be displayed with a warning banner.
* *
* @param owner the {@code Window} to act as owner or * @param owner the {@code Window} to act as owner or
* {@code null} if this window has no owner * {@code null} if this window has no owner
...@@ -585,7 +570,6 @@ public class Window extends Container implements Accessible { ...@@ -585,7 +570,6 @@ public class Window extends Container implements Accessible {
* {@code true} * {@code true}
* *
* @see java.awt.GraphicsEnvironment#isHeadless * @see java.awt.GraphicsEnvironment#isHeadless
* @see java.lang.SecurityManager#checkTopLevelWindow
* @see #isShowing * @see #isShowing
* *
* @since 1.2 * @since 1.2
...@@ -603,11 +587,10 @@ public class Window extends Container implements Accessible { ...@@ -603,11 +587,10 @@ public class Window extends Container implements Accessible {
* its nearest owning {@code Frame} or {@code Dialog} * its nearest owning {@code Frame} or {@code Dialog}
* is showing on the screen. * is showing on the screen.
* <p> * <p>
* If there is a security manager, this method first calls * If there is a security manager set, it is invoked to check
* the security manager's {@code checkTopLevelWindow} * {@code AWTPermission("showWindowWithoutWarningBanner")}. If that
* method with {@code this} * check fails with a {@code SecurityException} then a warning banner
* as its argument to determine whether or not the window * is created.
* must be displayed with a warning banner.
* *
* @param owner the window to act as owner or {@code null} * @param owner the window to act as owner or {@code null}
* if this window has no owner * if this window has no owner
...@@ -621,7 +604,6 @@ public class Window extends Container implements Accessible { ...@@ -621,7 +604,6 @@ public class Window extends Container implements Accessible {
* {@code true} * {@code true}
* *
* @see java.awt.GraphicsEnvironment#isHeadless * @see java.awt.GraphicsEnvironment#isHeadless
* @see java.lang.SecurityManager#checkTopLevelWindow
* @see GraphicsConfiguration#getBounds * @see GraphicsConfiguration#getBounds
* @see #isShowing * @see #isShowing
* @since 1.3 * @since 1.3
...@@ -1362,10 +1344,9 @@ public class Window extends Container implements Accessible { ...@@ -1362,10 +1344,9 @@ public class Window extends Container implements Accessible {
* Gets the warning string that is displayed with this window. * Gets the warning string that is displayed with this window.
* If this window is insecure, the warning string is displayed * If this window is insecure, the warning string is displayed
* somewhere in the visible area of the window. A window is * somewhere in the visible area of the window. A window is
* insecure if there is a security manager, and the security * insecure if there is a security manager and the security
* manager's {@code checkTopLevelWindow} method returns * manager denies
* {@code false} when this window is passed to it as an * {@code AWTPermission("showWindowWithoutWarningBanner")}.
* argument.
* <p> * <p>
* If the window is secure, then {@code getWarningString} * If the window is secure, then {@code getWarningString}
* returns {@code null}. If the window is insecure, this * returns {@code null}. If the window is insecure, this
...@@ -1373,7 +1354,6 @@ public class Window extends Container implements Accessible { ...@@ -1373,7 +1354,6 @@ public class Window extends Container implements Accessible {
* {@code awt.appletWarning} * {@code awt.appletWarning}
* and returns the string value of that property. * and returns the string value of that property.
* @return the warning string for this window. * @return the warning string for this window.
* @see java.lang.SecurityManager#checkTopLevelWindow(java.lang.Object)
*/ */
public final String getWarningString() { public final String getWarningString() {
return warningString; return warningString;
...@@ -1383,10 +1363,12 @@ public class Window extends Container implements Accessible { ...@@ -1383,10 +1363,12 @@ public class Window extends Container implements Accessible {
warningString = null; warningString = null;
SecurityManager sm = System.getSecurityManager(); SecurityManager sm = System.getSecurityManager();
if (sm != null) { if (sm != null) {
if (!sm.checkTopLevelWindow(this)) { try {
sm.checkPermission(SecurityConstants.AWT.TOPLEVEL_WINDOW_PERMISSION);
} catch (SecurityException se) {
// make sure the privileged action is only // make sure the privileged action is only
// for getting the property! We don't want the // for getting the property! We don't want the
// above checkTopLevelWindow call to always succeed! // above checkPermission call to always succeed!
warningString = AccessController.doPrivileged( warningString = AccessController.doPrivileged(
new GetPropertyAction("awt.appletWarning", new GetPropertyAction("awt.appletWarning",
"Java Applet Window")); "Java Applet Window"));
......
...@@ -33,6 +33,7 @@ import java.util.Arrays; ...@@ -33,6 +33,7 @@ import java.util.Arrays;
import sun.awt.AWTAccessor; import sun.awt.AWTAccessor;
import sun.util.logging.PlatformLogger; import sun.util.logging.PlatformLogger;
import sun.security.util.SecurityConstants;
/** /**
* The root event class for all component-level input events. * The root event class for all component-level input events.
...@@ -350,7 +351,7 @@ public abstract class InputEvent extends ComponentEvent { ...@@ -350,7 +351,7 @@ public abstract class InputEvent extends ComponentEvent {
SecurityManager sm = System.getSecurityManager(); SecurityManager sm = System.getSecurityManager();
if (sm != null) { if (sm != null) {
try { try {
sm.checkSystemClipboardAccess(); sm.checkPermission(SecurityConstants.AWT.ACCESS_CLIPBOARD_PERMISSION);
b = true; b = true;
} catch (SecurityException se) { } catch (SecurityException se) {
if (logger.isLoggable(PlatformLogger.Level.FINE)) { if (logger.isLoggable(PlatformLogger.Level.FINE)) {
......
...@@ -124,9 +124,11 @@ public final class Console implements Flushable ...@@ -124,9 +124,11 @@ public final class Console implements Flushable
* {@link java.io.Reader#read(java.nio.CharBuffer) read(java.nio.CharBuffer)} * {@link java.io.Reader#read(java.nio.CharBuffer) read(java.nio.CharBuffer)}
* on the returned object will not read in characters beyond the line * on the returned object will not read in characters beyond the line
* bound for each invocation, even if the destination buffer has space for * bound for each invocation, even if the destination buffer has space for
* more characters. A line bound is considered to be any one of a line feed * more characters. The {@code Reader}'s {@code read} methods may block if a
* (<tt>'\n'</tt>), a carriage return (<tt>'\r'</tt>), a carriage return * line bound has not been entered or reached on the console's input device.
* followed immediately by a linefeed, or an end of stream. * A line bound is considered to be any one of a line feed (<tt>'\n'</tt>),
* a carriage return (<tt>'\r'</tt>), a carriage return followed immediately
* by a linefeed, or an end of stream.
* *
* @return The reader associated with this console * @return The reader associated with this console
*/ */
......
...@@ -26,7 +26,24 @@ ...@@ -26,7 +26,24 @@
package java.lang; package java.lang;
/** /**
* A resource that must be closed when it is no longer needed. * An object that may hold resources (such as file or socket handles)
* until it is closed. The {@link #close()} method of an {@code AutoCloseable}
* object is called automatically when exiting a {@code
* try}-with-resources block for which the object has been declared in
* the resource specification header. This construction ensures prompt
* release, avoiding resource exhaustion exceptions and errors that
* may otherwise occur.
*
* @apiNote
* <p>It is possible, and in fact common, for a base class to
* implement AutoCloseable even though not all of its subclasses or
* instances will hold releasable resources. For code that must operate
* in complete generality, or when it is known that the {@code AutoCloseable}
* instance requires resource release, it is recommended to use {@code
* try}-with-resources constructions. However, when using facilities such as
* {@link java.util.stream.Stream} that support both I/O-based and
* non-I/O-based forms, {@code try}-with-resources blocks are in
* general unnecessary when using non-I/O-based forms.
* *
* @author Josh Bloch * @author Josh Bloch
* @since 1.7 * @since 1.7
......
...@@ -1484,22 +1484,24 @@ public final class Class<T> implements java.io.Serializable, ...@@ -1484,22 +1484,24 @@ public final class Class<T> implements java.io.Serializable,
/** /**
* Returns an array containing {@code Field} objects reflecting all * Returns an array containing {@code Field} objects reflecting all
* the accessible public fields of the class or interface represented by * the accessible public fields of the class or interface represented by
* this {@code Class} object. The elements in the array returned are * this {@code Class} object.
* not sorted and are not in any particular order. This method returns an
* array of length 0 if the class or interface has no accessible public
* fields, or if it represents an array class, a primitive type, or void.
* *
* <p> Specifically, if this {@code Class} object represents a class, * <p> If this {@code Class} object represents a class or interface with no
* this method returns the public fields of this class and of all its * no accessible public fields, then this method returns an array of length
* superclasses. If this {@code Class} object represents an * 0.
* interface, this method returns the fields of this interface and of all *
* its superinterfaces. * <p> If this {@code Class} object represents a class, then this method
* returns the public fields of the class and of all its superclasses.
*
* <p> If this {@code Class} object represents an interface, then this
* method returns the fields of the interface and of all its
* superinterfaces.
* *
* <p> The implicit length field for array class is not reflected by this * <p> If this {@code Class} object represents an array type, a primitive
* method. User code should use the methods of class {@code Array} to * type, or void, then this method returns an array of length 0.
* manipulate arrays.
* *
* <p> See <em>The Java Language Specification</em>, sections 8.2 and 8.3. * <p> The elements in the array returned are not sorted and are not in any
* particular order.
* *
* @return the array of {@code Field} objects representing the * @return the array of {@code Field} objects representing the
* public fields * public fields
...@@ -1512,6 +1514,8 @@ public final class Class<T> implements java.io.Serializable, ...@@ -1512,6 +1514,8 @@ public final class Class<T> implements java.io.Serializable,
* of this class. * of this class.
* *
* @since JDK1.1 * @since JDK1.1
* @jls 8.2 Class Members
* @jls 8.3 Field Declarations
*/ */
@CallerSensitive @CallerSensitive
public Field[] getFields() throws SecurityException { public Field[] getFields() throws SecurityException {
...@@ -1595,13 +1599,14 @@ public final class Class<T> implements java.io.Serializable, ...@@ -1595,13 +1599,14 @@ public final class Class<T> implements java.io.Serializable,
/** /**
* Returns a {@code Field} object that reflects the specified public * Returns a {@code Field} object that reflects the specified public member
* member field of the class or interface represented by this * field of the class or interface represented by this {@code Class}
* {@code Class} object. The {@code name} parameter is a * object. The {@code name} parameter is a {@code String} specifying the
* {@code String} specifying the simple name of the desired field. * simple name of the desired field.
* *
* <p> The field to be reflected is determined by the algorithm that * <p> The field to be reflected is determined by the algorithm that
* follows. Let C be the class represented by this object: * follows. Let C be the class or interface represented by this object:
*
* <OL> * <OL>
* <LI> If C declares a public field with the name specified, that is the * <LI> If C declares a public field with the name specified, that is the
* field to be reflected.</LI> * field to be reflected.</LI>
...@@ -1614,7 +1619,8 @@ public final class Class<T> implements java.io.Serializable, ...@@ -1614,7 +1619,8 @@ public final class Class<T> implements java.io.Serializable,
* is thrown.</LI> * is thrown.</LI>
* </OL> * </OL>
* *
* <p> See <em>The Java Language Specification</em>, sections 8.2 and 8.3. * <p> If this {@code Class} object represents an array type, then this
* method does not find the {@code length} field of the array type.
* *
* @param name the field name * @param name the field name
* @return the {@code Field} object of this class specified by * @return the {@code Field} object of this class specified by
...@@ -1631,6 +1637,8 @@ public final class Class<T> implements java.io.Serializable, ...@@ -1631,6 +1637,8 @@ public final class Class<T> implements java.io.Serializable,
* of this class. * of this class.
* *
* @since JDK1.1 * @since JDK1.1
* @jls 8.2 Class Members
* @jls 8.3 Field Declarations
*/ */
@CallerSensitive @CallerSensitive
public Field getField(String name) public Field getField(String name)
...@@ -1800,12 +1808,15 @@ public final class Class<T> implements java.io.Serializable, ...@@ -1800,12 +1808,15 @@ public final class Class<T> implements java.io.Serializable,
* declared by the class or interface represented by this * declared by the class or interface represented by this
* {@code Class} object. This includes public, protected, default * {@code Class} object. This includes public, protected, default
* (package) access, and private fields, but excludes inherited fields. * (package) access, and private fields, but excludes inherited fields.
* The elements in the array returned are not sorted and are not in any
* particular order. This method returns an array of length 0 if the class
* or interface declares no fields, or if this {@code Class} object
* represents a primitive type, an array class, or void.
* *
* <p> See <em>The Java Language Specification</em>, sections 8.2 and 8.3. * <p> If this {@code Class} object represents a class or interface with no
* declared fields, then this method returns an array of length 0.
*
* <p> If this {@code Class} object represents an array type, a primitive
* type, or void, then this method returns an array of length 0.
*
* <p> The elements in the array returned are not sorted and are not in any
* particular order.
* *
* @return the array of {@code Field} objects representing all the * @return the array of {@code Field} objects representing all the
* declared fields of this class * declared fields of this class
...@@ -1831,6 +1842,8 @@ public final class Class<T> implements java.io.Serializable, ...@@ -1831,6 +1842,8 @@ public final class Class<T> implements java.io.Serializable,
* </ul> * </ul>
* *
* @since JDK1.1 * @since JDK1.1
* @jls 8.2 Class Members
* @jls 8.3 Field Declarations
*/ */
@CallerSensitive @CallerSensitive
public Field[] getDeclaredFields() throws SecurityException { public Field[] getDeclaredFields() throws SecurityException {
...@@ -1935,9 +1948,11 @@ public final class Class<T> implements java.io.Serializable, ...@@ -1935,9 +1948,11 @@ public final class Class<T> implements java.io.Serializable,
/** /**
* Returns a {@code Field} object that reflects the specified declared * Returns a {@code Field} object that reflects the specified declared
* field of the class or interface represented by this {@code Class} * field of the class or interface represented by this {@code Class}
* object. The {@code name} parameter is a {@code String} that * object. The {@code name} parameter is a {@code String} that specifies
* specifies the simple name of the desired field. Note that this method * the simple name of the desired field.
* will not reflect the {@code length} field of an array class. *
* <p> If this {@code Class} object represents an array type, then this
* method does not find the {@code length} field of the array type.
* *
* @param name the name of the field * @param name the name of the field
* @return the {@code Field} object for the specified field in this * @return the {@code Field} object for the specified field in this
...@@ -1967,6 +1982,8 @@ public final class Class<T> implements java.io.Serializable, ...@@ -1967,6 +1982,8 @@ public final class Class<T> implements java.io.Serializable,
* </ul> * </ul>
* *
* @since JDK1.1 * @since JDK1.1
* @jls 8.2 Class Members
* @jls 8.3 Field Declarations
*/ */
@CallerSensitive @CallerSensitive
public Field getDeclaredField(String name) public Field getDeclaredField(String name)
......
...@@ -1336,9 +1336,16 @@ class SecurityManager { ...@@ -1336,9 +1336,16 @@ class SecurityManager {
* top-level windows; <code>false</code> otherwise. * top-level windows; <code>false</code> otherwise.
* @exception NullPointerException if the <code>window</code> argument is * @exception NullPointerException if the <code>window</code> argument is
* <code>null</code>. * <code>null</code>.
* @deprecated The dependency on {@code AWTPermission} creates an
* impediment to future modularization of the Java platform.
* Users of this method should instead invoke
* {@link #checkPermission} directly.
* This method will be changed in a future release to check
* the permission {@code java.security.AllPermission}.
* @see java.awt.Window * @see java.awt.Window
* @see #checkPermission(java.security.Permission) checkPermission * @see #checkPermission(java.security.Permission) checkPermission
*/ */
@Deprecated
public boolean checkTopLevelWindow(Object window) { public boolean checkTopLevelWindow(Object window) {
if (window == null) { if (window == null) {
throw new NullPointerException("window can't be null"); throw new NullPointerException("window can't be null");
...@@ -1398,8 +1405,15 @@ class SecurityManager { ...@@ -1398,8 +1405,15 @@ class SecurityManager {
* @since JDK1.1 * @since JDK1.1
* @exception SecurityException if the calling thread does not have * @exception SecurityException if the calling thread does not have
* permission to access the system clipboard. * permission to access the system clipboard.
* @deprecated The dependency on {@code AWTPermission} creates an
* impediment to future modularization of the Java platform.
* Users of this method should instead invoke
* {@link #checkPermission} directly.
* This method will be changed in a future release to check
* the permission {@code java.security.AllPermission}.
* @see #checkPermission(java.security.Permission) checkPermission * @see #checkPermission(java.security.Permission) checkPermission
*/ */
@Deprecated
public void checkSystemClipboardAccess() { public void checkSystemClipboardAccess() {
Permission perm = SecurityConstants.AWT.ACCESS_CLIPBOARD_PERMISSION; Permission perm = SecurityConstants.AWT.ACCESS_CLIPBOARD_PERMISSION;
if (perm == null) { if (perm == null) {
...@@ -1427,8 +1441,15 @@ class SecurityManager { ...@@ -1427,8 +1441,15 @@ class SecurityManager {
* @since JDK1.1 * @since JDK1.1
* @exception SecurityException if the calling thread does not have * @exception SecurityException if the calling thread does not have
* permission to access the AWT event queue. * permission to access the AWT event queue.
* @deprecated The dependency on {@code AWTPermission} creates an
* impediment to future modularization of the Java platform.
* Users of this method should instead invoke
* {@link #checkPermission} directly.
* This method will be changed in a future release to check
* the permission {@code java.security.AllPermission}.
* @see #checkPermission(java.security.Permission) checkPermission * @see #checkPermission(java.security.Permission) checkPermission
*/ */
@Deprecated
public void checkAwtEventQueueAccess() { public void checkAwtEventQueueAccess() {
Permission perm = SecurityConstants.AWT.CHECK_AWT_EVENTQUEUE_PERMISSION; Permission perm = SecurityConstants.AWT.CHECK_AWT_EVENTQUEUE_PERMISSION;
if (perm == null) { if (perm == null) {
......
...@@ -2457,8 +2457,8 @@ public final class String ...@@ -2457,8 +2457,8 @@ public final class String
* String message = String.join(" ", strings); * String message = String.join(" ", strings);
* //message returned is: "Java is cool" * //message returned is: "Java is cool"
* *
* Set<String> strings = new HashSet<>(); * Set<String> strings = new LinkedHashSet<>();
* Strings.add("Java"); strings.add("is"); * strings.add("Java"); strings.add("is");
* strings.add("very"); strings.add("cool"); * strings.add("very"); strings.add("cool");
* String message = String.join("-", strings); * String message = String.join("-", strings);
* //message returned is: "Java-is-very-cool" * //message returned is: "Java-is-very-cool"
...@@ -2652,7 +2652,7 @@ public final class String ...@@ -2652,7 +2652,7 @@ public final class String
* returns {@code "t\u005Cu0131tle"}, where '\u005Cu0131' is the * returns {@code "t\u005Cu0131tle"}, where '\u005Cu0131' is the
* LATIN SMALL LETTER DOTLESS I character. * LATIN SMALL LETTER DOTLESS I character.
* To obtain correct results for locale insensitive strings, use * To obtain correct results for locale insensitive strings, use
* {@code toLowerCase(Locale.ENGLISH)}. * {@code toLowerCase(Locale.ROOT)}.
* <p> * <p>
* @return the {@code String}, converted to lowercase. * @return the {@code String}, converted to lowercase.
* @see java.lang.String#toLowerCase(Locale) * @see java.lang.String#toLowerCase(Locale)
...@@ -2815,7 +2815,7 @@ public final class String ...@@ -2815,7 +2815,7 @@ public final class String
* returns {@code "T\u005Cu0130TLE"}, where '\u005Cu0130' is the * returns {@code "T\u005Cu0130TLE"}, where '\u005Cu0130' is the
* LATIN CAPITAL LETTER I WITH DOT ABOVE character. * LATIN CAPITAL LETTER I WITH DOT ABOVE character.
* To obtain correct results for locale insensitive strings, use * To obtain correct results for locale insensitive strings, use
* {@code toUpperCase(Locale.ENGLISH)}. * {@code toUpperCase(Locale.ROOT)}.
* <p> * <p>
* @return the {@code String}, converted to uppercase. * @return the {@code String}, converted to uppercase.
* @see java.lang.String#toUpperCase(Locale) * @see java.lang.String#toUpperCase(Locale)
......
...@@ -124,7 +124,7 @@ import static sun.invoke.util.Wrapper.isWrapperType; ...@@ -124,7 +124,7 @@ import static sun.invoke.util.Wrapper.isWrapperType;
this.samMethodType = samMethodType; this.samMethodType = samMethodType;
this.implMethod = implMethod; this.implMethod = implMethod;
this.implInfo = new MethodHandleInfo(implMethod); this.implInfo = caller.revealDirect(implMethod);
// @@@ Temporary work-around pending resolution of 8005119 // @@@ Temporary work-around pending resolution of 8005119
this.implKind = (implInfo.getReferenceKind() == MethodHandleInfo.REF_invokeSpecial) this.implKind = (implInfo.getReferenceKind() == MethodHandleInfo.REF_invokeSpecial)
? MethodHandleInfo.REF_invokeVirtual ? MethodHandleInfo.REF_invokeVirtual
......
/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.lang.invoke;
import java.security.*;
import java.lang.reflect.*;
import java.lang.invoke.MethodHandleNatives.Constants;
import java.lang.invoke.MethodHandles.Lookup;
import static java.lang.invoke.MethodHandleStatics.*;
/*
* Auxiliary to MethodHandleInfo, wants to nest in MethodHandleInfo but must be non-public.
*/
/*non-public*/
final
class InfoFromMemberName implements MethodHandleInfo {
private final MemberName member;
private final int referenceKind;
InfoFromMemberName(Lookup lookup, MemberName member, byte referenceKind) {
assert(member.isResolved() || member.isMethodHandleInvoke());
assert(member.referenceKindIsConsistentWith(referenceKind));
this.member = member;
this.referenceKind = referenceKind;
}
@Override
public Class<?> getDeclaringClass() {
return member.getDeclaringClass();
}
@Override
public String getName() {
return member.getName();
}
@Override
public MethodType getMethodType() {
return member.getMethodOrFieldType();
}
@Override
public int getModifiers() {
return member.getModifiers();
}
@Override
public int getReferenceKind() {
return referenceKind;
}
@Override
public String toString() {
return MethodHandleInfo.toString(getReferenceKind(), getDeclaringClass(), getName(), getMethodType());
}
@Override
public <T extends Member> T reflectAs(Class<T> expected, Lookup lookup) {
if (member.isMethodHandleInvoke() && !member.isVarargs()) {
// This member is an instance of a signature-polymorphic method, which cannot be reflected
// A method handle invoker can come in either of two forms:
// A generic placeholder (present in the source code, and varargs)
// and a signature-polymorphic instance (synthetic and not varargs).
// For more information see comments on {@link MethodHandleNatives#linkMethod}.
throw new IllegalArgumentException("cannot reflect signature polymorphic method");
}
Member mem = AccessController.doPrivileged(new PrivilegedAction<Member>() {
public Member run() {
try {
return reflectUnchecked();
} catch (ReflectiveOperationException ex) {
throw new IllegalArgumentException(ex);
}
}
});
try {
Class<?> defc = getDeclaringClass();
byte refKind = (byte) getReferenceKind();
lookup.checkAccess(refKind, defc, convertToMemberName(refKind, mem));
} catch (IllegalAccessException ex) {
throw new IllegalArgumentException(ex);
}
return expected.cast(mem);
}
private Member reflectUnchecked() throws ReflectiveOperationException {
byte refKind = (byte) getReferenceKind();
Class<?> defc = getDeclaringClass();
boolean isPublic = Modifier.isPublic(getModifiers());
if (MethodHandleNatives.refKindIsMethod(refKind)) {
if (isPublic)
return defc.getMethod(getName(), getMethodType().parameterArray());
else
return defc.getDeclaredMethod(getName(), getMethodType().parameterArray());
} else if (MethodHandleNatives.refKindIsConstructor(refKind)) {
if (isPublic)
return defc.getConstructor(getMethodType().parameterArray());
else
return defc.getDeclaredConstructor(getMethodType().parameterArray());
} else if (MethodHandleNatives.refKindIsField(refKind)) {
if (isPublic)
return defc.getField(getName());
else
return defc.getDeclaredField(getName());
} else {
throw new IllegalArgumentException("referenceKind="+refKind);
}
}
private static MemberName convertToMemberName(byte refKind, Member mem) throws IllegalAccessException {
if (mem instanceof Method) {
boolean wantSpecial = (refKind == REF_invokeSpecial);
return new MemberName((Method) mem, wantSpecial);
} else if (mem instanceof Constructor) {
return new MemberName((Constructor) mem);
} else if (mem instanceof Field) {
boolean isSetter = (refKind == REF_putField || refKind == REF_putStatic);
return new MemberName((Field) mem, isSetter);
}
throw new InternalError(mem.getClass().getName());
}
}
...@@ -612,6 +612,12 @@ class InvokerBytecodeGenerator { ...@@ -612,6 +612,12 @@ class InvokerBytecodeGenerator {
return false; // inner class of some sort return false; // inner class of some sort
if (cls.getClassLoader() != MethodHandle.class.getClassLoader()) if (cls.getClassLoader() != MethodHandle.class.getClassLoader())
return false; // not on BCP return false; // not on BCP
MethodType mtype = member.getMethodOrFieldType();
if (!isStaticallyNameable(mtype.returnType()))
return false;
for (Class<?> ptype : mtype.parameterArray())
if (!isStaticallyNameable(ptype))
return false;
if (!member.isPrivate() && VerifyAccess.isSamePackage(MethodHandle.class, cls)) if (!member.isPrivate() && VerifyAccess.isSamePackage(MethodHandle.class, cls))
return true; // in java.lang.invoke package return true; // in java.lang.invoke package
if (member.isPublic() && isStaticallyNameable(cls)) if (member.isPublic() && isStaticallyNameable(cls))
......
...@@ -87,6 +87,7 @@ class Invokers { ...@@ -87,6 +87,7 @@ class Invokers {
lform = invokeForm(mtype, true, MethodTypeForm.LF_EX_INVOKER); lform = invokeForm(mtype, true, MethodTypeForm.LF_EX_INVOKER);
invoker = SimpleMethodHandle.make(invokerType, lform); invoker = SimpleMethodHandle.make(invokerType, lform);
} }
invoker = invoker.withInternalMemberName(MemberName.makeMethodHandleInvoke("invokeExact", mtype));
assert(checkInvoker(invoker)); assert(checkInvoker(invoker));
exactInvoker = invoker; exactInvoker = invoker;
return invoker; return invoker;
...@@ -110,6 +111,7 @@ class Invokers { ...@@ -110,6 +111,7 @@ class Invokers {
lform = invokeForm(mtype, true, MethodTypeForm.LF_GEN_INVOKER); lform = invokeForm(mtype, true, MethodTypeForm.LF_GEN_INVOKER);
invoker = SimpleMethodHandle.make(invokerType, lform); invoker = SimpleMethodHandle.make(invokerType, lform);
} }
invoker = invoker.withInternalMemberName(MemberName.makeMethodHandleInvoke("invoke", mtype));
assert(checkInvoker(invoker)); assert(checkInvoker(invoker));
generalInvoker = invoker; generalInvoker = invoker;
return invoker; return invoker;
......
...@@ -320,14 +320,18 @@ import java.util.Objects; ...@@ -320,14 +320,18 @@ import java.util.Objects;
/** Utility method to query if this member is a method handle invocation (invoke or invokeExact). */ /** Utility method to query if this member is a method handle invocation (invoke or invokeExact). */
public boolean isMethodHandleInvoke() { public boolean isMethodHandleInvoke() {
final int bits = Modifier.NATIVE | Modifier.FINAL; final int bits = MH_INVOKE_MODS;
final int negs = Modifier.STATIC; final int negs = Modifier.STATIC;
if (testFlags(bits | negs, bits) && if (testFlags(bits | negs, bits) &&
clazz == MethodHandle.class) { clazz == MethodHandle.class) {
return name.equals("invoke") || name.equals("invokeExact"); return isMethodHandleInvokeName(name);
} }
return false; return false;
} }
public static boolean isMethodHandleInvokeName(String name) {
return name.equals("invoke") || name.equals("invokeExact");
}
private static final int MH_INVOKE_MODS = Modifier.NATIVE | Modifier.FINAL | Modifier.PUBLIC;
/** Utility method to query the modifier flags of this member. */ /** Utility method to query the modifier flags of this member. */
public boolean isStatic() { public boolean isStatic() {
...@@ -482,12 +486,27 @@ import java.util.Objects; ...@@ -482,12 +486,27 @@ import java.util.Objects;
m.getClass(); // NPE check m.getClass(); // NPE check
// fill in vmtarget, vmindex while we have m in hand: // fill in vmtarget, vmindex while we have m in hand:
MethodHandleNatives.init(this, m); MethodHandleNatives.init(this, m);
if (clazz == null) { // MHN.init failed
if (m.getDeclaringClass() == MethodHandle.class &&
isMethodHandleInvokeName(m.getName())) {
// The JVM did not reify this signature-polymorphic instance.
// Need a special case here.
// See comments on MethodHandleNatives.linkMethod.
MethodType type = MethodType.methodType(m.getReturnType(), m.getParameterTypes());
int flags = flagsMods(IS_METHOD, m.getModifiers(), REF_invokeVirtual);
init(MethodHandle.class, m.getName(), type, flags);
if (isMethodHandleInvoke())
return;
}
throw new LinkageError(m.toString());
}
assert(isResolved() && this.clazz != null); assert(isResolved() && this.clazz != null);
this.name = m.getName(); this.name = m.getName();
if (this.type == null) if (this.type == null)
this.type = new Object[] { m.getReturnType(), m.getParameterTypes() }; this.type = new Object[] { m.getReturnType(), m.getParameterTypes() };
if (wantSpecial) { if (wantSpecial) {
assert(!isAbstract()) : this; if (isAbstract())
throw new AbstractMethodError(this.toString());
if (getReferenceKind() == REF_invokeVirtual) if (getReferenceKind() == REF_invokeVirtual)
changeReferenceKind(REF_invokeSpecial, REF_invokeVirtual); changeReferenceKind(REF_invokeSpecial, REF_invokeVirtual);
else if (getReferenceKind() == REF_invokeInterface) else if (getReferenceKind() == REF_invokeInterface)
...@@ -562,6 +581,22 @@ import java.util.Objects; ...@@ -562,6 +581,22 @@ import java.util.Objects;
initResolved(true); initResolved(true);
} }
/**
* Create a name for a signature-polymorphic invoker.
* This is a placeholder for a signature-polymorphic instance
* (of MH.invokeExact, etc.) that the JVM does not reify.
* See comments on {@link MethodHandleNatives#linkMethod}.
*/
static MemberName makeMethodHandleInvoke(String name, MethodType type) {
return makeMethodHandleInvoke(name, type, MH_INVOKE_MODS | SYNTHETIC);
}
static MemberName makeMethodHandleInvoke(String name, MethodType type, int mods) {
MemberName mem = new MemberName(MethodHandle.class, name, type, REF_invokeVirtual);
mem.flags |= mods; // it's not resolved, but add these modifiers anyway
assert(mem.isMethodHandleInvoke()) : mem;
return mem;
}
// bare-bones constructor; the JVM will fill it in // bare-bones constructor; the JVM will fill it in
MemberName() { } MemberName() { }
......
...@@ -1284,6 +1284,21 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString()); ...@@ -1284,6 +1284,21 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
return null; // DMH returns DMH.member return null; // DMH returns DMH.member
} }
/*non-public*/
MethodHandle withInternalMemberName(MemberName member) {
if (member != null) {
return MethodHandleImpl.makeWrappedMember(this, member);
} else if (internalMemberName() == null) {
// The required internaMemberName is null, and this MH (like most) doesn't have one.
return this;
} else {
// The following case is rare. Mask the internalMemberName by wrapping the MH in a BMH.
MethodHandle result = rebind();
assert (result.internalMemberName() == null);
return result;
}
}
/*non-public*/ /*non-public*/
boolean isInvokeSpecial() { boolean isInvokeSpecial() {
return false; // DMH.Special returns true return false; // DMH.Special returns true
...@@ -1356,7 +1371,7 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString()); ...@@ -1356,7 +1371,7 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
MethodHandle rebind() { MethodHandle rebind() {
// Bind 'this' into a new invoker, of the known class BMH. // Bind 'this' into a new invoker, of the known class BMH.
MethodType type2 = type(); MethodType type2 = type();
LambdaForm form2 = reinvokerForm(type2.basicType()); LambdaForm form2 = reinvokerForm(this);
// form2 = lambda (bmh, arg*) { thismh = bmh[0]; invokeBasic(thismh, arg*) } // form2 = lambda (bmh, arg*) { thismh = bmh[0]; invokeBasic(thismh, arg*) }
return BoundMethodHandle.bindSingle(type2, form2, this); return BoundMethodHandle.bindSingle(type2, form2, this);
} }
...@@ -1369,23 +1384,38 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString()); ...@@ -1369,23 +1384,38 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
/** Create a LF which simply reinvokes a target of the given basic type. /** Create a LF which simply reinvokes a target of the given basic type.
* The target MH must override {@link #reinvokerTarget} to provide the target. * The target MH must override {@link #reinvokerTarget} to provide the target.
*/ */
static LambdaForm reinvokerForm(MethodType mtype) { static LambdaForm reinvokerForm(MethodHandle target) {
mtype = mtype.basicType(); MethodType mtype = target.type().basicType();
LambdaForm reinvoker = mtype.form().cachedLambdaForm(MethodTypeForm.LF_REINVOKE); LambdaForm reinvoker = mtype.form().cachedLambdaForm(MethodTypeForm.LF_REINVOKE);
if (reinvoker != null) return reinvoker; if (reinvoker != null) return reinvoker;
MethodHandle MH_invokeBasic = MethodHandles.basicInvoker(mtype); if (mtype.parameterSlotCount() >= MethodType.MAX_MH_ARITY)
return makeReinvokerForm(target.type(), target); // cannot cache this
reinvoker = makeReinvokerForm(mtype, null);
return mtype.form().setCachedLambdaForm(MethodTypeForm.LF_REINVOKE, reinvoker);
}
private static LambdaForm makeReinvokerForm(MethodType mtype, MethodHandle customTargetOrNull) {
boolean customized = (customTargetOrNull != null);
MethodHandle MH_invokeBasic = customized ? null : MethodHandles.basicInvoker(mtype);
final int THIS_BMH = 0; final int THIS_BMH = 0;
final int ARG_BASE = 1; final int ARG_BASE = 1;
final int ARG_LIMIT = ARG_BASE + mtype.parameterCount(); final int ARG_LIMIT = ARG_BASE + mtype.parameterCount();
int nameCursor = ARG_LIMIT; int nameCursor = ARG_LIMIT;
final int NEXT_MH = nameCursor++; final int NEXT_MH = customized ? -1 : nameCursor++;
final int REINVOKE = nameCursor++; final int REINVOKE = nameCursor++;
LambdaForm.Name[] names = LambdaForm.arguments(nameCursor - ARG_LIMIT, mtype.invokerType()); LambdaForm.Name[] names = LambdaForm.arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
names[NEXT_MH] = new LambdaForm.Name(NF_reinvokerTarget, names[THIS_BMH]); Object[] targetArgs;
Object[] targetArgs = Arrays.copyOfRange(names, THIS_BMH, ARG_LIMIT, Object[].class); MethodHandle targetMH;
targetArgs[0] = names[NEXT_MH]; // overwrite this MH with next MH if (customized) {
names[REINVOKE] = new LambdaForm.Name(MH_invokeBasic, targetArgs); targetArgs = Arrays.copyOfRange(names, ARG_BASE, ARG_LIMIT, Object[].class);
return mtype.form().setCachedLambdaForm(MethodTypeForm.LF_REINVOKE, new LambdaForm("BMH.reinvoke", ARG_LIMIT, names)); targetMH = customTargetOrNull;
} else {
names[NEXT_MH] = new LambdaForm.Name(NF_reinvokerTarget, names[THIS_BMH]);
targetArgs = Arrays.copyOfRange(names, THIS_BMH, ARG_LIMIT, Object[].class);
targetArgs[0] = names[NEXT_MH]; // overwrite this MH with next MH
targetMH = MethodHandles.basicInvoker(mtype);
}
names[REINVOKE] = new LambdaForm.Name(targetMH, targetArgs);
return new LambdaForm("BMH.reinvoke", ARG_LIMIT, names);
} }
private static final LambdaForm.NamedFunction NF_reinvokerTarget; private static final LambdaForm.NamedFunction NF_reinvokerTarget;
......
...@@ -317,7 +317,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -317,7 +317,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
private MethodHandle cache; private MethodHandle cache;
AsVarargsCollector(MethodHandle target, MethodType type, Class<?> arrayType) { AsVarargsCollector(MethodHandle target, MethodType type, Class<?> arrayType) {
super(type, reinvokerForm(type)); super(type, reinvokerForm(target));
this.target = target; this.target = target;
this.arrayType = arrayType; this.arrayType = arrayType;
this.cache = target.asCollector(arrayType, 0); this.cache = target.asCollector(arrayType, 0);
...@@ -778,16 +778,27 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -778,16 +778,27 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
} }
static <T extends Throwable> Empty throwException(T t) throws T { throw t; } static <T extends Throwable> Empty throwException(T t) throws T { throw t; }
static MethodHandle FAKE_METHOD_HANDLE_INVOKE; static MethodHandle[] FAKE_METHOD_HANDLE_INVOKE = new MethodHandle[2];
static static MethodHandle fakeMethodHandleInvoke(MemberName method) {
MethodHandle fakeMethodHandleInvoke(MemberName method) { int idx;
MethodType type = method.getInvocationType(); assert(method.isMethodHandleInvoke());
assert(type.equals(MethodType.methodType(Object.class, Object[].class))); switch (method.getName()) {
MethodHandle mh = FAKE_METHOD_HANDLE_INVOKE; case "invoke": idx = 0; break;
case "invokeExact": idx = 1; break;
default: throw new InternalError(method.getName());
}
MethodHandle mh = FAKE_METHOD_HANDLE_INVOKE[idx];
if (mh != null) return mh; if (mh != null) return mh;
mh = throwException(type.insertParameterTypes(0, UnsupportedOperationException.class)); MethodType type = MethodType.methodType(Object.class, UnsupportedOperationException.class,
MethodHandle.class, Object[].class);
mh = throwException(type);
mh = mh.bindTo(new UnsupportedOperationException("cannot reflectively invoke MethodHandle")); mh = mh.bindTo(new UnsupportedOperationException("cannot reflectively invoke MethodHandle"));
FAKE_METHOD_HANDLE_INVOKE = mh; if (!method.getInvocationType().equals(mh.type()))
throw new InternalError(method.toString());
mh = mh.withInternalMemberName(method);
mh = mh.asVarargsCollector(Object[].class);
assert(method.isVarargs());
FAKE_METHOD_HANDLE_INVOKE[idx] = mh;
return mh; return mh;
} }
...@@ -821,7 +832,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -821,7 +832,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
MethodHandle vamh = prepareForInvoker(mh); MethodHandle vamh = prepareForInvoker(mh);
// Cache the result of makeInjectedInvoker once per argument class. // Cache the result of makeInjectedInvoker once per argument class.
MethodHandle bccInvoker = CV_makeInjectedInvoker.get(hostClass); MethodHandle bccInvoker = CV_makeInjectedInvoker.get(hostClass);
return restoreToType(bccInvoker.bindTo(vamh), mh.type()); return restoreToType(bccInvoker.bindTo(vamh), mh.type(), mh.internalMemberName());
} }
private static MethodHandle makeInjectedInvoker(Class<?> hostClass) { private static MethodHandle makeInjectedInvoker(Class<?> hostClass) {
...@@ -876,8 +887,11 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -876,8 +887,11 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
} }
// Undo the adapter effect of prepareForInvoker: // Undo the adapter effect of prepareForInvoker:
private static MethodHandle restoreToType(MethodHandle vamh, MethodType type) { private static MethodHandle restoreToType(MethodHandle vamh, MethodType type, MemberName member) {
return vamh.asCollector(Object[].class, type.parameterCount()).asType(type); MethodHandle mh = vamh.asCollector(Object[].class, type.parameterCount());
mh = mh.asType(type);
mh = mh.withInternalMemberName(member);
return mh;
} }
private static final MethodHandle MH_checkCallerClass; private static final MethodHandle MH_checkCallerClass;
...@@ -939,4 +953,41 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -939,4 +953,41 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
} }
} }
} }
/** This subclass allows a wrapped method handle to be re-associated with an arbitrary member name. */
static class WrappedMember extends MethodHandle {
private final MethodHandle target;
private final MemberName member;
private WrappedMember(MethodHandle target, MethodType type, MemberName member) {
super(type, reinvokerForm(target));
this.target = target;
this.member = member;
}
@Override
MethodHandle reinvokerTarget() {
return target;
}
@Override
MemberName internalMemberName() {
return member;
}
@Override
boolean isInvokeSpecial() {
return target.isInvokeSpecial();
}
@Override
MethodHandle viewAsType(MethodType newType) {
return new WrappedMember(target, newType, member);
}
}
static MethodHandle makeWrappedMember(MethodHandle target, MemberName member) {
if (member.equals(target.internalMemberName()))
return target;
return new WrappedMember(target, target.type(), member);
}
} }
...@@ -24,80 +24,246 @@ ...@@ -24,80 +24,246 @@
*/ */
package java.lang.invoke; package java.lang.invoke;
import java.lang.reflect.*;
import java.util.*;
import java.lang.invoke.MethodHandleNatives.Constants; import java.lang.invoke.MethodHandleNatives.Constants;
import java.lang.invoke.MethodHandles.Lookup;
import static java.lang.invoke.MethodHandleStatics.*;
/** /**
* Cracking (reflecting) method handles back into their constituent symbolic parts. * A symbolic reference obtained by cracking a method handle into its consitutent symbolic parts.
* To crack a direct method handle, call {@link Lookup#revealDirect Lookup.revealDirect}.
* <p>
* A <em>direct method handle</em> represents a method, constructor, or field without
* any intervening argument bindings or other transformations.
* The method, constructor, or field referred to by a direct method handle is called
* its <em>underlying member</em>.
* Direct method handles may be obtained in any of these ways:
* <ul>
* <li>By executing an {@code ldc} instruction on a {@code CONSTANT_MethodHandle} constant.
* (See the Java Virtual Machine Specification, sections 4.4.8 and 5.4.3.)
* <li>By calling one of the <a href="MethodHandles.Lookup.html#lookups">Lookup Factory Methods</a>,
* such as {@link Lookup#findVirtual Lookup.findVirtual},
* to resolve a symbolic reference into a method handle.
* A symbolic reference consists of a class, name string, and type.
* <li>By calling the factory method {@link Lookup#unreflect Lookup.unreflect}
* or {@link Lookup#unreflectSpecial Lookup.unreflectSpecial}
* to convert a {@link Method} into a method handle.
* <li>By calling the factory method {@link Lookup#unreflectConstructor Lookup.unreflectConstructor}
* to convert a {@link Constructor} into a method handle.
* <li>By calling the factory method {@link Lookup#unreflectGetter Lookup.unreflectGetter}
* or {@link Lookup#unreflectSetter Lookup.unreflectSetter}
* to convert a {@link Field} into a method handle.
* </ul>
* In all of these cases, it is possible to crack the resulting direct method handle
* to recover a symbolic reference for the underlying method, constructor, or field.
* Cracking must be done via a {@code Lookup} object equivalent to that which created
* the target method handle, or which has enough access permissions to recreate
* an equivalent method handle.
* *
* <h1><a name="refkinds"></a>Reference kinds</h1>
* The <a href="MethodHandles.Lookup.html#lookups">Lookup Factory Methods</a>
* correspond to all major use cases for methods, constructors, and fields.
* These use cases may be distinguished using small integers as follows:
* <table border=1 cellpadding=5 summary="reference kinds">
* <tr><th>reference kind</th><th>descriptive name</th><th>scope</th><th>member</th><th>behavior</th></tr>
* <tr>
* <td>{@code 1}</td><td>{@code REF_getField}</td><td>{@code class}</td>
* <td>{@code FT f;}</td><td>{@code (T) this.f;}</td>
* </tr>
* <tr>
* <td>{@code 2}</td><td>{@code REF_getStatic}</td><td>{@code class} or {@code interface}</td>
* <td>{@code static}<br>{@code FT f;}</td><td>{@code (T) C.f;}</td>
* </tr>
* <tr>
* <td>{@code 3}</td><td>{@code REF_putField}</td><td>{@code class}</td>
* <td>{@code FT f;}</td><td>{@code this.f = x;}</td>
* </tr>
* <tr>
* <td>{@code 4}</td><td>{@code REF_putStatic}</td><td>{@code class}</td>
* <td>{@code static}<br>{@code FT f;}</td><td>{@code C.f = arg;}</td>
* </tr>
* <tr>
* <td>{@code 5}</td><td>{@code REF_invokeVirtual}</td><td>{@code class}</td>
* <td>{@code T m(A*);}</td><td>{@code (T) this.m(arg*);}</td>
* </tr>
* <tr>
* <td>{@code 6}</td><td>{@code REF_invokeStatic}</td><td>{@code class} or {@code interface}</td>
* <td>{@code static}<br>{@code T m(A*);}</td><td>{@code (T) C.m(arg*);}</td>
* </tr>
* <tr>
* <td>{@code 7}</td><td>{@code REF_invokeSpecial}</td><td>{@code class} or {@code interface}</td>
* <td>{@code T m(A*);}</td><td>{@code (T) super.m(arg*);}</td>
* </tr>
* <tr>
* <td>{@code 8}</td><td>{@code REF_newInvokeSpecial}</td><td>{@code class}</td>
* <td>{@code C(A*);}</td><td>{@code new C(arg*);}</td>
* </tr>
* <tr>
* <td>{@code 9}</td><td>{@code REF_invokeInterface}</td><td>{@code interface}</td>
* <td>{@code T m(A*);}</td><td>{@code (T) this.m(arg*);}</td>
* </tr>
* </table>
* @since 1.8
*/ */
final class MethodHandleInfo { public
public static final int interface MethodHandleInfo {
REF_getField = Constants.REF_getField, /**
REF_getStatic = Constants.REF_getStatic, * A direct method handle reference kind,
REF_putField = Constants.REF_putField, * as defined in the <a href="MethodHandleInfo.html#refkinds">table above</a>.
REF_putStatic = Constants.REF_putStatic, */
REF_invokeVirtual = Constants.REF_invokeVirtual, public static final int
REF_invokeStatic = Constants.REF_invokeStatic, REF_getField = Constants.REF_getField,
REF_invokeSpecial = Constants.REF_invokeSpecial, REF_getStatic = Constants.REF_getStatic,
REF_newInvokeSpecial = Constants.REF_newInvokeSpecial, REF_putField = Constants.REF_putField,
REF_invokeInterface = Constants.REF_invokeInterface; REF_putStatic = Constants.REF_putStatic,
REF_invokeVirtual = Constants.REF_invokeVirtual,
REF_invokeStatic = Constants.REF_invokeStatic,
REF_invokeSpecial = Constants.REF_invokeSpecial,
REF_newInvokeSpecial = Constants.REF_newInvokeSpecial,
REF_invokeInterface = Constants.REF_invokeInterface;
/**
* Returns the reference kind of the cracked method handle, which in turn
* determines whether the method handle's underlying member was a constructor, method, or field.
* See the <a href="MethodHandleInfo.html#refkinds">table above</a> for definitions.
* @return the integer code for the kind of reference used to access the underlying member
*/
public int getReferenceKind();
private final Class<?> declaringClass; /**
private final String name; * Returns the class in which the cracked method handle's underlying member was defined.
private final MethodType methodType; * @return the declaring class of the underlying member
private final int referenceKind; */
public Class<?> getDeclaringClass();
public MethodHandleInfo(MethodHandle mh) { /**
MemberName mn = mh.internalMemberName(); * Returns the name of the cracked method handle's underlying member.
if (mn == null) throw new IllegalArgumentException("not a direct method handle"); * This is {@code "&lt;init&gt;"} if the underlying member was a constructor,
this.declaringClass = mn.getDeclaringClass(); * else it is a simple method name or field name.
this.name = mn.getName(); * @return the simple name of the underlying member
this.methodType = mn.getMethodOrFieldType(); */
byte refKind = mn.getReferenceKind(); public String getName();
if (refKind == REF_invokeSpecial && !mh.isInvokeSpecial())
// Devirtualized method invocation is usually formally virtual.
refKind = REF_invokeVirtual;
this.referenceKind = refKind;
}
public Class<?> getDeclaringClass() { /**
return declaringClass; * Returns the nominal type of the cracked symbolic reference, expressed as a method type.
} * If the reference is to a constructor, the return type will be {@code void}.
* If it is to a non-static method, the method type will not mention the {@code this} parameter.
* If it is to a field and the requested access is to read the field,
* the method type will have no parameters and return the field type.
* If it is to a field and the requested access is to write the field,
* the method type will have one parameter of the field type and return {@code void}.
* <p>
* Note that original direct method handle may include a leading {@code this} parameter,
* or (in the case of a constructor) will replace the {@code void} return type
* with the constructed class.
* The nominal type does not include any {@code this} parameter,
* and (in the case of a constructor) will return {@code void}.
* @return the type of the underlying member, expressed as a method type
*/
public MethodType getMethodType();
public String getName() { // Utility methods.
return name; // NOTE: class/name/type and reference kind constitute a symbolic reference
} // member and modifiers are an add-on, derived from Core Reflection (or the equivalent)
public MethodType getMethodType() { /**
return methodType; * Reflects the underlying member as a method, constructor, or field object.
} * If the underlying member is public, it is reflected as if by
* {@code getMethod}, {@code getConstructor}, or {@code getField}.
* Otherwise, it is reflected as if by
* {@code getDeclaredMethod}, {@code getDeclaredConstructor}, or {@code getDeclaredField}.
* The underlying member must be accessible to the given lookup object.
* @param <T> the desired type of the result, either {@link Member} or a subtype
* @param expected a class object representing the desired result type {@code T}
* @param lookup the lookup object that created this MethodHandleInfo, or one with equivalent access privileges
* @return a reference to the method, constructor, or field object
* @exception ClassCastException if the member is not of the expected type
* @exception NullPointerException if either argument is {@code null}
* @exception IllegalArgumentException if the underlying member is not accessible to the given lookup object
*/
public <T extends Member> T reflectAs(Class<T> expected, Lookup lookup);
public int getModifiers() { /**
return -1; //TODO * Returns the access modifiers of the underlying member.
} * @return the Java language modifiers for underlying member,
* or -1 if the member cannot be accessed
* @see Modifier
* @see reflectAs
*/
public int getModifiers();
public int getReferenceKind() { /**
return referenceKind; * Determines if the underlying member was a variable arity method or constructor.
} * Such members are represented by method handles that are varargs collectors.
* @implSpec
* This produces a result equivalent to:
* <pre>{@code
* getReferenceKind() >= REF_invokeVirtual && Modifier.isTransient(getModifiers())
* }</pre>
*
*
* @return {@code true} if and only if the underlying member was declared with variable arity.
*/
// spelling derived from java.lang.reflect.Executable, not MethodHandle.isVarargsCollector
public default boolean isVarArgs() {
// fields are never varargs:
if (MethodHandleNatives.refKindIsField((byte) getReferenceKind()))
return false;
// not in the public API: Modifier.VARARGS
final int ACC_VARARGS = 0x00000080; // from JVMS 4.6 (Table 4.20)
assert(ACC_VARARGS == Modifier.TRANSIENT);
return Modifier.isTransient(getModifiers());
}
static String getReferenceKindString(int referenceKind) { /**
switch (referenceKind) { * Returns the descriptive name of the given reference kind,
case REF_getField: return "getfield"; * as defined in the <a href="MethodHandleInfo.html#refkinds">table above</a>.
case REF_getStatic: return "getstatic"; * The conventional prefix "REF_" is omitted.
case REF_putField: return "putfield"; * @param referenceKind an integer code for a kind of reference used to access a class member
case REF_putStatic: return "putstatic"; * @return a mixed-case string such as {@code "getField"}
case REF_invokeVirtual: return "invokevirtual"; * @exception IllegalArgumentException if the argument is not a valid
case REF_invokeStatic: return "invokestatic"; * <a href="MethodHandleInfo.html#refkinds">reference kind number</a>
case REF_invokeSpecial: return "invokespecial"; */
case REF_newInvokeSpecial: return "newinvokespecial"; public static String referenceKindToString(int referenceKind) {
case REF_invokeInterface: return "invokeinterface"; if (!MethodHandleNatives.refKindIsValid(referenceKind))
default: return "UNKNOWN_REFENCE_KIND" + "[" + referenceKind + "]"; throw newIllegalArgumentException("invalid reference kind", referenceKind);
} return MethodHandleNatives.refKindName((byte)referenceKind);
} }
@Override /**
public String toString() { * Returns a string representation for a {@code MethodHandleInfo},
return String.format("%s %s.%s:%s", getReferenceKindString(referenceKind), * given the four parts of its symbolic reference.
declaringClass.getName(), name, methodType); * This is defined to be of the form {@code "RK C.N:MT"}, where {@code RK} is the
* {@linkplain #referenceKindToString reference kind string} for {@code kind},
* {@code C} is the {@linkplain java.lang.Class#getName name} of {@code defc}
* {@code N} is the {@code name}, and
* {@code MT} is the {@code type}.
* These four values may be obtained from the
* {@linkplain #getReferenceKind reference kind},
* {@linkplain #getDeclaringClass declaring class},
* {@linkplain #getName member name},
* and {@linkplain #getMethodType method type}
* of a {@code MethodHandleInfo} object.
*
* @implSpec
* This produces a result equivalent to:
* <pre>{@code
* String.format("%s %s.%s:%s", referenceKindToString(kind), defc.getName(), name, type)
* }</pre>
*
* @param kind the {@linkplain #getReferenceKind reference kind} part of the symbolic reference
* @param defc the {@linkplain #getDeclaringClass declaring class} part of the symbolic reference
* @param name the {@linkplain #getName member name} part of the symbolic reference
* @param type the {@linkplain #getMethodType method type} part of the symbolic reference
* @return a string of the form {@code "RK C.N:MT"}
* @exception IllegalArgumentException if the first argument is not a valid
* <a href="MethodHandleInfo.html#refkinds">reference kind number</a>
* @exception NullPointerException if any reference argument is {@code null}
*/
public static String toString(int kind, Class<?> defc, String name, MethodType type) {
Objects.requireNonNull(name); Objects.requireNonNull(type);
return String.format("%s %s.%s:%s", referenceKindToString(kind), defc.getName(), name, type);
} }
} }
...@@ -205,6 +205,9 @@ class MethodHandleNatives { ...@@ -205,6 +205,9 @@ class MethodHandleNatives {
static boolean refKindIsMethod(byte refKind) { static boolean refKindIsMethod(byte refKind) {
return !refKindIsField(refKind) && (refKind != REF_newInvokeSpecial); return !refKindIsField(refKind) && (refKind != REF_newInvokeSpecial);
} }
static boolean refKindIsConstructor(byte refKind) {
return (refKind == REF_newInvokeSpecial);
}
static boolean refKindHasReceiver(byte refKind) { static boolean refKindHasReceiver(byte refKind) {
assert(refKindIsValid(refKind)); assert(refKindIsValid(refKind));
return (refKind & 1) != 0; return (refKind & 1) != 0;
...@@ -313,7 +316,65 @@ class MethodHandleNatives { ...@@ -313,7 +316,65 @@ class MethodHandleNatives {
* The method assumes the following arguments on the stack: * The method assumes the following arguments on the stack:
* 0: the method handle being invoked * 0: the method handle being invoked
* 1-N: the arguments to the method handle invocation * 1-N: the arguments to the method handle invocation
* N+1: an implicitly added type argument (the given MethodType) * N+1: an optional, implicitly added argument (typically the given MethodType)
* <p>
* The nominal method at such a call site is an instance of
* a signature-polymorphic method (see @PolymorphicSignature).
* Such method instances are user-visible entities which are
* "split" from the generic placeholder method in {@code MethodHandle}.
* (Note that the placeholder method is not identical with any of
* its instances. If invoked reflectively, is guaranteed to throw an
* {@code UnsupportedOperationException}.)
* If the signature-polymorphic method instance is ever reified,
* it appears as a "copy" of the original placeholder
* (a native final member of {@code MethodHandle}) except
* that its type descriptor has shape required by the instance,
* and the method instance is <em>not</em> varargs.
* The method instance is also marked synthetic, since the
* method (by definition) does not appear in Java source code.
* <p>
* The JVM is allowed to reify this method as instance metadata.
* For example, {@code invokeBasic} is always reified.
* But the JVM may instead call {@code linkMethod}.
* If the result is an * ordered pair of a {@code (method, appendix)},
* the method gets all the arguments (0..N inclusive)
* plus the appendix (N+1), and uses the appendix to complete the call.
* In this way, one reusable method (called a "linker method")
* can perform the function of any number of polymorphic instance
* methods.
* <p>
* Linker methods are allowed to be weakly typed, with any or
* all references rewritten to {@code Object} and any primitives
* (except {@code long}/{@code float}/{@code double})
* rewritten to {@code int}.
* A linker method is trusted to return a strongly typed result,
* according to the specific method type descriptor of the
* signature-polymorphic instance it is emulating.
* This can involve (as necessary) a dynamic check using
* data extracted from the appendix argument.
* <p>
* The JVM does not inspect the appendix, other than to pass
* it verbatim to the linker method at every call.
* This means that the JDK runtime has wide latitude
* for choosing the shape of each linker method and its
* corresponding appendix.
* Linker methods should be generated from {@code LambdaForm}s
* so that they do not become visible on stack traces.
* <p>
* The {@code linkMethod} call is free to omit the appendix
* (returning null) and instead emulate the required function
* completely in the linker method.
* As a corner case, if N==255, no appendix is possible.
* In this case, the method returned must be custom-generated to
* to perform any needed type checking.
* <p>
* If the JVM does not reify a method at a call site, but instead
* calls {@code linkMethod}, the corresponding call represented
* in the bytecodes may mention a valid method which is not
* representable with a {@code MemberName}.
* Therefore, use cases for {@code linkMethod} tend to correspond to
* special cases in reflective code such as {@code findVirtual}
* or {@code revealDirect}.
*/ */
static MemberName linkMethod(Class<?> callerClass, int refKind, static MemberName linkMethod(Class<?> callerClass, int refKind,
Class<?> defc, String name, Object type, Class<?> defc, String name, Object type,
......
...@@ -26,8 +26,6 @@ ...@@ -26,8 +26,6 @@
package java.lang.invoke; package java.lang.invoke;
import java.lang.reflect.*; import java.lang.reflect.*;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.List; import java.util.List;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
...@@ -54,6 +52,7 @@ import sun.security.util.SecurityConstants; ...@@ -54,6 +52,7 @@ import sun.security.util.SecurityConstants;
* </ul> * </ul>
* <p> * <p>
* @author John Rose, JSR 292 EG * @author John Rose, JSR 292 EG
* @since 1.7
*/ */
public class MethodHandles { public class MethodHandles {
...@@ -96,6 +95,38 @@ public class MethodHandles { ...@@ -96,6 +95,38 @@ public class MethodHandles {
return Lookup.PUBLIC_LOOKUP; return Lookup.PUBLIC_LOOKUP;
} }
/**
* Performs an unchecked "crack" of a direct method handle.
* The result is as if the user had obtained a lookup object capable enough
* to crack the target method handle, called
* {@link java.lang.invoke.MethodHandles.Lookup#revealDirect Lookup.revealDirect}
* on the target to obtain its symbolic reference, and then called
* {@link java.lang.invoke.MethodHandleInfo#reflectAs MethodHandleInfo.reflectAs}
* to resolve the symbolic reference to a member.
* <p>
* If there is a security manager, its {@code checkPermission} method
* is called with a {@code ReflectPermission("suppressAccessChecks")} permission.
* @param <T> the desired type of the result, either {@link Member} or a subtype
* @param target a direct method handle to crack into symbolic reference components
* @param expected a class object representing the desired result type {@code T}
* @return a reference to the method, constructor, or field object
* @exception SecurityException if the caller is not privileged to call {@code setAccessible}
* @exception NullPointerException if either argument is {@code null}
* @exception IllegalArgumentException if the target is not a direct method handle
* @exception ClassCastException if the member is not of the expected type
* @since 1.8
*/
public static <T extends Member> T
reflectAs(Class<T> expected, MethodHandle target) {
SecurityManager smgr = System.getSecurityManager();
if (smgr != null) smgr.checkPermission(ACCESS_PERMISSION);
Lookup lookup = Lookup.IMPL_LOOKUP; // use maximally privileged lookup
return lookup.revealDirect(target).reflectAs(expected, lookup);
}
// Copied from AccessibleObject, as used by Method.setAccessible, etc.:
static final private java.security.Permission ACCESS_PERMISSION =
new ReflectPermission("suppressAccessChecks");
/** /**
* A <em>lookup object</em> is a factory for creating method handles, * A <em>lookup object</em> is a factory for creating method handles,
* when the creation requires access checking. * when the creation requires access checking.
...@@ -647,6 +678,7 @@ public class MethodHandles { ...@@ -647,6 +678,7 @@ public class MethodHandles {
return invoker(type); return invoker(type);
if ("invokeExact".equals(name)) if ("invokeExact".equals(name))
return exactInvoker(type); return exactInvoker(type);
assert(!MemberName.isMethodHandleInvokeName(name));
return null; return null;
} }
...@@ -892,6 +924,10 @@ return mh1; ...@@ -892,6 +924,10 @@ return mh1;
* @throws NullPointerException if the argument is null * @throws NullPointerException if the argument is null
*/ */
public MethodHandle unreflect(Method m) throws IllegalAccessException { public MethodHandle unreflect(Method m) throws IllegalAccessException {
if (m.getDeclaringClass() == MethodHandle.class) {
MethodHandle mh = unreflectForMH(m);
if (mh != null) return mh;
}
MemberName method = new MemberName(m); MemberName method = new MemberName(m);
byte refKind = method.getReferenceKind(); byte refKind = method.getReferenceKind();
if (refKind == REF_invokeSpecial) if (refKind == REF_invokeSpecial)
...@@ -900,6 +936,12 @@ return mh1; ...@@ -900,6 +936,12 @@ return mh1;
Lookup lookup = m.isAccessible() ? IMPL_LOOKUP : this; Lookup lookup = m.isAccessible() ? IMPL_LOOKUP : this;
return lookup.getDirectMethod(refKind, method.getDeclaringClass(), method, findBoundCallerClass(method)); return lookup.getDirectMethod(refKind, method.getDeclaringClass(), method, findBoundCallerClass(method));
} }
private MethodHandle unreflectForMH(Method m) {
// these names require special lookups because they throw UnsupportedOperationException
if (MemberName.isMethodHandleInvokeName(m.getName()))
return MethodHandleImpl.fakeMethodHandleInvoke(new MemberName(m));
return null;
}
/** /**
* Produces a method handle for a reflected method. * Produces a method handle for a reflected method.
...@@ -1004,6 +1046,46 @@ return mh1; ...@@ -1004,6 +1046,46 @@ return mh1;
return unreflectField(f, true); return unreflectField(f, true);
} }
/**
* Cracks a direct method handle created by this lookup object or a similar one.
* Security and access checks are performed to ensure that this lookup object
* is capable of reproducing the target method handle.
* This means that the cracking may fail if target is a direct method handle
* but was created by an unrelated lookup object.
* @param target a direct method handle to crack into symbolic reference components
* @return a symbolic reference which can be used to reconstruct this method handle from this lookup object
* @exception SecurityException if a security manager is present and it
* <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
* @throws IllegalArgumentException if the target is not a direct method handle or if access checking fails
* @exception NullPointerException if the target is {@code null}
* @since 1.8
*/
public MethodHandleInfo revealDirect(MethodHandle target) {
MemberName member = target.internalMemberName();
if (member == null || (!member.isResolved() && !member.isMethodHandleInvoke()))
throw newIllegalArgumentException("not a direct method handle");
Class<?> defc = member.getDeclaringClass();
byte refKind = member.getReferenceKind();
assert(MethodHandleNatives.refKindIsValid(refKind));
if (refKind == REF_invokeSpecial && !target.isInvokeSpecial())
// Devirtualized method invocation is usually formally virtual.
// To avoid creating extra MemberName objects for this common case,
// we encode this extra degree of freedom using MH.isInvokeSpecial.
refKind = REF_invokeVirtual;
if (refKind == REF_invokeVirtual && defc.isInterface())
// Symbolic reference is through interface but resolves to Object method (toString, etc.)
refKind = REF_invokeInterface;
// Check SM permissions and member access before cracking.
try {
checkSecurityManager(defc, member);
checkAccess(refKind, defc, member);
} catch (IllegalAccessException ex) {
throw new IllegalArgumentException(ex);
}
// Produce the handle to the results.
return new InfoFromMemberName(this, member, refKind);
}
/// Helper methods, all package-private. /// Helper methods, all package-private.
MemberName resolveOrFail(byte refKind, Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException { MemberName resolveOrFail(byte refKind, Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
...@@ -1201,12 +1283,12 @@ return mh1; ...@@ -1201,12 +1283,12 @@ return mh1;
private MethodHandle getDirectMethodCommon(byte refKind, Class<?> refc, MemberName method, private MethodHandle getDirectMethodCommon(byte refKind, Class<?> refc, MemberName method,
boolean doRestrict, Class<?> callerClass) throws IllegalAccessException { boolean doRestrict, Class<?> callerClass) throws IllegalAccessException {
checkMethod(refKind, refc, method); checkMethod(refKind, refc, method);
if (method.isMethodHandleInvoke()) assert(!method.isMethodHandleInvoke());
return fakeMethodHandleInvoke(method);
Class<?> refcAsSuper; Class<?> refcAsSuper;
if (refKind == REF_invokeSpecial && if (refKind == REF_invokeSpecial &&
refc != lookupClass() && refc != lookupClass() &&
!refc.isInterface() &&
refc != (refcAsSuper = lookupClass().getSuperclass()) && refc != (refcAsSuper = lookupClass().getSuperclass()) &&
refc.isAssignableFrom(lookupClass())) { refc.isAssignableFrom(lookupClass())) {
assert(!method.getName().equals("<init>")); // not this code path assert(!method.getName().equals("<init>")); // not this code path
...@@ -1234,9 +1316,6 @@ return mh1; ...@@ -1234,9 +1316,6 @@ return mh1;
mh = restrictReceiver(method, mh, lookupClass()); mh = restrictReceiver(method, mh, lookupClass());
return mh; return mh;
} }
private MethodHandle fakeMethodHandleInvoke(MemberName method) {
return throwException(method.getReturnType(), UnsupportedOperationException.class);
}
private MethodHandle maybeBindCaller(MemberName method, MethodHandle mh, private MethodHandle maybeBindCaller(MemberName method, MethodHandle mh,
Class<?> callerClass) Class<?> callerClass)
throws IllegalAccessException { throws IllegalAccessException {
......
...@@ -225,7 +225,7 @@ public final class SerializedLambda implements Serializable { ...@@ -225,7 +225,7 @@ public final class SerializedLambda implements Serializable {
@Override @Override
public String toString() { public String toString() {
String implKind=MethodHandleInfo.getReferenceKindString(implMethodKind); String implKind=MethodHandleInfo.referenceKindToString(implMethodKind);
return String.format("SerializedLambda[%s=%s, %s=%s.%s:%s, " + return String.format("SerializedLambda[%s=%s, %s=%s.%s:%s, " +
"%s=%s %s.%s:%s, %s=%s, %s=%d]", "%s=%s %s.%s:%s, %s=%s, %s=%d]",
"capturingClass", capturingClass, "capturingClass", capturingClass,
......
...@@ -292,13 +292,17 @@ public final class IDN { ...@@ -292,13 +292,17 @@ public final class IDN {
if (useSTD3ASCIIRules) { if (useSTD3ASCIIRules) {
for (int i = 0; i < dest.length(); i++) { for (int i = 0; i < dest.length(); i++) {
int c = dest.charAt(i); int c = dest.charAt(i);
if (!isLDHChar(c)) { if (isNonLDHAsciiCodePoint(c)) {
throw new IllegalArgumentException("Contains non-LDH characters"); throw new IllegalArgumentException(
"Contains non-LDH ASCII characters");
} }
} }
if (dest.charAt(0) == '-' || dest.charAt(dest.length() - 1) == '-') { if (dest.charAt(0) == '-' ||
throw new IllegalArgumentException("Has leading or trailing hyphen"); dest.charAt(dest.length() - 1) == '-') {
throw new IllegalArgumentException(
"Has leading or trailing hyphen");
} }
} }
...@@ -401,26 +405,20 @@ public final class IDN { ...@@ -401,26 +405,20 @@ public final class IDN {
// //
// LDH stands for "letter/digit/hyphen", with characters restricted to the // LDH stands for "letter/digit/hyphen", with characters restricted to the
// 26-letter Latin alphabet <A-Z a-z>, the digits <0-9>, and the hyphen // 26-letter Latin alphabet <A-Z a-z>, the digits <0-9>, and the hyphen
// <-> // <->.
// non-LDH = 0..0x2C, 0x2E..0x2F, 0x3A..0x40, 0x56..0x60, 0x7B..0x7F // Non LDH refers to characters in the ASCII range, but which are not
// letters, digits or the hypen.
// //
private static boolean isLDHChar(int ch){ // non-LDH = 0..0x2C, 0x2E..0x2F, 0x3A..0x40, 0x5B..0x60, 0x7B..0x7F
// high runner case //
if(ch > 0x007A){ private static boolean isNonLDHAsciiCodePoint(int ch){
return false; return (0x0000 <= ch && ch <= 0x002C) ||
} (0x002E <= ch && ch <= 0x002F) ||
//['-' '0'..'9' 'A'..'Z' 'a'..'z'] (0x003A <= ch && ch <= 0x0040) ||
if((ch == 0x002D) || (0x005B <= ch && ch <= 0x0060) ||
(0x0030 <= ch && ch <= 0x0039) || (0x007B <= ch && ch <= 0x007F);
(0x0041 <= ch && ch <= 0x005A) ||
(0x0061 <= ch && ch <= 0x007A)
){
return true;
}
return false;
} }
// //
// search dots in a string and return the index of that character; // search dots in a string and return the index of that character;
// or if there is no dots, return the length of input string // or if there is no dots, return the length of input string
......
...@@ -25,34 +25,56 @@ ...@@ -25,34 +25,56 @@
package java.nio.file; package java.nio.file;
import java.nio.file.attribute.*;
import java.nio.file.spi.FileSystemProvider;
import java.nio.file.spi.FileTypeDetector;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.SeekableByteChannel;
import java.io.Closeable;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.io.IOException; import java.io.Reader;
import java.io.UncheckedIOException; import java.io.UncheckedIOException;
import java.util.*; import java.io.Writer;
import java.util.function.BiPredicate; import java.nio.channels.Channels;
import java.util.stream.CloseableStream; import java.nio.channels.FileChannel;
import java.util.stream.DelegatingStream; import java.nio.channels.SeekableByteChannel;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder; import java.nio.charset.CharsetEncoder;
import java.nio.file.attribute.BasicFileAttributeView;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.DosFileAttributes;
import java.nio.file.attribute.FileAttribute;
import java.nio.file.attribute.FileAttributeView;
import java.nio.file.attribute.FileOwnerAttributeView;
import java.nio.file.attribute.FileStoreAttributeView;
import java.nio.file.attribute.FileTime;
import java.nio.file.attribute.PosixFileAttributeView;
import java.nio.file.attribute.PosixFileAttributes;
import java.nio.file.attribute.PosixFilePermission;
import java.nio.file.attribute.UserPrincipal;
import java.nio.file.spi.FileSystemProvider;
import java.nio.file.spi.FileTypeDetector;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.function.BiPredicate;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
/** /**
* This class consists exclusively of static methods that operate on files, * This class consists exclusively of static methods that operate on files,
...@@ -74,6 +96,21 @@ public final class Files { ...@@ -74,6 +96,21 @@ public final class Files {
return path.getFileSystem().provider(); return path.getFileSystem().provider();
} }
/**
* Convert a Closeable to a Runnable by converting checked IOException
* to UncheckedIOException
*/
private static Runnable asUncheckedRunnable(Closeable c) {
return () -> {
try {
c.close();
}
catch (IOException e) {
throw new UncheckedIOException(e);
}
};
}
// -- File contents -- // -- File contents --
/** /**
...@@ -3228,29 +3265,7 @@ public final class Files { ...@@ -3228,29 +3265,7 @@ public final class Files {
// -- Stream APIs -- // -- Stream APIs --
/** /**
* Implementation of CloseableStream * Return a lazily populated {@code Stream}, the elements of
*/
private static class DelegatingCloseableStream<T> extends DelegatingStream<T>
implements CloseableStream<T>
{
private final Closeable closeable;
DelegatingCloseableStream(Closeable c, Stream<T> delegate) {
super(delegate);
this.closeable = c;
}
public void close() {
try {
closeable.close();
} catch (IOException ex) {
throw new UncheckedIOException(ex);
}
}
}
/**
* Return a lazily populated {@code CloseableStream}, the elements of
* which are the entries in the directory. The listing is not recursive. * which are the entries in the directory. The listing is not recursive.
* *
* <p> The elements of the stream are {@link Path} objects that are * <p> The elements of the stream are {@link Path} objects that are
...@@ -3264,10 +3279,13 @@ public final class Files { ...@@ -3264,10 +3279,13 @@ public final class Files {
* reflect updates to the directory that occur after returning from this * reflect updates to the directory that occur after returning from this
* method. * method.
* *
* <p> When not using the try-with-resources construct, then the stream's * <p> The returned stream encapsulates a {@link DirectoryStream}.
* {@link CloseableStream#close close} method should be invoked after the * If timely disposal of file system resources is required, the
* operation is completed so as to free any resources held for the open * {@code try}-with-resources construct should be used to ensure that the
* directory. Operating on a closed stream behaves as if the end of stream * stream's {@link Stream#close close} method is invoked after the stream
* operations are completed.
*
* <p> Operating on a closed stream behaves as if the end of stream
* has been reached. Due to read-ahead, one or more elements may be * has been reached. Due to read-ahead, one or more elements may be
* returned after the stream has been closed. * returned after the stream has been closed.
* *
...@@ -3278,7 +3296,7 @@ public final class Files { ...@@ -3278,7 +3296,7 @@ public final class Files {
* *
* @param dir The path to the directory * @param dir The path to the directory
* *
* @return The {@code CloseableStream} describing the content of the * @return The {@code Stream} describing the content of the
* directory * directory
* *
* @throws NotDirectoryException * @throws NotDirectoryException
...@@ -3294,43 +3312,54 @@ public final class Files { ...@@ -3294,43 +3312,54 @@ public final class Files {
* @see #newDirectoryStream(Path) * @see #newDirectoryStream(Path)
* @since 1.8 * @since 1.8
*/ */
public static CloseableStream<Path> list(Path dir) throws IOException { public static Stream<Path> list(Path dir) throws IOException {
DirectoryStream<Path> ds = Files.newDirectoryStream(dir); DirectoryStream<Path> ds = Files.newDirectoryStream(dir);
final Iterator<Path> delegate = ds.iterator(); try {
final Iterator<Path> delegate = ds.iterator();
// Re-wrap DirectoryIteratorException to UncheckedIOException
Iterator<Path> it = new Iterator<Path>() { // Re-wrap DirectoryIteratorException to UncheckedIOException
public boolean hasNext() { Iterator<Path> it = new Iterator<Path>() {
try { @Override
return delegate.hasNext(); public boolean hasNext() {
} catch (DirectoryIteratorException e) { try {
throw new UncheckedIOException(e.getCause()); return delegate.hasNext();
} catch (DirectoryIteratorException e) {
throw new UncheckedIOException(e.getCause());
}
} }
} @Override
public Path next() { public Path next() {
try { try {
return delegate.next(); return delegate.next();
} catch (DirectoryIteratorException e) { } catch (DirectoryIteratorException e) {
throw new UncheckedIOException(e.getCause()); throw new UncheckedIOException(e.getCause());
}
} }
} };
};
Stream<Path> s = StreamSupport.stream( return StreamSupport.stream(Spliterators.spliteratorUnknownSize(it, Spliterator.DISTINCT), false)
Spliterators.spliteratorUnknownSize(it, Spliterator.DISTINCT), .onClose(asUncheckedRunnable(ds));
false); } catch (Error|RuntimeException e) {
return new DelegatingCloseableStream<>(ds, s); try {
ds.close();
} catch (IOException ex) {
try {
e.addSuppressed(ex);
} catch (Throwable ignore) {}
}
throw e;
}
} }
/** /**
* Return a {@code CloseableStream} that is lazily populated with {@code * Return a {@code Stream} that is lazily populated with {@code
* Path} by walking the file tree rooted at a given starting file. The * Path} by walking the file tree rooted at a given starting file. The
* file tree is traversed <em>depth-first</em>, the elements in the stream * file tree is traversed <em>depth-first</em>, the elements in the stream
* are {@link Path} objects that are obtained as if by {@link * are {@link Path} objects that are obtained as if by {@link
* Path#resolve(Path) resolving} the relative path against {@code start}. * Path#resolve(Path) resolving} the relative path against {@code start}.
* *
* <p> The {@code stream} walks the file tree as elements are consumed. * <p> The {@code stream} walks the file tree as elements are consumed.
* The {@code CloseableStream} returned is guaranteed to have at least one * The {@code Stream} returned is guaranteed to have at least one
* element, the starting file itself. For each file visited, the stream * element, the starting file itself. For each file visited, the stream
* attempts to read its {@link BasicFileAttributes}. If the file is a * attempts to read its {@link BasicFileAttributes}. If the file is a
* directory and can be opened successfully, entries in the directory, and * directory and can be opened successfully, entries in the directory, and
...@@ -3370,10 +3399,11 @@ public final class Files { ...@@ -3370,10 +3399,11 @@ public final class Files {
* <p> When a security manager is installed and it denies access to a file * <p> When a security manager is installed and it denies access to a file
* (or directory), then it is ignored and not included in the stream. * (or directory), then it is ignored and not included in the stream.
* *
* <p> When not using the try-with-resources construct, then the stream's * <p> The returned stream encapsulates one or more {@link DirectoryStream}s.
* {@link CloseableStream#close close} method should be invoked after the * If timely disposal of file system resources is required, the
* operation is completed so as to free any resources held for the open * {@code try}-with-resources construct should be used to ensure that the
* directory. Operate the stream after it is closed will throw an * stream's {@link Stream#close close} method is invoked after the stream
* operations are completed. Operating on a closed stream will result in an
* {@link java.lang.IllegalStateException}. * {@link java.lang.IllegalStateException}.
* *
* <p> If an {@link IOException} is thrown when accessing the directory * <p> If an {@link IOException} is thrown when accessing the directory
...@@ -3388,7 +3418,7 @@ public final class Files { ...@@ -3388,7 +3418,7 @@ public final class Files {
* @param options * @param options
* options to configure the traversal * options to configure the traversal
* *
* @return the {@link CloseableStream} of {@link Path} * @return the {@link Stream} of {@link Path}
* *
* @throws IllegalArgumentException * @throws IllegalArgumentException
* if the {@code maxDepth} parameter is negative * if the {@code maxDepth} parameter is negative
...@@ -3401,21 +3431,22 @@ public final class Files { ...@@ -3401,21 +3431,22 @@ public final class Files {
* if an I/O error is thrown when accessing the starting file. * if an I/O error is thrown when accessing the starting file.
* @since 1.8 * @since 1.8
*/ */
public static CloseableStream<Path> walk(Path start, int maxDepth, public static Stream<Path> walk(Path start, int maxDepth,
FileVisitOption... options) FileVisitOption... options)
throws IOException throws IOException {
{
FileTreeIterator iterator = new FileTreeIterator(start, maxDepth, options); FileTreeIterator iterator = new FileTreeIterator(start, maxDepth, options);
try {
Stream<Path> s = StreamSupport.stream( return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.DISTINCT), false)
Spliterators.spliteratorUnknownSize(iterator, Spliterator.DISTINCT), .onClose(iterator::close)
false). .map(entry -> entry.file());
map(entry -> entry.file()); } catch (Error|RuntimeException e) {
return new DelegatingCloseableStream<>(iterator, s); iterator.close();
throw e;
}
} }
/** /**
* Return a {@code CloseableStream} that is lazily populated with {@code * Return a {@code Stream} that is lazily populated with {@code
* Path} by walking the file tree rooted at a given starting file. The * Path} by walking the file tree rooted at a given starting file. The
* file tree is traversed <em>depth-first</em>, the elements in the stream * file tree is traversed <em>depth-first</em>, the elements in the stream
* are {@link Path} objects that are obtained as if by {@link * are {@link Path} objects that are obtained as if by {@link
...@@ -3428,12 +3459,19 @@ public final class Files { ...@@ -3428,12 +3459,19 @@ public final class Files {
* </pre></blockquote> * </pre></blockquote>
* In other words, it visits all levels of the file tree. * In other words, it visits all levels of the file tree.
* *
* <p> The returned stream encapsulates one or more {@link DirectoryStream}s.
* If timely disposal of file system resources is required, the
* {@code try}-with-resources construct should be used to ensure that the
* stream's {@link Stream#close close} method is invoked after the stream
* operations are completed. Operating on a closed stream will result in an
* {@link java.lang.IllegalStateException}.
*
* @param start * @param start
* the starting file * the starting file
* @param options * @param options
* options to configure the traversal * options to configure the traversal
* *
* @return the {@link CloseableStream} of {@link Path} * @return the {@link Stream} of {@link Path}
* *
* @throws SecurityException * @throws SecurityException
* If the security manager denies access to the starting file. * If the security manager denies access to the starting file.
...@@ -3446,15 +3484,14 @@ public final class Files { ...@@ -3446,15 +3484,14 @@ public final class Files {
* @see #walk(Path, int, FileVisitOption...) * @see #walk(Path, int, FileVisitOption...)
* @since 1.8 * @since 1.8
*/ */
public static CloseableStream<Path> walk(Path start, public static Stream<Path> walk(Path start,
FileVisitOption... options) FileVisitOption... options)
throws IOException throws IOException {
{
return walk(start, Integer.MAX_VALUE, options); return walk(start, Integer.MAX_VALUE, options);
} }
/** /**
* Return a {@code CloseableStream} that is lazily populated with {@code * Return a {@code Stream} that is lazily populated with {@code
* Path} by searching for files in a file tree rooted at a given starting * Path} by searching for files in a file tree rooted at a given starting
* file. * file.
* *
...@@ -3463,12 +3500,19 @@ public final class Files { ...@@ -3463,12 +3500,19 @@ public final class Files {
* {@link BiPredicate} is invoked with its {@link Path} and {@link * {@link BiPredicate} is invoked with its {@link Path} and {@link
* BasicFileAttributes}. The {@code Path} object is obtained as if by * BasicFileAttributes}. The {@code Path} object is obtained as if by
* {@link Path#resolve(Path) resolving} the relative path against {@code * {@link Path#resolve(Path) resolving} the relative path against {@code
* start} and is only included in the returned {@link CloseableStream} if * start} and is only included in the returned {@link Stream} if
* the {@code BiPredicate} returns true. Compare to calling {@link * the {@code BiPredicate} returns true. Compare to calling {@link
* java.util.stream.Stream#filter filter} on the {@code Stream} * java.util.stream.Stream#filter filter} on the {@code Stream}
* returned by {@code walk} method, this method may be more efficient by * returned by {@code walk} method, this method may be more efficient by
* avoiding redundant retrieval of the {@code BasicFileAttributes}. * avoiding redundant retrieval of the {@code BasicFileAttributes}.
* *
* <p> The returned stream encapsulates one or more {@link DirectoryStream}s.
* If timely disposal of file system resources is required, the
* {@code try}-with-resources construct should be used to ensure that the
* stream's {@link Stream#close close} method is invoked after the stream
* operations are completed. Operating on a closed stream will result in an
* {@link java.lang.IllegalStateException}.
*
* <p> If an {@link IOException} is thrown when accessing the directory * <p> If an {@link IOException} is thrown when accessing the directory
* after returned from this method, it is wrapped in an {@link * after returned from this method, it is wrapped in an {@link
* UncheckedIOException} which will be thrown from the method that caused * UncheckedIOException} which will be thrown from the method that caused
...@@ -3484,7 +3528,7 @@ public final class Files { ...@@ -3484,7 +3528,7 @@ public final class Files {
* @param options * @param options
* options to configure the traversal * options to configure the traversal
* *
* @return the {@link CloseableStream} of {@link Path} * @return the {@link Stream} of {@link Path}
* *
* @throws IllegalArgumentException * @throws IllegalArgumentException
* if the {@code maxDepth} parameter is negative * if the {@code maxDepth} parameter is negative
...@@ -3499,24 +3543,25 @@ public final class Files { ...@@ -3499,24 +3543,25 @@ public final class Files {
* @see #walk(Path, int, FileVisitOption...) * @see #walk(Path, int, FileVisitOption...)
* @since 1.8 * @since 1.8
*/ */
public static CloseableStream<Path> find(Path start, public static Stream<Path> find(Path start,
int maxDepth, int maxDepth,
BiPredicate<Path, BasicFileAttributes> matcher, BiPredicate<Path, BasicFileAttributes> matcher,
FileVisitOption... options) FileVisitOption... options)
throws IOException throws IOException {
{
FileTreeIterator iterator = new FileTreeIterator(start, maxDepth, options); FileTreeIterator iterator = new FileTreeIterator(start, maxDepth, options);
try {
Stream<Path> s = StreamSupport.stream( return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.DISTINCT), false)
Spliterators.spliteratorUnknownSize(iterator, Spliterator.DISTINCT), .onClose(iterator::close)
false). .filter(entry -> matcher.test(entry.file(), entry.attributes()))
filter(entry -> matcher.test(entry.file(), entry.attributes())). .map(entry -> entry.file());
map(entry -> entry.file()); } catch (Error|RuntimeException e) {
return new DelegatingCloseableStream<>(iterator, s); iterator.close();
throw e;
}
} }
/** /**
* Read all lines from a file as a {@code CloseableStream}. Unlike {@link * Read all lines from a file as a {@code Stream}. Unlike {@link
* #readAllLines(Path, Charset) readAllLines}, this method does not read * #readAllLines(Path, Charset) readAllLines}, this method does not read
* all lines into a {@code List}, but instead populates lazily as the stream * all lines into a {@code List}, but instead populates lazily as the stream
* is consumed. * is consumed.
...@@ -3528,22 +3573,24 @@ public final class Files { ...@@ -3528,22 +3573,24 @@ public final class Files {
* <p> After this method returns, then any subsequent I/O exception that * <p> After this method returns, then any subsequent I/O exception that
* occurs while reading from the file or when a malformed or unmappable byte * occurs while reading from the file or when a malformed or unmappable byte
* sequence is read, is wrapped in an {@link UncheckedIOException} that will * sequence is read, is wrapped in an {@link UncheckedIOException} that will
* be thrown form the * be thrown from the
* {@link java.util.stream.Stream} method that caused the read to take * {@link java.util.stream.Stream} method that caused the read to take
* place. In case an {@code IOException} is thrown when closing the file, * place. In case an {@code IOException} is thrown when closing the file,
* it is also wrapped as an {@code UncheckedIOException}. * it is also wrapped as an {@code UncheckedIOException}.
* *
* <p> When not using the try-with-resources construct, then stream's * <p> The returned stream encapsulates a {@link Reader}. If timely
* {@link CloseableStream#close close} method should be invoked after * disposal of file system resources is required, the try-with-resources
* operation is completed so as to free any resources held for the open * construct should be used to ensure that the stream's
* file. * {@link Stream#close close} method is invoked after the stream operations
* are completed.
*
* *
* @param path * @param path
* the path to the file * the path to the file
* @param cs * @param cs
* the charset to use for decoding * the charset to use for decoding
* *
* @return the lines from the file as a {@code CloseableStream} * @return the lines from the file as a {@code Stream}
* *
* @throws IOException * @throws IOException
* if an I/O error occurs opening the file * if an I/O error occurs opening the file
...@@ -3557,10 +3604,19 @@ public final class Files { ...@@ -3557,10 +3604,19 @@ public final class Files {
* @see java.io.BufferedReader#lines() * @see java.io.BufferedReader#lines()
* @since 1.8 * @since 1.8
*/ */
public static CloseableStream<String> lines(Path path, Charset cs) public static Stream<String> lines(Path path, Charset cs) throws IOException {
throws IOException
{
BufferedReader br = Files.newBufferedReader(path, cs); BufferedReader br = Files.newBufferedReader(path, cs);
return new DelegatingCloseableStream<>(br, br.lines()); try {
return br.lines().onClose(asUncheckedRunnable(br));
} catch (Error|RuntimeException e) {
try {
br.close();
} catch (IOException ex) {
try {
e.addSuppressed(ex);
} catch (Throwable ignore) {}
}
throw e;
}
} }
} }
...@@ -303,7 +303,7 @@ public class AtomicLongArray implements java.io.Serializable { ...@@ -303,7 +303,7 @@ public class AtomicLongArray implements java.io.Serializable {
* @return the previous value * @return the previous value
* @since 1.8 * @since 1.8
*/ */
public final long getAndAccumulate(int i, int x, public final long getAndAccumulate(int i, long x,
LongBinaryOperator accumulatorFunction) { LongBinaryOperator accumulatorFunction) {
long offset = checkedByteOffset(i); long offset = checkedByteOffset(i);
long prev, next; long prev, next;
...@@ -329,7 +329,7 @@ public class AtomicLongArray implements java.io.Serializable { ...@@ -329,7 +329,7 @@ public class AtomicLongArray implements java.io.Serializable {
* @return the updated value * @return the updated value
* @since 1.8 * @since 1.8
*/ */
public final long accumulateAndGet(int i, int x, public final long accumulateAndGet(int i, long x,
LongBinaryOperator accumulatorFunction) { LongBinaryOperator accumulatorFunction) {
long offset = checkedByteOffset(i); long offset = checkedByteOffset(i);
long prev, next; long prev, next;
......
...@@ -26,9 +26,6 @@ ...@@ -26,9 +26,6 @@
package java.util.logging; package java.util.logging;
import java.io.*;
import java.net.*;
/** /**
* This <tt>Handler</tt> publishes log records to <tt>System.err</tt>. * This <tt>Handler</tt> publishes log records to <tt>System.err</tt>.
* By default the <tt>SimpleFormatter</tt> is used to generate brief summaries. * By default the <tt>SimpleFormatter</tt> is used to generate brief summaries.
...@@ -114,6 +111,7 @@ public class ConsoleHandler extends StreamHandler { ...@@ -114,6 +111,7 @@ public class ConsoleHandler extends StreamHandler {
* @param record description of the log event. A null record is * @param record description of the log event. A null record is
* silently ignored and is not published * silently ignored and is not published
*/ */
@Override
public void publish(LogRecord record) { public void publish(LogRecord record) {
super.publish(record); super.publish(record);
flush(); flush();
...@@ -124,6 +122,7 @@ public class ConsoleHandler extends StreamHandler { ...@@ -124,6 +122,7 @@ public class ConsoleHandler extends StreamHandler {
* to close the output stream. That is, we do <b>not</b> * to close the output stream. That is, we do <b>not</b>
* close <tt>System.err</tt>. * close <tt>System.err</tt>.
*/ */
@Override
public void close() { public void close() {
flush(); flush();
} }
......
...@@ -149,7 +149,7 @@ public class FileHandler extends StreamHandler { ...@@ -149,7 +149,7 @@ public class FileHandler extends StreamHandler {
private FileChannel lockFileChannel; private FileChannel lockFileChannel;
private File files[]; private File files[];
private static final int MAX_LOCKS = 100; private static final int MAX_LOCKS = 100;
private static java.util.HashMap<String, String> locks = new java.util.HashMap<>(); private static final java.util.HashMap<String, String> locks = new java.util.HashMap<>();
/** /**
* A metered stream is a subclass of OutputStream that * A metered stream is a subclass of OutputStream that
...@@ -157,7 +157,7 @@ public class FileHandler extends StreamHandler { ...@@ -157,7 +157,7 @@ public class FileHandler extends StreamHandler {
* (b) keeps track of how many bytes have been written * (b) keeps track of how many bytes have been written
*/ */
private class MeteredStream extends OutputStream { private class MeteredStream extends OutputStream {
OutputStream out; final OutputStream out;
int written; int written;
MeteredStream(OutputStream out, int written) { MeteredStream(OutputStream out, int written) {
...@@ -165,25 +165,30 @@ public class FileHandler extends StreamHandler { ...@@ -165,25 +165,30 @@ public class FileHandler extends StreamHandler {
this.written = written; this.written = written;
} }
@Override
public void write(int b) throws IOException { public void write(int b) throws IOException {
out.write(b); out.write(b);
written++; written++;
} }
@Override
public void write(byte buff[]) throws IOException { public void write(byte buff[]) throws IOException {
out.write(buff); out.write(buff);
written += buff.length; written += buff.length;
} }
@Override
public void write(byte buff[], int off, int len) throws IOException { public void write(byte buff[], int off, int len) throws IOException {
out.write(buff,off,len); out.write(buff,off,len);
written += len; written += len;
} }
@Override
public void flush() throws IOException { public void flush() throws IOException {
out.flush(); out.flush();
} }
@Override
public void close() throws IOException { public void close() throws IOException {
out.close(); out.close();
} }
...@@ -607,6 +612,7 @@ public class FileHandler extends StreamHandler { ...@@ -607,6 +612,7 @@ public class FileHandler extends StreamHandler {
* @param record description of the log event. A null record is * @param record description of the log event. A null record is
* silently ignored and is not published * silently ignored and is not published
*/ */
@Override
public synchronized void publish(LogRecord record) { public synchronized void publish(LogRecord record) {
if (!isLoggable(record)) { if (!isLoggable(record)) {
return; return;
...@@ -620,6 +626,7 @@ public class FileHandler extends StreamHandler { ...@@ -620,6 +626,7 @@ public class FileHandler extends StreamHandler {
// currently being called from untrusted code. // currently being called from untrusted code.
// So it is safe to raise privilege here. // So it is safe to raise privilege here.
AccessController.doPrivileged(new PrivilegedAction<Object>() { AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() { public Object run() {
rotate(); rotate();
return null; return null;
...@@ -634,6 +641,7 @@ public class FileHandler extends StreamHandler { ...@@ -634,6 +641,7 @@ public class FileHandler extends StreamHandler {
* @exception SecurityException if a security manager exists and if * @exception SecurityException if a security manager exists and if
* the caller does not have <tt>LoggingPermission("control")</tt>. * the caller does not have <tt>LoggingPermission("control")</tt>.
*/ */
@Override
public synchronized void close() throws SecurityException { public synchronized void close() throws SecurityException {
super.close(); super.close();
// Unlock any lock file. // Unlock any lock file.
...@@ -656,6 +664,7 @@ public class FileHandler extends StreamHandler { ...@@ -656,6 +664,7 @@ public class FileHandler extends StreamHandler {
private static class InitializationErrorManager extends ErrorManager { private static class InitializationErrorManager extends ErrorManager {
Exception lastException; Exception lastException;
@Override
public void error(String msg, Exception ex, int code) { public void error(String msg, Exception ex, int code) {
lastException = ex; lastException = ex;
} }
......
...@@ -47,12 +47,20 @@ import java.io.UnsupportedEncodingException; ...@@ -47,12 +47,20 @@ import java.io.UnsupportedEncodingException;
public abstract class Handler { public abstract class Handler {
private static final int offValue = Level.OFF.intValue(); private static final int offValue = Level.OFF.intValue();
private LogManager manager = LogManager.getLogManager(); private final LogManager manager = LogManager.getLogManager();
private Filter filter;
private Formatter formatter; // We're using volatile here to avoid synchronizing getters, which
private Level logLevel = Level.ALL; // would prevent other threads from calling isLoggable()
private ErrorManager errorManager = new ErrorManager(); // while publish() is executing.
private String encoding; // On the other hand, setters will be synchronized to exclude concurrent
// execution with more complex methods, such as StreamHandler.publish().
// We wouldn't want 'level' to be changed by another thread in the middle
// of the execution of a 'publish' call.
private volatile Filter filter;
private volatile Formatter formatter;
private volatile Level logLevel = Level.ALL;
private volatile ErrorManager errorManager = new ErrorManager();
private volatile String encoding;
// Package private support for security checking. When sealed // Package private support for security checking. When sealed
// is true, we access check updates to the class. // is true, we access check updates to the class.
...@@ -110,7 +118,7 @@ public abstract class Handler { ...@@ -110,7 +118,7 @@ public abstract class Handler {
* @exception SecurityException if a security manager exists and if * @exception SecurityException if a security manager exists and if
* the caller does not have <tt>LoggingPermission("control")</tt>. * the caller does not have <tt>LoggingPermission("control")</tt>.
*/ */
public void setFormatter(Formatter newFormatter) throws SecurityException { public synchronized void setFormatter(Formatter newFormatter) throws SecurityException {
checkPermission(); checkPermission();
// Check for a null pointer: // Check for a null pointer:
newFormatter.getClass(); newFormatter.getClass();
...@@ -138,7 +146,7 @@ public abstract class Handler { ...@@ -138,7 +146,7 @@ public abstract class Handler {
* @exception UnsupportedEncodingException if the named encoding is * @exception UnsupportedEncodingException if the named encoding is
* not supported. * not supported.
*/ */
public void setEncoding(String encoding) public synchronized void setEncoding(String encoding)
throws SecurityException, java.io.UnsupportedEncodingException { throws SecurityException, java.io.UnsupportedEncodingException {
checkPermission(); checkPermission();
if (encoding != null) { if (encoding != null) {
...@@ -174,7 +182,7 @@ public abstract class Handler { ...@@ -174,7 +182,7 @@ public abstract class Handler {
* @exception SecurityException if a security manager exists and if * @exception SecurityException if a security manager exists and if
* the caller does not have <tt>LoggingPermission("control")</tt>. * the caller does not have <tt>LoggingPermission("control")</tt>.
*/ */
public void setFilter(Filter newFilter) throws SecurityException { public synchronized void setFilter(Filter newFilter) throws SecurityException {
checkPermission(); checkPermission();
filter = newFilter; filter = newFilter;
} }
...@@ -198,7 +206,7 @@ public abstract class Handler { ...@@ -198,7 +206,7 @@ public abstract class Handler {
* @exception SecurityException if a security manager exists and if * @exception SecurityException if a security manager exists and if
* the caller does not have <tt>LoggingPermission("control")</tt>. * the caller does not have <tt>LoggingPermission("control")</tt>.
*/ */
public void setErrorManager(ErrorManager em) { public synchronized void setErrorManager(ErrorManager em) {
checkPermission(); checkPermission();
if (em == null) { if (em == null) {
throw new NullPointerException(); throw new NullPointerException();
...@@ -264,7 +272,7 @@ public abstract class Handler { ...@@ -264,7 +272,7 @@ public abstract class Handler {
* than this level will be discarded. * than this level will be discarded.
* @return the level of messages being logged. * @return the level of messages being logged.
*/ */
public synchronized Level getLevel() { public Level getLevel() {
return logLevel; return logLevel;
} }
...@@ -282,11 +290,11 @@ public abstract class Handler { ...@@ -282,11 +290,11 @@ public abstract class Handler {
* *
*/ */
public boolean isLoggable(LogRecord record) { public boolean isLoggable(LogRecord record) {
int levelValue = getLevel().intValue(); final int levelValue = getLevel().intValue();
if (record.getLevel().intValue() < levelValue || levelValue == offValue) { if (record.getLevel().intValue() < levelValue || levelValue == offValue) {
return false; return false;
} }
Filter filter = getFilter(); final Filter filter = getFilter();
if (filter == null) { if (filter == null) {
return true; return true;
} }
......
...@@ -27,6 +27,7 @@ package java.util.logging; ...@@ -27,6 +27,7 @@ package java.util.logging;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.ResourceBundle; import java.util.ResourceBundle;
...@@ -63,7 +64,7 @@ import java.util.ResourceBundle; ...@@ -63,7 +64,7 @@ import java.util.ResourceBundle;
*/ */
public class Level implements java.io.Serializable { public class Level implements java.io.Serializable {
private static String defaultBundle = "sun.util.logging.resources.logging"; private static final String defaultBundle = "sun.util.logging.resources.logging";
/** /**
* @serial The non-localized name of the level. * @serial The non-localized name of the level.
...@@ -81,7 +82,8 @@ public class Level implements java.io.Serializable { ...@@ -81,7 +82,8 @@ public class Level implements java.io.Serializable {
private final String resourceBundleName; private final String resourceBundleName;
// localized level name // localized level name
private String localizedLevelName; private transient String localizedLevelName;
private transient Locale cachedLocale;
/** /**
* OFF is a special level that can be used to turn off logging. * OFF is a special level that can be used to turn off logging.
...@@ -209,6 +211,7 @@ public class Level implements java.io.Serializable { ...@@ -209,6 +211,7 @@ public class Level implements java.io.Serializable {
this.value = value; this.value = value;
this.resourceBundleName = resourceBundleName; this.resourceBundleName = resourceBundleName;
this.localizedLevelName = resourceBundleName == null ? name : null; this.localizedLevelName = resourceBundleName == null ? name : null;
this.cachedLocale = null;
KnownLevel.add(this); KnownLevel.add(this);
} }
...@@ -250,17 +253,71 @@ public class Level implements java.io.Serializable { ...@@ -250,17 +253,71 @@ public class Level implements java.io.Serializable {
return this.name; return this.name;
} }
final synchronized String getLocalizedLevelName() { private String computeLocalizedLevelName(Locale newLocale) {
ResourceBundle rb = ResourceBundle.getBundle(resourceBundleName, newLocale);
final String localizedName = rb.getString(name);
final boolean isDefaultBundle = defaultBundle.equals(resourceBundleName);
if (!isDefaultBundle) return localizedName;
// This is a trick to determine whether the name has been translated
// or not. If it has not been translated, we need to use Locale.ROOT
// when calling toUpperCase().
final Locale rbLocale = rb.getLocale();
final Locale locale =
Locale.ROOT.equals(rbLocale)
|| name.equals(localizedName.toUpperCase(Locale.ROOT))
? Locale.ROOT : rbLocale;
// ALL CAPS in a resource bundle's message indicates no translation
// needed per Oracle translation guideline. To workaround this
// in Oracle JDK implementation, convert the localized level name
// to uppercase for compatibility reason.
return Locale.ROOT.equals(locale) ? name : localizedName.toUpperCase(locale);
}
// Avoid looking up the localizedLevelName twice if we already
// have it.
final String getCachedLocalizedLevelName() {
if (localizedLevelName != null) { if (localizedLevelName != null) {
return localizedLevelName; if (cachedLocale != null) {
if (cachedLocale.equals(Locale.getDefault())) {
// OK: our cached value was looked up with the same
// locale. We can use it.
return localizedLevelName;
}
}
}
if (resourceBundleName == null) {
// No resource bundle: just use the name.
return name;
}
// We need to compute the localized name.
// Either because it's the first time, or because our cached
// value is for a different locale. Just return null.
return null;
}
final synchronized String getLocalizedLevelName() {
// See if we have a cached localized name
final String cachedLocalizedName = getCachedLocalizedLevelName();
if (cachedLocalizedName != null) {
return cachedLocalizedName;
} }
// No cached localized name or cache invalid.
// Need to compute the localized name.
final Locale newLocale = Locale.getDefault();
try { try {
ResourceBundle rb = ResourceBundle.getBundle(resourceBundleName); localizedLevelName = computeLocalizedLevelName(newLocale);
localizedLevelName = rb.getString(name);
} catch (Exception ex) { } catch (Exception ex) {
localizedLevelName = name; localizedLevelName = name;
} }
cachedLocale = newLocale;
return localizedLevelName; return localizedLevelName;
} }
...@@ -318,6 +375,7 @@ public class Level implements java.io.Serializable { ...@@ -318,6 +375,7 @@ public class Level implements java.io.Serializable {
* *
* @return the non-localized name of the Level, for example "INFO". * @return the non-localized name of the Level, for example "INFO".
*/ */
@Override
public final String toString() { public final String toString() {
return name; return name;
} }
...@@ -420,6 +478,7 @@ public class Level implements java.io.Serializable { ...@@ -420,6 +478,7 @@ public class Level implements java.io.Serializable {
* Compare two objects for value equality. * Compare two objects for value equality.
* @return true if and only if the two objects have the same level value. * @return true if and only if the two objects have the same level value.
*/ */
@Override
public boolean equals(Object ox) { public boolean equals(Object ox) {
try { try {
Level lx = (Level)ox; Level lx = (Level)ox;
...@@ -433,6 +492,7 @@ public class Level implements java.io.Serializable { ...@@ -433,6 +492,7 @@ public class Level implements java.io.Serializable {
* Generate a hashcode. * Generate a hashcode.
* @return a hashcode based on the level value * @return a hashcode based on the level value
*/ */
@Override
public int hashCode() { public int hashCode() {
return this.value; return this.value;
} }
......
...@@ -391,6 +391,9 @@ public class LogManager { ...@@ -391,6 +391,9 @@ public class LogManager {
} }
} }
// LoggerContext maps from AppContext
private static WeakHashMap<Object, LoggerContext> contextsMap = null;
// Returns the LoggerContext for the user code (i.e. application or AppContext). // Returns the LoggerContext for the user code (i.e. application or AppContext).
// Loggers are isolated from each AppContext. // Loggers are isolated from each AppContext.
private LoggerContext getUserContext() { private LoggerContext getUserContext() {
...@@ -399,33 +402,28 @@ public class LogManager { ...@@ -399,33 +402,28 @@ public class LogManager {
SecurityManager sm = System.getSecurityManager(); SecurityManager sm = System.getSecurityManager();
JavaAWTAccess javaAwtAccess = SharedSecrets.getJavaAWTAccess(); JavaAWTAccess javaAwtAccess = SharedSecrets.getJavaAWTAccess();
if (sm != null && javaAwtAccess != null) { if (sm != null && javaAwtAccess != null) {
// for each applet, it has its own LoggerContext isolated from others
synchronized (javaAwtAccess) { synchronized (javaAwtAccess) {
// AppContext.getAppContext() returns the system AppContext if called // find the AppContext of the applet code
// from a system thread but Logger.getLogger might be called from // will be null if we are in the main app context.
// an applet code. Instead, find the AppContext of the applet code final Object ecx = javaAwtAccess.getAppletContext();
// from the execution stack.
Object ecx = javaAwtAccess.getExecutionContext();
if (ecx == null) {
// fall back to thread group seach of AppContext
ecx = javaAwtAccess.getContext();
}
if (ecx != null) { if (ecx != null) {
context = (LoggerContext)javaAwtAccess.get(ecx, LoggerContext.class); if (contextsMap == null) {
contextsMap = new WeakHashMap<>();
}
context = contextsMap.get(ecx);
if (context == null) { if (context == null) {
if (javaAwtAccess.isMainAppContext()) { // Create a new LoggerContext for the applet.
context = userContext; // The new logger context has its requiresDefaultLoggers
} else { // flag set to true - so that these loggers will be
// Create a new LoggerContext for the applet. // lazily added when the context is firt accessed.
// The new logger context has its requiresDefaultLoggers context = new LoggerContext(true);
// flag set to true - so that these loggers will be contextsMap.put(ecx, context);
// lazily added when the context is firt accessed.
context = new LoggerContext(true);
}
javaAwtAccess.put(ecx, LoggerContext.class, context);
} }
} }
} }
} }
// for standalone app, return userContext
return context != null ? context : userContext; return context != null ? context : userContext;
} }
......
...@@ -88,7 +88,7 @@ package java.util.logging; ...@@ -88,7 +88,7 @@ package java.util.logging;
public class MemoryHandler extends Handler { public class MemoryHandler extends Handler {
private final static int DEFAULT_SIZE = 1000; private final static int DEFAULT_SIZE = 1000;
private Level pushLevel; private volatile Level pushLevel;
private int size; private int size;
private Handler target; private Handler target;
private LogRecord buffer[]; private LogRecord buffer[];
...@@ -188,6 +188,7 @@ public class MemoryHandler extends Handler { ...@@ -188,6 +188,7 @@ public class MemoryHandler extends Handler {
* @param record description of the log event. A null record is * @param record description of the log event. A null record is
* silently ignored and is not published * silently ignored and is not published
*/ */
@Override
public synchronized void publish(LogRecord record) { public synchronized void publish(LogRecord record) {
if (!isLoggable(record)) { if (!isLoggable(record)) {
return; return;
...@@ -227,6 +228,7 @@ public class MemoryHandler extends Handler { ...@@ -227,6 +228,7 @@ public class MemoryHandler extends Handler {
* Note that the current contents of the <tt>MemoryHandler</tt> * Note that the current contents of the <tt>MemoryHandler</tt>
* buffer are <b>not</b> written out. That requires a "push". * buffer are <b>not</b> written out. That requires a "push".
*/ */
@Override
public void flush() { public void flush() {
target.flush(); target.flush();
} }
...@@ -238,6 +240,7 @@ public class MemoryHandler extends Handler { ...@@ -238,6 +240,7 @@ public class MemoryHandler extends Handler {
* @exception SecurityException if a security manager exists and if * @exception SecurityException if a security manager exists and if
* the caller does not have <tt>LoggingPermission("control")</tt>. * the caller does not have <tt>LoggingPermission("control")</tt>.
*/ */
@Override
public void close() throws SecurityException { public void close() throws SecurityException {
target.close(); target.close();
setLevel(Level.OFF); setLevel(Level.OFF);
...@@ -252,11 +255,10 @@ public class MemoryHandler extends Handler { ...@@ -252,11 +255,10 @@ public class MemoryHandler extends Handler {
* @exception SecurityException if a security manager exists and if * @exception SecurityException if a security manager exists and if
* the caller does not have <tt>LoggingPermission("control")</tt>. * the caller does not have <tt>LoggingPermission("control")</tt>.
*/ */
public void setPushLevel(Level newLevel) throws SecurityException { public synchronized void setPushLevel(Level newLevel) throws SecurityException {
if (newLevel == null) { if (newLevel == null) {
throw new NullPointerException(); throw new NullPointerException();
} }
LogManager manager = LogManager.getLogManager();
checkPermission(); checkPermission();
pushLevel = newLevel; pushLevel = newLevel;
} }
...@@ -266,7 +268,7 @@ public class MemoryHandler extends Handler { ...@@ -266,7 +268,7 @@ public class MemoryHandler extends Handler {
* *
* @return the value of the <tt>pushLevel</tt> * @return the value of the <tt>pushLevel</tt>
*/ */
public synchronized Level getPushLevel() { public Level getPushLevel() {
return pushLevel; return pushLevel;
} }
...@@ -283,6 +285,7 @@ public class MemoryHandler extends Handler { ...@@ -283,6 +285,7 @@ public class MemoryHandler extends Handler {
* @return true if the <tt>LogRecord</tt> would be logged. * @return true if the <tt>LogRecord</tt> would be logged.
* *
*/ */
@Override
public boolean isLoggable(LogRecord record) { public boolean isLoggable(LogRecord record) {
return super.isLoggable(record); return super.isLoggable(record);
} }
......
...@@ -82,7 +82,6 @@ public class SocketHandler extends StreamHandler { ...@@ -82,7 +82,6 @@ public class SocketHandler extends StreamHandler {
private Socket sock; private Socket sock;
private String host; private String host;
private int port; private int port;
private String portProperty;
// Private method to configure a SocketHandler from LogManager // Private method to configure a SocketHandler from LogManager
// properties and/or default values as specified in the class // properties and/or default values as specified in the class
...@@ -177,6 +176,7 @@ public class SocketHandler extends StreamHandler { ...@@ -177,6 +176,7 @@ public class SocketHandler extends StreamHandler {
* @exception SecurityException if a security manager exists and if * @exception SecurityException if a security manager exists and if
* the caller does not have <tt>LoggingPermission("control")</tt>. * the caller does not have <tt>LoggingPermission("control")</tt>.
*/ */
@Override
public synchronized void close() throws SecurityException { public synchronized void close() throws SecurityException {
super.close(); super.close();
if (sock != null) { if (sock != null) {
...@@ -195,6 +195,7 @@ public class SocketHandler extends StreamHandler { ...@@ -195,6 +195,7 @@ public class SocketHandler extends StreamHandler {
* @param record description of the log event. A null record is * @param record description of the log event. A null record is
* silently ignored and is not published * silently ignored and is not published
*/ */
@Override
public synchronized void publish(LogRecord record) { public synchronized void publish(LogRecord record) {
if (!isLoggable(record)) { if (!isLoggable(record)) {
return; return;
......
...@@ -73,10 +73,9 @@ import java.io.*; ...@@ -73,10 +73,9 @@ import java.io.*;
*/ */
public class StreamHandler extends Handler { public class StreamHandler extends Handler {
private LogManager manager = LogManager.getLogManager();
private OutputStream output; private OutputStream output;
private boolean doneHeader; private boolean doneHeader;
private Writer writer; private volatile Writer writer;
// Private method to configure a StreamHandler from LogManager // Private method to configure a StreamHandler from LogManager
// properties and/or default values as specified in the class // properties and/or default values as specified in the class
...@@ -169,7 +168,8 @@ public class StreamHandler extends Handler { ...@@ -169,7 +168,8 @@ public class StreamHandler extends Handler {
* @exception UnsupportedEncodingException if the named encoding is * @exception UnsupportedEncodingException if the named encoding is
* not supported. * not supported.
*/ */
public void setEncoding(String encoding) @Override
public synchronized void setEncoding(String encoding)
throws SecurityException, java.io.UnsupportedEncodingException { throws SecurityException, java.io.UnsupportedEncodingException {
super.setEncoding(encoding); super.setEncoding(encoding);
if (output == null) { if (output == null) {
...@@ -201,6 +201,7 @@ public class StreamHandler extends Handler { ...@@ -201,6 +201,7 @@ public class StreamHandler extends Handler {
* @param record description of the log event. A null record is * @param record description of the log event. A null record is
* silently ignored and is not published * silently ignored and is not published
*/ */
@Override
public synchronized void publish(LogRecord record) { public synchronized void publish(LogRecord record) {
if (!isLoggable(record)) { if (!isLoggable(record)) {
return; return;
...@@ -240,6 +241,7 @@ public class StreamHandler extends Handler { ...@@ -240,6 +241,7 @@ public class StreamHandler extends Handler {
* @return true if the <tt>LogRecord</tt> would be logged. * @return true if the <tt>LogRecord</tt> would be logged.
* *
*/ */
@Override
public boolean isLoggable(LogRecord record) { public boolean isLoggable(LogRecord record) {
if (writer == null || record == null) { if (writer == null || record == null) {
return false; return false;
...@@ -250,6 +252,7 @@ public class StreamHandler extends Handler { ...@@ -250,6 +252,7 @@ public class StreamHandler extends Handler {
/** /**
* Flush any buffered messages. * Flush any buffered messages.
*/ */
@Override
public synchronized void flush() { public synchronized void flush() {
if (writer != null) { if (writer != null) {
try { try {
...@@ -294,6 +297,7 @@ public class StreamHandler extends Handler { ...@@ -294,6 +297,7 @@ public class StreamHandler extends Handler {
* @exception SecurityException if a security manager exists and if * @exception SecurityException if a security manager exists and if
* the caller does not have LoggingPermission("control"). * the caller does not have LoggingPermission("control").
*/ */
@Override
public synchronized void close() throws SecurityException { public synchronized void close() throws SecurityException {
flushAndClose(); flushAndClose();
} }
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册