提交 d81d6a4a 编写于 作者: M mullan

Merge

......@@ -38,6 +38,7 @@ import java.util.*;
import sun.awt.*;
import sun.lwawt.macosx.*;
import sun.print.*;
import sun.security.util.SecurityConstants;
public abstract class LWToolkit extends SunToolkit implements Runnable {
......@@ -502,7 +503,7 @@ public abstract class LWToolkit extends SunToolkit implements Runnable {
public Clipboard getSystemClipboard() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkSystemClipboardAccess();
security.checkPermission(SecurityConstants.AWT.ACCESS_CLIPBOARD_PERMISSION);
}
synchronized (this) {
......
......@@ -87,6 +87,7 @@ class KQueueArrayWrapper {
private int incomingInterruptFD;
static {
IOUtil.load();
initStructSizes();
String datamodel = java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction("sun.arch.data.model")
......
......@@ -246,9 +246,4 @@ class KQueueSelectorImpl
}
return this;
}
static {
Util.load();
}
}
......@@ -28,6 +28,12 @@
#include "util.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
* allow concurrent translation - due to caching method.
......
......@@ -35,6 +35,7 @@ import java.text.BreakIterator;
import javax.swing.text.AttributeSet;
import javax.accessibility.*;
import java.awt.im.InputMethodRequests;
import sun.security.util.SecurityConstants;
/**
* The <code>TextComponent</code> class is the superclass of
......@@ -728,7 +729,7 @@ public class TextComponent extends Component implements Accessible {
SecurityManager sm = System.getSecurityManager();
if (sm == null) return true;
try {
sm.checkSystemClipboardAccess();
sm.checkPermission(SecurityConstants.AWT.ACCESS_CLIPBOARD_PERMISSION);
return true;
} catch (SecurityException e) {}
return false;
......
......@@ -1270,12 +1270,8 @@ public abstract class Toolkit {
* <p>
* Each actual implementation of this method should first check if there
* is a security manager installed. If there is, the method should call
* the security manager's <code>checkSystemClipboardAccess</code> method
* to ensure it's ok to to access the system clipboard. If the default
* 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.
* the security manager's {@link SecurityManager#checkPermission
* checkPermission} method to check {@code AWTPermission("accessClipboard")}.
*
* @return the system Clipboard
* @exception HeadlessException if GraphicsEnvironment.isHeadless()
......@@ -1318,14 +1314,9 @@ public abstract class Toolkit {
* system selection <code>Clipboard</code> as described above.
* <p>
* Each actual implementation of this method should first check if there
* is a <code>SecurityManager</code> installed. If there is, the method
* should call the <code>SecurityManager</code>'s
* <code>checkSystemClipboardAccess</code> method to ensure that client
* 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.
* is a security manager installed. If there is, the method should call
* the security manager's {@link SecurityManager#checkPermission
* checkPermission} method to check {@code AWTPermission("accessClipboard")}.
*
* @return the system selection as a <code>Clipboard</code>, or
* <code>null</code> if the native platform does not support a
......@@ -1699,25 +1690,20 @@ public abstract class Toolkit {
* therefore not assume that the EventQueue instance returned
* by this method will be shared by other applets or the system.
*
* <p>First, if there is a security manager, its
* <code>checkAwtEventQueueAccess</code>
* method is called.
* 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.
* <p> If there is a security manager then its
* {@link SecurityManager#checkPermission checkPermission} method
* is called to check {@code AWTPermission("accessEventQueue")}.
*
* @return the <code>EventQueue</code> object
* @throws SecurityException
* if a security manager exists and its <code>{@link
* java.lang.SecurityManager#checkAwtEventQueueAccess}</code>
* method denies access to the <code>EventQueue</code>
* if a security manager is set and it denies access to
* the {@code EventQueue}
* @see java.awt.AWTPermission
*/
public final EventQueue getSystemEventQueue() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkAwtEventQueueAccess();
security.checkPermission(SecurityConstants.AWT.CHECK_AWT_EVENTQUEUE_PERMISSION);
}
return getSystemEventQueueImpl();
}
......
......@@ -195,10 +195,9 @@ public class Window extends Container implements Accessible {
/**
* This represents the warning message that is
* to be displayed in a non secure window. ie :
* a window that has a security manager installed for
* which calling SecurityManager.checkTopLevelWindow()
* is false. This message can be displayed anywhere in
* the window.
* a window that has a security manager installed that denies
* {@code AWTPermission("showWindowWithoutWarningBanner")}.
* This message can be displayed anywhere in the window.
*
* @serial
* @see #getWarningString
......@@ -417,11 +416,10 @@ public class Window extends Container implements Accessible {
* Constructs a new, initially invisible window in default size with the
* specified {@code GraphicsConfiguration}.
* <p>
* If there is a security manager, this method first calls
* the security manager's {@code checkTopLevelWindow}
* method with {@code this}
* as its argument to determine whether or not the window
* must be displayed with a warning banner.
* If there is a security manager, then it is invoked to check
* {@code AWTPermission("showWindowWithoutWarningBanner")}
* to determine whether or not the window must be displayed with
* a warning banner.
*
* @param gc the {@code GraphicsConfiguration} of the target screen
* device. If {@code gc} is {@code null}, the system default
......@@ -432,7 +430,6 @@ public class Window extends Container implements Accessible {
* {@code GraphicsEnvironment.isHeadless()} returns {@code true}
*
* @see java.awt.GraphicsEnvironment#isHeadless
* @see java.lang.SecurityManager#checkTopLevelWindow
*/
Window(GraphicsConfiguration gc) {
init(gc);
......@@ -511,25 +508,16 @@ public class Window extends Container implements Accessible {
/**
* Constructs a new, initially invisible window in the default size.
*
* <p>First, if there is a security manager, its
* {@code checkTopLevelWindow}
* method is called with {@code this}
* as its argument
* 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.
* <p>
* If there is a security manager set, it is invoked to check
* {@code AWTPermission("showWindowWithoutWarningBanner")}.
* If that check fails with a {@code SecurityException} then a warning
* banner is created.
*
* @exception HeadlessException when
* {@code GraphicsEnvironment.isHeadless()} returns {@code true}
*
* @see java.awt.GraphicsEnvironment#isHeadless
* @see java.lang.SecurityManager#checkTopLevelWindow
*/
Window() throws HeadlessException {
GraphicsEnvironment.checkHeadless();
......@@ -541,11 +529,10 @@ public class Window extends Container implements Accessible {
* {@code Frame} as its owner. The window will not be focusable
* unless its owner is showing on the screen.
* <p>
* If there is a security manager, this method first calls
* the security manager's {@code checkTopLevelWindow}
* method with {@code this}
* as its argument to determine whether or not the window
* must be displayed with a warning banner.
* If there is a security manager set, it is invoked to check
* {@code AWTPermission("showWindowWithoutWarningBanner")}.
* If that check fails with a {@code SecurityException} then a warning
* banner is created.
*
* @param owner the {@code Frame} to act as owner or {@code null}
* if this window has no owner
......@@ -555,7 +542,6 @@ public class Window extends Container implements Accessible {
* {@code GraphicsEnvironment.isHeadless} returns {@code true}
*
* @see java.awt.GraphicsEnvironment#isHeadless
* @see java.lang.SecurityManager#checkTopLevelWindow
* @see #isShowing
*/
public Window(Frame owner) {
......@@ -570,11 +556,10 @@ public class Window extends Container implements Accessible {
* unless its nearest owning {@code Frame} or {@code Dialog}
* is showing on the screen.
* <p>
* If there is a security manager, this method first calls
* the security manager's {@code checkTopLevelWindow}
* method with {@code this}
* as its argument to determine whether or not the window
* must be displayed with a warning banner.
* If there is a security manager set, it is invoked to check
* {@code AWTPermission("showWindowWithoutWarningBanner")}.
* If that check fails with a {@code SecurityException} then a
* warning banner is created.
*
* @param owner the {@code Window} to act as owner or
* {@code null} if this window has no owner
......@@ -585,7 +570,6 @@ public class Window extends Container implements Accessible {
* {@code true}
*
* @see java.awt.GraphicsEnvironment#isHeadless
* @see java.lang.SecurityManager#checkTopLevelWindow
* @see #isShowing
*
* @since 1.2
......@@ -603,11 +587,10 @@ public class Window extends Container implements Accessible {
* its nearest owning {@code Frame} or {@code Dialog}
* is showing on the screen.
* <p>
* If there is a security manager, this method first calls
* the security manager's {@code checkTopLevelWindow}
* method with {@code this}
* as its argument to determine whether or not the window
* must be displayed with a warning banner.
* If there is a security manager set, it is invoked to check
* {@code AWTPermission("showWindowWithoutWarningBanner")}. If that
* check fails with a {@code SecurityException} then a warning banner
* is created.
*
* @param owner the window to act as owner or {@code null}
* if this window has no owner
......@@ -621,7 +604,6 @@ public class Window extends Container implements Accessible {
* {@code true}
*
* @see java.awt.GraphicsEnvironment#isHeadless
* @see java.lang.SecurityManager#checkTopLevelWindow
* @see GraphicsConfiguration#getBounds
* @see #isShowing
* @since 1.3
......@@ -1362,10 +1344,9 @@ public class Window extends Container implements Accessible {
* Gets the warning string that is displayed with this window.
* If this window is insecure, the warning string is displayed
* somewhere in the visible area of the window. A window is
* insecure if there is a security manager, and the security
* manager's {@code checkTopLevelWindow} method returns
* {@code false} when this window is passed to it as an
* argument.
* insecure if there is a security manager and the security
* manager denies
* {@code AWTPermission("showWindowWithoutWarningBanner")}.
* <p>
* If the window is secure, then {@code getWarningString}
* returns {@code null}. If the window is insecure, this
......@@ -1373,7 +1354,6 @@ public class Window extends Container implements Accessible {
* {@code awt.appletWarning}
* and returns the string value of that property.
* @return the warning string for this window.
* @see java.lang.SecurityManager#checkTopLevelWindow(java.lang.Object)
*/
public final String getWarningString() {
return warningString;
......@@ -1383,10 +1363,12 @@ public class Window extends Container implements Accessible {
warningString = null;
SecurityManager sm = System.getSecurityManager();
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
// for getting the property! We don't want the
// above checkTopLevelWindow call to always succeed!
// above checkPermission call to always succeed!
warningString = AccessController.doPrivileged(
new GetPropertyAction("awt.appletWarning",
"Java Applet Window"));
......
......@@ -33,6 +33,7 @@ import java.util.Arrays;
import sun.awt.AWTAccessor;
import sun.util.logging.PlatformLogger;
import sun.security.util.SecurityConstants;
/**
* The root event class for all component-level input events.
......@@ -350,7 +351,7 @@ public abstract class InputEvent extends ComponentEvent {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
try {
sm.checkSystemClipboardAccess();
sm.checkPermission(SecurityConstants.AWT.ACCESS_CLIPBOARD_PERMISSION);
b = true;
} catch (SecurityException se) {
if (logger.isLoggable(PlatformLogger.Level.FINE)) {
......
......@@ -124,9 +124,11 @@ public final class Console implements Flushable
* {@link java.io.Reader#read(java.nio.CharBuffer) read(java.nio.CharBuffer)}
* on the returned object will not read in characters beyond the line
* 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
* (<tt>'\n'</tt>), a carriage return (<tt>'\r'</tt>), a carriage return
* followed immediately by a linefeed, or an end of stream.
* more characters. The {@code Reader}'s {@code read} methods may block if a
* line bound has not been entered or reached on the console's input device.
* 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
*/
......
......@@ -26,7 +26,24 @@
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
* @since 1.7
......
......@@ -1484,22 +1484,24 @@ public final class Class<T> implements java.io.Serializable,
/**
* Returns an array containing {@code Field} objects reflecting all
* the accessible public fields of the class or interface represented by
* this {@code Class} object. 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 has no accessible public
* fields, or if it represents an array class, a primitive type, or void.
* this {@code Class} object.
*
* <p> Specifically, if this {@code Class} object represents a class,
* this method returns the public fields of this class and of all its
* superclasses. If this {@code Class} object represents an
* interface, this method returns the fields of this interface and of all
* its superinterfaces.
* <p> If this {@code Class} object represents a class or interface with no
* no accessible public fields, then this method returns an array of length
* 0.
*
* <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
* method. User code should use the methods of class {@code Array} to
* manipulate arrays.
* <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> 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
* public fields
......@@ -1512,6 +1514,8 @@ public final class Class<T> implements java.io.Serializable,
* of this class.
*
* @since JDK1.1
* @jls 8.2 Class Members
* @jls 8.3 Field Declarations
*/
@CallerSensitive
public Field[] getFields() throws SecurityException {
......@@ -1595,13 +1599,14 @@ public final class Class<T> implements java.io.Serializable,
/**
* Returns a {@code Field} object that reflects the specified public
* member field of the class or interface represented by this
* {@code Class} object. The {@code name} parameter is a
* {@code String} specifying the simple name of the desired field.
* Returns a {@code Field} object that reflects the specified public member
* field of the class or interface represented by this {@code Class}
* object. The {@code name} parameter is a {@code String} specifying the
* simple name of the desired field.
*
* <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>
* <LI> If C declares a public field with the name specified, that is the
* field to be reflected.</LI>
......@@ -1614,7 +1619,8 @@ public final class Class<T> implements java.io.Serializable,
* is thrown.</LI>
* </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
* @return the {@code Field} object of this class specified by
......@@ -1631,6 +1637,8 @@ public final class Class<T> implements java.io.Serializable,
* of this class.
*
* @since JDK1.1
* @jls 8.2 Class Members
* @jls 8.3 Field Declarations
*/
@CallerSensitive
public Field getField(String name)
......@@ -1800,12 +1808,15 @@ public final class Class<T> implements java.io.Serializable,
* declared by the class or interface represented by this
* {@code Class} object. This includes public, protected, default
* (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
* declared fields of this class
......@@ -1831,6 +1842,8 @@ public final class Class<T> implements java.io.Serializable,
* </ul>
*
* @since JDK1.1
* @jls 8.2 Class Members
* @jls 8.3 Field Declarations
*/
@CallerSensitive
public Field[] getDeclaredFields() throws SecurityException {
......@@ -1935,9 +1948,11 @@ public final class Class<T> implements java.io.Serializable,
/**
* Returns a {@code Field} object that reflects the specified declared
* field of the class or interface represented by this {@code Class}
* object. The {@code name} parameter is a {@code String} that
* specifies the simple name of the desired field. Note that this method
* will not reflect the {@code length} field of an array class.
* object. The {@code name} parameter is a {@code String} that specifies
* the simple name of the desired field.
*
* <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
* @return the {@code Field} object for the specified field in this
......@@ -1967,6 +1982,8 @@ public final class Class<T> implements java.io.Serializable,
* </ul>
*
* @since JDK1.1
* @jls 8.2 Class Members
* @jls 8.3 Field Declarations
*/
@CallerSensitive
public Field getDeclaredField(String name)
......
......@@ -1336,9 +1336,16 @@ class SecurityManager {
* top-level windows; <code>false</code> otherwise.
* @exception NullPointerException if the <code>window</code> argument is
* <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 #checkPermission(java.security.Permission) checkPermission
*/
@Deprecated
public boolean checkTopLevelWindow(Object window) {
if (window == null) {
throw new NullPointerException("window can't be null");
......@@ -1398,8 +1405,15 @@ class SecurityManager {
* @since JDK1.1
* @exception SecurityException if the calling thread does not have
* 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
*/
@Deprecated
public void checkSystemClipboardAccess() {
Permission perm = SecurityConstants.AWT.ACCESS_CLIPBOARD_PERMISSION;
if (perm == null) {
......@@ -1427,8 +1441,15 @@ class SecurityManager {
* @since JDK1.1
* @exception SecurityException if the calling thread does not have
* 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
*/
@Deprecated
public void checkAwtEventQueueAccess() {
Permission perm = SecurityConstants.AWT.CHECK_AWT_EVENTQUEUE_PERMISSION;
if (perm == null) {
......
......@@ -2457,8 +2457,8 @@ public final class String
* String message = String.join(" ", strings);
* //message returned is: "Java is cool"
*
* Set<String> strings = new HashSet<>();
* Strings.add("Java"); strings.add("is");
* Set<String> strings = new LinkedHashSet<>();
* strings.add("Java"); strings.add("is");
* strings.add("very"); strings.add("cool");
* String message = String.join("-", strings);
* //message returned is: "Java-is-very-cool"
......@@ -2652,7 +2652,7 @@ public final class String
* returns {@code "t\u005Cu0131tle"}, where '\u005Cu0131' is the
* LATIN SMALL LETTER DOTLESS I character.
* To obtain correct results for locale insensitive strings, use
* {@code toLowerCase(Locale.ENGLISH)}.
* {@code toLowerCase(Locale.ROOT)}.
* <p>
* @return the {@code String}, converted to lowercase.
* @see java.lang.String#toLowerCase(Locale)
......@@ -2815,7 +2815,7 @@ public final class String
* returns {@code "T\u005Cu0130TLE"}, where '\u005Cu0130' is the
* LATIN CAPITAL LETTER I WITH DOT ABOVE character.
* To obtain correct results for locale insensitive strings, use
* {@code toUpperCase(Locale.ENGLISH)}.
* {@code toUpperCase(Locale.ROOT)}.
* <p>
* @return the {@code String}, converted to uppercase.
* @see java.lang.String#toUpperCase(Locale)
......
......@@ -124,7 +124,7 @@ import static sun.invoke.util.Wrapper.isWrapperType;
this.samMethodType = samMethodType;
this.implMethod = implMethod;
this.implInfo = new MethodHandleInfo(implMethod);
this.implInfo = caller.revealDirect(implMethod);
// @@@ Temporary work-around pending resolution of 8005119
this.implKind = (implInfo.getReferenceKind() == MethodHandleInfo.REF_invokeSpecial)
? 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 {
return false; // inner class of some sort
if (cls.getClassLoader() != MethodHandle.class.getClassLoader())
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))
return true; // in java.lang.invoke package
if (member.isPublic() && isStaticallyNameable(cls))
......
......@@ -87,6 +87,7 @@ class Invokers {
lform = invokeForm(mtype, true, MethodTypeForm.LF_EX_INVOKER);
invoker = SimpleMethodHandle.make(invokerType, lform);
}
invoker = invoker.withInternalMemberName(MemberName.makeMethodHandleInvoke("invokeExact", mtype));
assert(checkInvoker(invoker));
exactInvoker = invoker;
return invoker;
......@@ -110,6 +111,7 @@ class Invokers {
lform = invokeForm(mtype, true, MethodTypeForm.LF_GEN_INVOKER);
invoker = SimpleMethodHandle.make(invokerType, lform);
}
invoker = invoker.withInternalMemberName(MemberName.makeMethodHandleInvoke("invoke", mtype));
assert(checkInvoker(invoker));
generalInvoker = invoker;
return invoker;
......
......@@ -320,14 +320,18 @@ import java.util.Objects;
/** Utility method to query if this member is a method handle invocation (invoke or invokeExact). */
public boolean isMethodHandleInvoke() {
final int bits = Modifier.NATIVE | Modifier.FINAL;
final int bits = MH_INVOKE_MODS;
final int negs = Modifier.STATIC;
if (testFlags(bits | negs, bits) &&
clazz == MethodHandle.class) {
return name.equals("invoke") || name.equals("invokeExact");
return isMethodHandleInvokeName(name);
}
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. */
public boolean isStatic() {
......@@ -482,12 +486,27 @@ import java.util.Objects;
m.getClass(); // NPE check
// fill in vmtarget, vmindex while we have m in hand:
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);
this.name = m.getName();
if (this.type == null)
this.type = new Object[] { m.getReturnType(), m.getParameterTypes() };
if (wantSpecial) {
assert(!isAbstract()) : this;
if (isAbstract())
throw new AbstractMethodError(this.toString());
if (getReferenceKind() == REF_invokeVirtual)
changeReferenceKind(REF_invokeSpecial, REF_invokeVirtual);
else if (getReferenceKind() == REF_invokeInterface)
......@@ -562,6 +581,22 @@ import java.util.Objects;
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
MemberName() { }
......
......@@ -1284,6 +1284,21 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
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*/
boolean isInvokeSpecial() {
return false; // DMH.Special returns true
......@@ -1356,7 +1371,7 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
MethodHandle rebind() {
// Bind 'this' into a new invoker, of the known class BMH.
MethodType type2 = type();
LambdaForm form2 = reinvokerForm(type2.basicType());
LambdaForm form2 = reinvokerForm(this);
// form2 = lambda (bmh, arg*) { thismh = bmh[0]; invokeBasic(thismh, arg*) }
return BoundMethodHandle.bindSingle(type2, form2, this);
}
......@@ -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.
* The target MH must override {@link #reinvokerTarget} to provide the target.
*/
static LambdaForm reinvokerForm(MethodType mtype) {
mtype = mtype.basicType();
static LambdaForm reinvokerForm(MethodHandle target) {
MethodType mtype = target.type().basicType();
LambdaForm reinvoker = mtype.form().cachedLambdaForm(MethodTypeForm.LF_REINVOKE);
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 ARG_BASE = 1;
final int ARG_LIMIT = ARG_BASE + mtype.parameterCount();
int nameCursor = ARG_LIMIT;
final int NEXT_MH = nameCursor++;
final int NEXT_MH = customized ? -1 : nameCursor++;
final int REINVOKE = nameCursor++;
LambdaForm.Name[] names = LambdaForm.arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
names[NEXT_MH] = new LambdaForm.Name(NF_reinvokerTarget, names[THIS_BMH]);
Object[] targetArgs = Arrays.copyOfRange(names, THIS_BMH, ARG_LIMIT, Object[].class);
targetArgs[0] = names[NEXT_MH]; // overwrite this MH with next MH
names[REINVOKE] = new LambdaForm.Name(MH_invokeBasic, targetArgs);
return mtype.form().setCachedLambdaForm(MethodTypeForm.LF_REINVOKE, new LambdaForm("BMH.reinvoke", ARG_LIMIT, names));
Object[] targetArgs;
MethodHandle targetMH;
if (customized) {
targetArgs = Arrays.copyOfRange(names, ARG_BASE, ARG_LIMIT, Object[].class);
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;
......
......@@ -317,7 +317,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
private MethodHandle cache;
AsVarargsCollector(MethodHandle target, MethodType type, Class<?> arrayType) {
super(type, reinvokerForm(type));
super(type, reinvokerForm(target));
this.target = target;
this.arrayType = arrayType;
this.cache = target.asCollector(arrayType, 0);
......@@ -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 MethodHandle FAKE_METHOD_HANDLE_INVOKE;
static
MethodHandle fakeMethodHandleInvoke(MemberName method) {
MethodType type = method.getInvocationType();
assert(type.equals(MethodType.methodType(Object.class, Object[].class)));
MethodHandle mh = FAKE_METHOD_HANDLE_INVOKE;
static MethodHandle[] FAKE_METHOD_HANDLE_INVOKE = new MethodHandle[2];
static MethodHandle fakeMethodHandleInvoke(MemberName method) {
int idx;
assert(method.isMethodHandleInvoke());
switch (method.getName()) {
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;
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"));
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;
}
......@@ -821,7 +832,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
MethodHandle vamh = prepareForInvoker(mh);
// Cache the result of makeInjectedInvoker once per argument class.
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) {
......@@ -876,8 +887,11 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
}
// Undo the adapter effect of prepareForInvoker:
private static MethodHandle restoreToType(MethodHandle vamh, MethodType type) {
return vamh.asCollector(Object[].class, type.parameterCount()).asType(type);
private static MethodHandle restoreToType(MethodHandle vamh, MethodType type, MemberName member) {
MethodHandle mh = vamh.asCollector(Object[].class, type.parameterCount());
mh = mh.asType(type);
mh = mh.withInternalMemberName(member);
return mh;
}
private static final MethodHandle MH_checkCallerClass;
......@@ -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 @@
*/
package java.lang.invoke;
import java.lang.reflect.*;
import java.util.*;
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 static final int
REF_getField = Constants.REF_getField,
REF_getStatic = Constants.REF_getStatic,
REF_putField = Constants.REF_putField,
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;
public
interface MethodHandleInfo {
/**
* A direct method handle reference kind,
* as defined in the <a href="MethodHandleInfo.html#refkinds">table above</a>.
*/
public static final int
REF_getField = Constants.REF_getField,
REF_getStatic = Constants.REF_getStatic,
REF_putField = Constants.REF_putField,
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;
private final MethodType methodType;
private final int referenceKind;
/**
* Returns the class in which the cracked method handle's underlying member was defined.
* @return the declaring class of the underlying member
*/
public Class<?> getDeclaringClass();
public MethodHandleInfo(MethodHandle mh) {
MemberName mn = mh.internalMemberName();
if (mn == null) throw new IllegalArgumentException("not a direct method handle");
this.declaringClass = mn.getDeclaringClass();
this.name = mn.getName();
this.methodType = mn.getMethodOrFieldType();
byte refKind = mn.getReferenceKind();
if (refKind == REF_invokeSpecial && !mh.isInvokeSpecial())
// Devirtualized method invocation is usually formally virtual.
refKind = REF_invokeVirtual;
this.referenceKind = refKind;
}
/**
* Returns the name of the cracked method handle's underlying member.
* This is {@code "&lt;init&gt;"} if the underlying member was a constructor,
* else it is a simple method name or field name.
* @return the simple name of the underlying member
*/
public String getName();
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() {
return name;
}
// Utility methods.
// 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) {
case REF_getField: return "getfield";
case REF_getStatic: return "getstatic";
case REF_putField: return "putfield";
case REF_putStatic: return "putstatic";
case REF_invokeVirtual: return "invokevirtual";
case REF_invokeStatic: return "invokestatic";
case REF_invokeSpecial: return "invokespecial";
case REF_newInvokeSpecial: return "newinvokespecial";
case REF_invokeInterface: return "invokeinterface";
default: return "UNKNOWN_REFENCE_KIND" + "[" + referenceKind + "]";
}
/**
* Returns the descriptive name of the given reference kind,
* as defined in the <a href="MethodHandleInfo.html#refkinds">table above</a>.
* The conventional prefix "REF_" is omitted.
* @param referenceKind an integer code for a kind of reference used to access a class member
* @return a mixed-case string such as {@code "getField"}
* @exception IllegalArgumentException if the argument is not a valid
* <a href="MethodHandleInfo.html#refkinds">reference kind number</a>
*/
public static String referenceKindToString(int referenceKind) {
if (!MethodHandleNatives.refKindIsValid(referenceKind))
throw newIllegalArgumentException("invalid reference kind", referenceKind);
return MethodHandleNatives.refKindName((byte)referenceKind);
}
@Override
public String toString() {
return String.format("%s %s.%s:%s", getReferenceKindString(referenceKind),
declaringClass.getName(), name, methodType);
/**
* Returns a string representation for a {@code MethodHandleInfo},
* given the four parts of its symbolic reference.
* 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 {
static boolean refKindIsMethod(byte refKind) {
return !refKindIsField(refKind) && (refKind != REF_newInvokeSpecial);
}
static boolean refKindIsConstructor(byte refKind) {
return (refKind == REF_newInvokeSpecial);
}
static boolean refKindHasReceiver(byte refKind) {
assert(refKindIsValid(refKind));
return (refKind & 1) != 0;
......@@ -313,7 +316,65 @@ class MethodHandleNatives {
* The method assumes the following arguments on the stack:
* 0: the method handle being invoked
* 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,
Class<?> defc, String name, Object type,
......
......@@ -26,8 +26,6 @@
package java.lang.invoke;
import java.lang.reflect.*;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
......@@ -54,6 +52,7 @@ import sun.security.util.SecurityConstants;
* </ul>
* <p>
* @author John Rose, JSR 292 EG
* @since 1.7
*/
public class MethodHandles {
......@@ -96,6 +95,38 @@ public class MethodHandles {
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,
* when the creation requires access checking.
......@@ -647,6 +678,7 @@ public class MethodHandles {
return invoker(type);
if ("invokeExact".equals(name))
return exactInvoker(type);
assert(!MemberName.isMethodHandleInvokeName(name));
return null;
}
......@@ -892,6 +924,10 @@ return mh1;
* @throws NullPointerException if the argument is null
*/
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);
byte refKind = method.getReferenceKind();
if (refKind == REF_invokeSpecial)
......@@ -900,6 +936,12 @@ return mh1;
Lookup lookup = m.isAccessible() ? IMPL_LOOKUP : this;
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.
......@@ -1004,6 +1046,46 @@ return mh1;
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.
MemberName resolveOrFail(byte refKind, Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
......@@ -1201,12 +1283,12 @@ return mh1;
private MethodHandle getDirectMethodCommon(byte refKind, Class<?> refc, MemberName method,
boolean doRestrict, Class<?> callerClass) throws IllegalAccessException {
checkMethod(refKind, refc, method);
if (method.isMethodHandleInvoke())
return fakeMethodHandleInvoke(method);
assert(!method.isMethodHandleInvoke());
Class<?> refcAsSuper;
if (refKind == REF_invokeSpecial &&
refc != lookupClass() &&
!refc.isInterface() &&
refc != (refcAsSuper = lookupClass().getSuperclass()) &&
refc.isAssignableFrom(lookupClass())) {
assert(!method.getName().equals("<init>")); // not this code path
......@@ -1234,9 +1316,6 @@ return mh1;
mh = restrictReceiver(method, mh, lookupClass());
return mh;
}
private MethodHandle fakeMethodHandleInvoke(MemberName method) {
return throwException(method.getReturnType(), UnsupportedOperationException.class);
}
private MethodHandle maybeBindCaller(MemberName method, MethodHandle mh,
Class<?> callerClass)
throws IllegalAccessException {
......
......@@ -225,7 +225,7 @@ public final class SerializedLambda implements Serializable {
@Override
public String toString() {
String implKind=MethodHandleInfo.getReferenceKindString(implMethodKind);
String implKind=MethodHandleInfo.referenceKindToString(implMethodKind);
return String.format("SerializedLambda[%s=%s, %s=%s.%s:%s, " +
"%s=%s %s.%s:%s, %s=%s, %s=%d]",
"capturingClass", capturingClass,
......
......@@ -292,13 +292,17 @@ public final class IDN {
if (useSTD3ASCIIRules) {
for (int i = 0; i < dest.length(); i++) {
int c = dest.charAt(i);
if (!isLDHChar(c)) {
throw new IllegalArgumentException("Contains non-LDH characters");
if (isNonLDHAsciiCodePoint(c)) {
throw new IllegalArgumentException(
"Contains non-LDH ASCII characters");
}
}
if (dest.charAt(0) == '-' || dest.charAt(dest.length() - 1) == '-') {
throw new IllegalArgumentException("Has leading or trailing hyphen");
if (dest.charAt(0) == '-' ||
dest.charAt(dest.length() - 1) == '-') {
throw new IllegalArgumentException(
"Has leading or trailing hyphen");
}
}
......@@ -401,26 +405,20 @@ public final class IDN {
//
// 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
// <->
// 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){
// high runner case
if(ch > 0x007A){
return false;
}
//['-' '0'..'9' 'A'..'Z' 'a'..'z']
if((ch == 0x002D) ||
(0x0030 <= ch && ch <= 0x0039) ||
(0x0041 <= ch && ch <= 0x005A) ||
(0x0061 <= ch && ch <= 0x007A)
){
return true;
}
return false;
// non-LDH = 0..0x2C, 0x2E..0x2F, 0x3A..0x40, 0x5B..0x60, 0x7B..0x7F
//
private static boolean isNonLDHAsciiCodePoint(int ch){
return (0x0000 <= ch && ch <= 0x002C) ||
(0x002E <= ch && ch <= 0x002F) ||
(0x003A <= ch && ch <= 0x0040) ||
(0x005B <= ch && ch <= 0x0060) ||
(0x007B <= ch && ch <= 0x007F);
}
//
// search dots in a string and return the index of that character;
// or if there is no dots, return the length of input string
......
......@@ -25,34 +25,56 @@
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.BufferedWriter;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.IOException;
import java.io.Reader;
import java.io.UncheckedIOException;
import java.util.*;
import java.util.function.BiPredicate;
import java.util.stream.CloseableStream;
import java.util.stream.DelegatingStream;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.io.Writer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.SeekableByteChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
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,
......@@ -74,6 +96,21 @@ public final class Files {
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 --
/**
......@@ -3228,29 +3265,7 @@ public final class Files {
// -- Stream APIs --
/**
* Implementation of CloseableStream
*/
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
* Return a lazily populated {@code Stream}, the elements of
* which are the entries in the directory. The listing is not recursive.
*
* <p> The elements of the stream are {@link Path} objects that are
......@@ -3264,10 +3279,13 @@ public final class Files {
* reflect updates to the directory that occur after returning from this
* method.
*
* <p> When not using the try-with-resources construct, then the stream's
* {@link CloseableStream#close close} method should be invoked after the
* operation is completed so as to free any resources held for the open
* directory. Operating on a closed stream behaves as if the end of stream
* <p> The returned stream encapsulates a {@link DirectoryStream}.
* 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.
*
* <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
* returned after the stream has been closed.
*
......@@ -3278,7 +3296,7 @@ public final class Files {
*
* @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
*
* @throws NotDirectoryException
......@@ -3294,43 +3312,54 @@ public final class Files {
* @see #newDirectoryStream(Path)
* @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);
final Iterator<Path> delegate = ds.iterator();
// Re-wrap DirectoryIteratorException to UncheckedIOException
Iterator<Path> it = new Iterator<Path>() {
public boolean hasNext() {
try {
return delegate.hasNext();
} catch (DirectoryIteratorException e) {
throw new UncheckedIOException(e.getCause());
try {
final Iterator<Path> delegate = ds.iterator();
// Re-wrap DirectoryIteratorException to UncheckedIOException
Iterator<Path> it = new Iterator<Path>() {
@Override
public boolean hasNext() {
try {
return delegate.hasNext();
} catch (DirectoryIteratorException e) {
throw new UncheckedIOException(e.getCause());
}
}
}
public Path next() {
try {
return delegate.next();
} catch (DirectoryIteratorException e) {
throw new UncheckedIOException(e.getCause());
@Override
public Path next() {
try {
return delegate.next();
} catch (DirectoryIteratorException e) {
throw new UncheckedIOException(e.getCause());
}
}
}
};
};
Stream<Path> s = StreamSupport.stream(
Spliterators.spliteratorUnknownSize(it, Spliterator.DISTINCT),
false);
return new DelegatingCloseableStream<>(ds, s);
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(it, Spliterator.DISTINCT), false)
.onClose(asUncheckedRunnable(ds));
} catch (Error|RuntimeException e) {
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
* file tree is traversed <em>depth-first</em>, the elements in the stream
* are {@link Path} objects that are obtained as if by {@link
* Path#resolve(Path) resolving} the relative path against {@code start}.
*
* <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
* attempts to read its {@link BasicFileAttributes}. If the file is a
* directory and can be opened successfully, entries in the directory, and
......@@ -3370,10 +3399,11 @@ public final class Files {
* <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.
*
* <p> When not using the try-with-resources construct, then the stream's
* {@link CloseableStream#close close} method should be invoked after the
* operation is completed so as to free any resources held for the open
* directory. Operate the stream after it is closed will throw an
* <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
......@@ -3388,7 +3418,7 @@ public final class Files {
* @param options
* options to configure the traversal
*
* @return the {@link CloseableStream} of {@link Path}
* @return the {@link Stream} of {@link Path}
*
* @throws IllegalArgumentException
* if the {@code maxDepth} parameter is negative
......@@ -3401,21 +3431,22 @@ public final class Files {
* if an I/O error is thrown when accessing the starting file.
* @since 1.8
*/
public static CloseableStream<Path> walk(Path start, int maxDepth,
FileVisitOption... options)
throws IOException
{
public static Stream<Path> walk(Path start, int maxDepth,
FileVisitOption... options)
throws IOException {
FileTreeIterator iterator = new FileTreeIterator(start, maxDepth, options);
Stream<Path> s = StreamSupport.stream(
Spliterators.spliteratorUnknownSize(iterator, Spliterator.DISTINCT),
false).
map(entry -> entry.file());
return new DelegatingCloseableStream<>(iterator, s);
try {
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.DISTINCT), false)
.onClose(iterator::close)
.map(entry -> entry.file());
} catch (Error|RuntimeException e) {
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
* file tree is traversed <em>depth-first</em>, the elements in the stream
* are {@link Path} objects that are obtained as if by {@link
......@@ -3428,12 +3459,19 @@ public final class Files {
* </pre></blockquote>
* 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
* the starting file
* @param options
* options to configure the traversal
*
* @return the {@link CloseableStream} of {@link Path}
* @return the {@link Stream} of {@link Path}
*
* @throws SecurityException
* If the security manager denies access to the starting file.
......@@ -3446,15 +3484,14 @@ public final class Files {
* @see #walk(Path, int, FileVisitOption...)
* @since 1.8
*/
public static CloseableStream<Path> walk(Path start,
FileVisitOption... options)
throws IOException
{
public static Stream<Path> walk(Path start,
FileVisitOption... options)
throws IOException {
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
* file.
*
......@@ -3463,12 +3500,19 @@ public final class Files {
* {@link BiPredicate} is invoked with its {@link Path} and {@link
* BasicFileAttributes}. The {@code Path} object is obtained as if by
* {@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
* java.util.stream.Stream#filter filter} on the {@code Stream}
* returned by {@code walk} method, this method may be more efficient by
* 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
* after returned from this method, it is wrapped in an {@link
* UncheckedIOException} which will be thrown from the method that caused
......@@ -3484,7 +3528,7 @@ public final class Files {
* @param options
* options to configure the traversal
*
* @return the {@link CloseableStream} of {@link Path}
* @return the {@link Stream} of {@link Path}
*
* @throws IllegalArgumentException
* if the {@code maxDepth} parameter is negative
......@@ -3499,24 +3543,25 @@ public final class Files {
* @see #walk(Path, int, FileVisitOption...)
* @since 1.8
*/
public static CloseableStream<Path> find(Path start,
int maxDepth,
BiPredicate<Path, BasicFileAttributes> matcher,
FileVisitOption... options)
throws IOException
{
public static Stream<Path> find(Path start,
int maxDepth,
BiPredicate<Path, BasicFileAttributes> matcher,
FileVisitOption... options)
throws IOException {
FileTreeIterator iterator = new FileTreeIterator(start, maxDepth, options);
Stream<Path> s = StreamSupport.stream(
Spliterators.spliteratorUnknownSize(iterator, Spliterator.DISTINCT),
false).
filter(entry -> matcher.test(entry.file(), entry.attributes())).
map(entry -> entry.file());
return new DelegatingCloseableStream<>(iterator, s);
try {
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.DISTINCT), false)
.onClose(iterator::close)
.filter(entry -> matcher.test(entry.file(), entry.attributes()))
.map(entry -> entry.file());
} catch (Error|RuntimeException e) {
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
* all lines into a {@code List}, but instead populates lazily as the stream
* is consumed.
......@@ -3528,22 +3573,24 @@ public final class Files {
* <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
* 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
* place. In case an {@code IOException} is thrown when closing the file,
* it is also wrapped as an {@code UncheckedIOException}.
*
* <p> When not using the try-with-resources construct, then stream's
* {@link CloseableStream#close close} method should be invoked after
* operation is completed so as to free any resources held for the open
* file.
* <p> The returned stream encapsulates a {@link Reader}. If timely
* disposal of file system resources is required, the 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.
*
*
* @param path
* the path to the file
* @param cs
* 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
* if an I/O error occurs opening the file
......@@ -3557,10 +3604,19 @@ public final class Files {
* @see java.io.BufferedReader#lines()
* @since 1.8
*/
public static CloseableStream<String> lines(Path path, Charset cs)
throws IOException
{
public static Stream<String> lines(Path path, Charset cs) throws IOException {
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 {
* @return the previous value
* @since 1.8
*/
public final long getAndAccumulate(int i, int x,
public final long getAndAccumulate(int i, long x,
LongBinaryOperator accumulatorFunction) {
long offset = checkedByteOffset(i);
long prev, next;
......@@ -329,7 +329,7 @@ public class AtomicLongArray implements java.io.Serializable {
* @return the updated value
* @since 1.8
*/
public final long accumulateAndGet(int i, int x,
public final long accumulateAndGet(int i, long x,
LongBinaryOperator accumulatorFunction) {
long offset = checkedByteOffset(i);
long prev, next;
......
......@@ -26,9 +26,6 @@
package java.util.logging;
import java.io.*;
import java.net.*;
/**
* This <tt>Handler</tt> publishes log records to <tt>System.err</tt>.
* By default the <tt>SimpleFormatter</tt> is used to generate brief summaries.
......@@ -114,6 +111,7 @@ public class ConsoleHandler extends StreamHandler {
* @param record description of the log event. A null record is
* silently ignored and is not published
*/
@Override
public void publish(LogRecord record) {
super.publish(record);
flush();
......@@ -124,6 +122,7 @@ public class ConsoleHandler extends StreamHandler {
* to close the output stream. That is, we do <b>not</b>
* close <tt>System.err</tt>.
*/
@Override
public void close() {
flush();
}
......
......@@ -149,7 +149,7 @@ public class FileHandler extends StreamHandler {
private FileChannel lockFileChannel;
private File files[];
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
......@@ -157,7 +157,7 @@ public class FileHandler extends StreamHandler {
* (b) keeps track of how many bytes have been written
*/
private class MeteredStream extends OutputStream {
OutputStream out;
final OutputStream out;
int written;
MeteredStream(OutputStream out, int written) {
......@@ -165,25 +165,30 @@ public class FileHandler extends StreamHandler {
this.written = written;
}
@Override
public void write(int b) throws IOException {
out.write(b);
written++;
}
@Override
public void write(byte buff[]) throws IOException {
out.write(buff);
written += buff.length;
}
@Override
public void write(byte buff[], int off, int len) throws IOException {
out.write(buff,off,len);
written += len;
}
@Override
public void flush() throws IOException {
out.flush();
}
@Override
public void close() throws IOException {
out.close();
}
......@@ -607,6 +612,7 @@ public class FileHandler extends StreamHandler {
* @param record description of the log event. A null record is
* silently ignored and is not published
*/
@Override
public synchronized void publish(LogRecord record) {
if (!isLoggable(record)) {
return;
......@@ -620,6 +626,7 @@ public class FileHandler extends StreamHandler {
// currently being called from untrusted code.
// So it is safe to raise privilege here.
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
rotate();
return null;
......@@ -634,6 +641,7 @@ public class FileHandler extends StreamHandler {
* @exception SecurityException if a security manager exists and if
* the caller does not have <tt>LoggingPermission("control")</tt>.
*/
@Override
public synchronized void close() throws SecurityException {
super.close();
// Unlock any lock file.
......@@ -656,6 +664,7 @@ public class FileHandler extends StreamHandler {
private static class InitializationErrorManager extends ErrorManager {
Exception lastException;
@Override
public void error(String msg, Exception ex, int code) {
lastException = ex;
}
......
......@@ -47,12 +47,20 @@ import java.io.UnsupportedEncodingException;
public abstract class Handler {
private static final int offValue = Level.OFF.intValue();
private LogManager manager = LogManager.getLogManager();
private Filter filter;
private Formatter formatter;
private Level logLevel = Level.ALL;
private ErrorManager errorManager = new ErrorManager();
private String encoding;
private final LogManager manager = LogManager.getLogManager();
// We're using volatile here to avoid synchronizing getters, which
// would prevent other threads from calling isLoggable()
// while publish() is executing.
// 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
// is true, we access check updates to the class.
......@@ -110,7 +118,7 @@ public abstract class Handler {
* @exception SecurityException if a security manager exists and if
* 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();
// Check for a null pointer:
newFormatter.getClass();
......@@ -138,7 +146,7 @@ public abstract class Handler {
* @exception UnsupportedEncodingException if the named encoding is
* not supported.
*/
public void setEncoding(String encoding)
public synchronized void setEncoding(String encoding)
throws SecurityException, java.io.UnsupportedEncodingException {
checkPermission();
if (encoding != null) {
......@@ -174,7 +182,7 @@ public abstract class Handler {
* @exception SecurityException if a security manager exists and if
* 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();
filter = newFilter;
}
......@@ -198,7 +206,7 @@ public abstract class Handler {
* @exception SecurityException if a security manager exists and if
* the caller does not have <tt>LoggingPermission("control")</tt>.
*/
public void setErrorManager(ErrorManager em) {
public synchronized void setErrorManager(ErrorManager em) {
checkPermission();
if (em == null) {
throw new NullPointerException();
......@@ -264,7 +272,7 @@ public abstract class Handler {
* than this level will be discarded.
* @return the level of messages being logged.
*/
public synchronized Level getLevel() {
public Level getLevel() {
return logLevel;
}
......@@ -282,11 +290,11 @@ public abstract class Handler {
*
*/
public boolean isLoggable(LogRecord record) {
int levelValue = getLevel().intValue();
final int levelValue = getLevel().intValue();
if (record.getLevel().intValue() < levelValue || levelValue == offValue) {
return false;
}
Filter filter = getFilter();
final Filter filter = getFilter();
if (filter == null) {
return true;
}
......
......@@ -27,6 +27,7 @@ package java.util.logging;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
......@@ -63,7 +64,7 @@ import java.util.ResourceBundle;
*/
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.
......@@ -81,7 +82,8 @@ public class Level implements java.io.Serializable {
private final String resourceBundleName;
// 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.
......@@ -209,6 +211,7 @@ public class Level implements java.io.Serializable {
this.value = value;
this.resourceBundleName = resourceBundleName;
this.localizedLevelName = resourceBundleName == null ? name : null;
this.cachedLocale = null;
KnownLevel.add(this);
}
......@@ -250,17 +253,71 @@ public class Level implements java.io.Serializable {
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) {
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 {
ResourceBundle rb = ResourceBundle.getBundle(resourceBundleName);
localizedLevelName = rb.getString(name);
localizedLevelName = computeLocalizedLevelName(newLocale);
} catch (Exception ex) {
localizedLevelName = name;
}
cachedLocale = newLocale;
return localizedLevelName;
}
......@@ -318,6 +375,7 @@ public class Level implements java.io.Serializable {
*
* @return the non-localized name of the Level, for example "INFO".
*/
@Override
public final String toString() {
return name;
}
......@@ -420,6 +478,7 @@ public class Level implements java.io.Serializable {
* Compare two objects for value equality.
* @return true if and only if the two objects have the same level value.
*/
@Override
public boolean equals(Object ox) {
try {
Level lx = (Level)ox;
......@@ -433,6 +492,7 @@ public class Level implements java.io.Serializable {
* Generate a hashcode.
* @return a hashcode based on the level value
*/
@Override
public int hashCode() {
return this.value;
}
......
......@@ -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).
// Loggers are isolated from each AppContext.
private LoggerContext getUserContext() {
......@@ -399,33 +402,28 @@ public class LogManager {
SecurityManager sm = System.getSecurityManager();
JavaAWTAccess javaAwtAccess = SharedSecrets.getJavaAWTAccess();
if (sm != null && javaAwtAccess != null) {
// for each applet, it has its own LoggerContext isolated from others
synchronized (javaAwtAccess) {
// AppContext.getAppContext() returns the system AppContext if called
// from a system thread but Logger.getLogger might be called from
// an applet code. Instead, find the AppContext of the applet code
// from the execution stack.
Object ecx = javaAwtAccess.getExecutionContext();
if (ecx == null) {
// fall back to thread group seach of AppContext
ecx = javaAwtAccess.getContext();
}
// find the AppContext of the applet code
// will be null if we are in the main app context.
final Object ecx = javaAwtAccess.getAppletContext();
if (ecx != null) {
context = (LoggerContext)javaAwtAccess.get(ecx, LoggerContext.class);
if (contextsMap == null) {
contextsMap = new WeakHashMap<>();
}
context = contextsMap.get(ecx);
if (context == null) {
if (javaAwtAccess.isMainAppContext()) {
context = userContext;
} else {
// Create a new LoggerContext for the applet.
// The new logger context has its requiresDefaultLoggers
// flag set to true - so that these loggers will be
// lazily added when the context is firt accessed.
context = new LoggerContext(true);
}
javaAwtAccess.put(ecx, LoggerContext.class, context);
// Create a new LoggerContext for the applet.
// The new logger context has its requiresDefaultLoggers
// flag set to true - so that these loggers will be
// lazily added when the context is firt accessed.
context = new LoggerContext(true);
contextsMap.put(ecx, context);
}
}
}
}
// for standalone app, return userContext
return context != null ? context : userContext;
}
......
......@@ -88,7 +88,7 @@ package java.util.logging;
public class MemoryHandler extends Handler {
private final static int DEFAULT_SIZE = 1000;
private Level pushLevel;
private volatile Level pushLevel;
private int size;
private Handler target;
private LogRecord buffer[];
......@@ -188,6 +188,7 @@ public class MemoryHandler extends Handler {
* @param record description of the log event. A null record is
* silently ignored and is not published
*/
@Override
public synchronized void publish(LogRecord record) {
if (!isLoggable(record)) {
return;
......@@ -227,6 +228,7 @@ public class MemoryHandler extends Handler {
* Note that the current contents of the <tt>MemoryHandler</tt>
* buffer are <b>not</b> written out. That requires a "push".
*/
@Override
public void flush() {
target.flush();
}
......@@ -238,6 +240,7 @@ public class MemoryHandler extends Handler {
* @exception SecurityException if a security manager exists and if
* the caller does not have <tt>LoggingPermission("control")</tt>.
*/
@Override
public void close() throws SecurityException {
target.close();
setLevel(Level.OFF);
......@@ -252,11 +255,10 @@ public class MemoryHandler extends Handler {
* @exception SecurityException if a security manager exists and if
* 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) {
throw new NullPointerException();
}
LogManager manager = LogManager.getLogManager();
checkPermission();
pushLevel = newLevel;
}
......@@ -266,7 +268,7 @@ public class MemoryHandler extends Handler {
*
* @return the value of the <tt>pushLevel</tt>
*/
public synchronized Level getPushLevel() {
public Level getPushLevel() {
return pushLevel;
}
......@@ -283,6 +285,7 @@ public class MemoryHandler extends Handler {
* @return true if the <tt>LogRecord</tt> would be logged.
*
*/
@Override
public boolean isLoggable(LogRecord record) {
return super.isLoggable(record);
}
......
......@@ -82,7 +82,6 @@ public class SocketHandler extends StreamHandler {
private Socket sock;
private String host;
private int port;
private String portProperty;
// Private method to configure a SocketHandler from LogManager
// properties and/or default values as specified in the class
......@@ -177,6 +176,7 @@ public class SocketHandler extends StreamHandler {
* @exception SecurityException if a security manager exists and if
* the caller does not have <tt>LoggingPermission("control")</tt>.
*/
@Override
public synchronized void close() throws SecurityException {
super.close();
if (sock != null) {
......@@ -195,6 +195,7 @@ public class SocketHandler extends StreamHandler {
* @param record description of the log event. A null record is
* silently ignored and is not published
*/
@Override
public synchronized void publish(LogRecord record) {
if (!isLoggable(record)) {
return;
......
......@@ -73,10 +73,9 @@ import java.io.*;
*/
public class StreamHandler extends Handler {
private LogManager manager = LogManager.getLogManager();
private OutputStream output;
private boolean doneHeader;
private Writer writer;
private volatile Writer writer;
// Private method to configure a StreamHandler from LogManager
// properties and/or default values as specified in the class
......@@ -169,7 +168,8 @@ public class StreamHandler extends Handler {
* @exception UnsupportedEncodingException if the named encoding is
* not supported.
*/
public void setEncoding(String encoding)
@Override
public synchronized void setEncoding(String encoding)
throws SecurityException, java.io.UnsupportedEncodingException {
super.setEncoding(encoding);
if (output == null) {
......@@ -201,6 +201,7 @@ public class StreamHandler extends Handler {
* @param record description of the log event. A null record is
* silently ignored and is not published
*/
@Override
public synchronized void publish(LogRecord record) {
if (!isLoggable(record)) {
return;
......@@ -240,6 +241,7 @@ public class StreamHandler extends Handler {
* @return true if the <tt>LogRecord</tt> would be logged.
*
*/
@Override
public boolean isLoggable(LogRecord record) {
if (writer == null || record == null) {
return false;
......@@ -250,6 +252,7 @@ public class StreamHandler extends Handler {
/**
* Flush any buffered messages.
*/
@Override
public synchronized void flush() {
if (writer != null) {
try {
......@@ -294,6 +297,7 @@ public class StreamHandler extends Handler {
* @exception SecurityException if a security manager exists and if
* the caller does not have LoggingPermission("control").
*/
@Override
public synchronized void close() throws SecurityException {
flushAndClose();
}
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册