Merge
This commit is contained in:
commit
04d4410fb9
@ -28,7 +28,6 @@ package java.lang.reflect;
|
|||||||
import java.lang.ref.Reference;
|
import java.lang.ref.Reference;
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.security.AccessController;
|
import java.security.AccessController;
|
||||||
import java.security.Permission;
|
|
||||||
import java.security.PrivilegedAction;
|
import java.security.PrivilegedAction;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -53,16 +52,14 @@ import sun.security.util.SecurityConstants;
|
|||||||
* <p>To create a proxy for some interface {@code Foo}:
|
* <p>To create a proxy for some interface {@code Foo}:
|
||||||
* <pre>
|
* <pre>
|
||||||
* InvocationHandler handler = new MyInvocationHandler(...);
|
* InvocationHandler handler = new MyInvocationHandler(...);
|
||||||
* Class proxyClass = Proxy.getProxyClass(
|
* Class<?> proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), Foo.class);
|
||||||
* Foo.class.getClassLoader(), new Class[] { Foo.class });
|
* Foo f = (Foo) proxyClass.getConstructor(InvocationHandler.class).
|
||||||
* Foo f = (Foo) proxyClass.
|
* newInstance(handler);
|
||||||
* getConstructor(new Class[] { InvocationHandler.class }).
|
|
||||||
* newInstance(new Object[] { handler });
|
|
||||||
* </pre>
|
* </pre>
|
||||||
* or more simply:
|
* or more simply:
|
||||||
* <pre>
|
* <pre>
|
||||||
* Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
|
* Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
|
||||||
* new Class[] { Foo.class },
|
* new Class<?>[] { Foo.class },
|
||||||
* handler);
|
* handler);
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
@ -91,7 +88,11 @@ import sun.security.util.SecurityConstants;
|
|||||||
* <p>A proxy class has the following properties:
|
* <p>A proxy class has the following properties:
|
||||||
*
|
*
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>Proxy classes are public, final, and not abstract.
|
* <li>Proxy classes are <em>public, final, and not abstract</em> if
|
||||||
|
* all proxy interfaces are public.</li>
|
||||||
|
*
|
||||||
|
* <li>Proxy classes are <em>non-public, final, and not abstract</em> if
|
||||||
|
* any of the proxy interfaces is non-public.</li>
|
||||||
*
|
*
|
||||||
* <li>The unqualified name of a proxy class is unspecified. The space
|
* <li>The unqualified name of a proxy class is unspecified. The space
|
||||||
* of class names that begin with the string {@code "$Proxy"}
|
* of class names that begin with the string {@code "$Proxy"}
|
||||||
@ -273,76 +274,17 @@ public class Proxy implements java.io.Serializable {
|
|||||||
* @param h the invocation handler for this proxy instance
|
* @param h the invocation handler for this proxy instance
|
||||||
*/
|
*/
|
||||||
protected Proxy(InvocationHandler h) {
|
protected Proxy(InvocationHandler h) {
|
||||||
doNewInstanceCheck();
|
|
||||||
this.h = h;
|
this.h = h;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ProxyAccessHelper {
|
|
||||||
// The permission is implementation specific.
|
|
||||||
static final Permission PROXY_PERMISSION =
|
|
||||||
new ReflectPermission("proxyConstructorNewInstance");
|
|
||||||
// These system properties are defined to provide a short-term
|
|
||||||
// workaround if customers need to disable the new security checks.
|
|
||||||
static final boolean allowNewInstance;
|
|
||||||
static final boolean allowNullLoader;
|
|
||||||
static {
|
|
||||||
allowNewInstance = getBooleanProperty("sun.reflect.proxy.allowsNewInstance");
|
|
||||||
allowNullLoader = getBooleanProperty("sun.reflect.proxy.allowsNullLoader");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean getBooleanProperty(final String key) {
|
|
||||||
String s = AccessController.doPrivileged(new PrivilegedAction<String>() {
|
|
||||||
public String run() {
|
|
||||||
return System.getProperty(key);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return Boolean.valueOf(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
static boolean needsNewInstanceCheck(Class<?> proxyClass) {
|
|
||||||
if (!Proxy.isProxyClass(proxyClass) || allowNewInstance) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (proxyClass.getName().startsWith(ReflectUtil.PROXY_PACKAGE + ".")) {
|
|
||||||
// all proxy interfaces are public
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for (Class<?> intf : proxyClass.getInterfaces()) {
|
|
||||||
if (!Modifier.isPublic(intf.getModifiers())) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Access check on a proxy class that implements any non-public interface.
|
|
||||||
*
|
|
||||||
* @throws SecurityException if a security manager exists, and
|
|
||||||
* the caller does not have the permission.
|
|
||||||
*/
|
|
||||||
private void doNewInstanceCheck() {
|
|
||||||
SecurityManager sm = System.getSecurityManager();
|
|
||||||
Class<?> proxyClass = this.getClass();
|
|
||||||
if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(proxyClass)) {
|
|
||||||
try {
|
|
||||||
sm.checkPermission(ProxyAccessHelper.PROXY_PERMISSION);
|
|
||||||
} catch (SecurityException e) {
|
|
||||||
throw new SecurityException("Not allowed to construct a Proxy "
|
|
||||||
+ "instance that implements a non-public interface", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@code java.lang.Class} object for a proxy class
|
* Returns the {@code java.lang.Class} object for a proxy class
|
||||||
* given a class loader and an array of interfaces. The proxy class
|
* given a class loader and an array of interfaces. The proxy class
|
||||||
* will be defined by the specified class loader and will implement
|
* will be defined by the specified class loader and will implement
|
||||||
* all of the supplied interfaces. If a proxy class for the same
|
* all of the supplied interfaces. If any of the given interfaces
|
||||||
* permutation of interfaces has already been defined by the class
|
* is non-public, the proxy class will be non-public. If a proxy class
|
||||||
* loader, then the existing proxy class will be returned; otherwise,
|
* for the same permutation of interfaces has already been defined by the
|
||||||
|
* class loader, then the existing proxy class will be returned; otherwise,
|
||||||
* a proxy class for those interfaces will be generated dynamically
|
* a proxy class for those interfaces will be generated dynamically
|
||||||
* and defined by the class loader.
|
* and defined by the class loader.
|
||||||
*
|
*
|
||||||
@ -407,6 +349,22 @@ public class Proxy implements java.io.Serializable {
|
|||||||
* @throws IllegalArgumentException if any of the restrictions on the
|
* @throws IllegalArgumentException if any of the restrictions on the
|
||||||
* parameters that may be passed to {@code getProxyClass}
|
* parameters that may be passed to {@code getProxyClass}
|
||||||
* are violated
|
* are violated
|
||||||
|
* @throws SecurityException if a security manager, <em>s</em>, is present
|
||||||
|
* and any of the following conditions is met:
|
||||||
|
* <ul>
|
||||||
|
* <li> the given {@code loader} is {@code null} and
|
||||||
|
* the caller's class loader is not {@code null} and the
|
||||||
|
* invocation of {@link SecurityManager#checkPermission
|
||||||
|
* s.checkPermission} with
|
||||||
|
* {@code RuntimePermission("getClassLoader")} permission
|
||||||
|
* denies access.</li>
|
||||||
|
* <li> the caller's class loader is not the same as or an
|
||||||
|
* ancestor of the class loader for the current class and
|
||||||
|
* invocation of {@link SecurityManager#checkPackageAccess
|
||||||
|
* s.checkPackageAccess()} denies access to any one of the
|
||||||
|
* given proxy interfaces.</li>
|
||||||
|
* </ul>
|
||||||
|
|
||||||
* @throws NullPointerException if the {@code interfaces} array
|
* @throws NullPointerException if the {@code interfaces} array
|
||||||
* argument or any of its elements are {@code null}
|
* argument or any of its elements are {@code null}
|
||||||
*/
|
*/
|
||||||
@ -449,10 +407,8 @@ public class Proxy implements java.io.Serializable {
|
|||||||
if (sm != null) {
|
if (sm != null) {
|
||||||
ClassLoader ccl = caller.getClassLoader();
|
ClassLoader ccl = caller.getClassLoader();
|
||||||
if (VM.isSystemDomainLoader(loader) && !VM.isSystemDomainLoader(ccl)) {
|
if (VM.isSystemDomainLoader(loader) && !VM.isSystemDomainLoader(ccl)) {
|
||||||
if (!ProxyAccessHelper.allowNullLoader) {
|
|
||||||
sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
|
sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
ReflectUtil.checkProxyPackageAccess(ccl, interfaces);
|
ReflectUtil.checkProxyPackageAccess(ccl, interfaces);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -593,6 +549,7 @@ public class Proxy implements java.io.Serializable {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
String proxyPkg = null; // package to define proxy class in
|
String proxyPkg = null; // package to define proxy class in
|
||||||
|
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Record the package of a non-public proxy interface so that the
|
* Record the package of a non-public proxy interface so that the
|
||||||
@ -602,6 +559,7 @@ public class Proxy implements java.io.Serializable {
|
|||||||
for (int i = 0; i < interfaces.length; i++) {
|
for (int i = 0; i < interfaces.length; i++) {
|
||||||
int flags = interfaces[i].getModifiers();
|
int flags = interfaces[i].getModifiers();
|
||||||
if (!Modifier.isPublic(flags)) {
|
if (!Modifier.isPublic(flags)) {
|
||||||
|
accessFlags = Modifier.FINAL;
|
||||||
String name = interfaces[i].getName();
|
String name = interfaces[i].getName();
|
||||||
int n = name.lastIndexOf('.');
|
int n = name.lastIndexOf('.');
|
||||||
String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
|
String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
|
||||||
@ -637,7 +595,7 @@ public class Proxy implements java.io.Serializable {
|
|||||||
* Generate the specified proxy class.
|
* Generate the specified proxy class.
|
||||||
*/
|
*/
|
||||||
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
|
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
|
||||||
proxyName, interfaces);
|
proxyName, interfaces, accessFlags);
|
||||||
try {
|
try {
|
||||||
proxyClass = defineClass0(loader, proxyName,
|
proxyClass = defineClass0(loader, proxyName,
|
||||||
proxyClassFile, 0, proxyClassFile.length);
|
proxyClassFile, 0, proxyClassFile.length);
|
||||||
@ -678,12 +636,7 @@ public class Proxy implements java.io.Serializable {
|
|||||||
/**
|
/**
|
||||||
* Returns an instance of a proxy class for the specified interfaces
|
* Returns an instance of a proxy class for the specified interfaces
|
||||||
* that dispatches method invocations to the specified invocation
|
* that dispatches method invocations to the specified invocation
|
||||||
* handler. This method is equivalent to:
|
* handler.
|
||||||
* <pre>
|
|
||||||
* Proxy.getProxyClass(loader, interfaces).
|
|
||||||
* getConstructor(new Class[] { InvocationHandler.class }).
|
|
||||||
* newInstance(new Object[] { handler });
|
|
||||||
* </pre>
|
|
||||||
*
|
*
|
||||||
* <p>{@code Proxy.newProxyInstance} throws
|
* <p>{@code Proxy.newProxyInstance} throws
|
||||||
* {@code IllegalArgumentException} for the same reasons that
|
* {@code IllegalArgumentException} for the same reasons that
|
||||||
@ -699,6 +652,27 @@ public class Proxy implements java.io.Serializable {
|
|||||||
* @throws IllegalArgumentException if any of the restrictions on the
|
* @throws IllegalArgumentException if any of the restrictions on the
|
||||||
* parameters that may be passed to {@code getProxyClass}
|
* parameters that may be passed to {@code getProxyClass}
|
||||||
* are violated
|
* are violated
|
||||||
|
* @throws SecurityException if a security manager, <em>s</em>, is present
|
||||||
|
* and any of the following conditions is met:
|
||||||
|
* <ul>
|
||||||
|
* <li> the given {@code loader} is {@code null} and
|
||||||
|
* the caller's class loader is not {@code null} and the
|
||||||
|
* invocation of {@link SecurityManager#checkPermission
|
||||||
|
* s.checkPermission} with
|
||||||
|
* {@code RuntimePermission("getClassLoader")} permission
|
||||||
|
* denies access;</li>
|
||||||
|
* <li> the caller's class loader is not the same as or an
|
||||||
|
* ancestor of the class loader for the current class and
|
||||||
|
* invocation of {@link SecurityManager#checkPackageAccess
|
||||||
|
* s.checkPackageAccess()} denies access to any one of the
|
||||||
|
* given proxy interfaces.</li>
|
||||||
|
* <li> any of the given proxy interfaces is non-public and the
|
||||||
|
* caller class is not in the same {@linkplain Package runtime package}
|
||||||
|
* as the non-public interface and the invocation of
|
||||||
|
* {@link SecurityManager#checkPermission s.checkPermission} with
|
||||||
|
* {@code ReflectPermission("newProxyInPackage.{package name}")}
|
||||||
|
* permission denies access.</li>
|
||||||
|
* </ul>
|
||||||
* @throws NullPointerException if the {@code interfaces} array
|
* @throws NullPointerException if the {@code interfaces} array
|
||||||
* argument or any of its elements are {@code null}, or
|
* argument or any of its elements are {@code null}, or
|
||||||
* if the invocation handler, {@code h}, is
|
* if the invocation handler, {@code h}, is
|
||||||
@ -728,24 +702,61 @@ public class Proxy implements java.io.Serializable {
|
|||||||
* Invoke its constructor with the designated invocation handler.
|
* Invoke its constructor with the designated invocation handler.
|
||||||
*/
|
*/
|
||||||
try {
|
try {
|
||||||
|
if (sm != null) {
|
||||||
|
checkNewProxyPermission(Reflection.getCallerClass(), cl);
|
||||||
|
}
|
||||||
|
|
||||||
final Constructor<?> cons = cl.getConstructor(constructorParams);
|
final Constructor<?> cons = cl.getConstructor(constructorParams);
|
||||||
final InvocationHandler ih = h;
|
final InvocationHandler ih = h;
|
||||||
if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) {
|
if (!Modifier.isPublic(cl.getModifiers())) {
|
||||||
// create proxy instance with doPrivilege as the proxy class may
|
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||||
// implement non-public interfaces that requires a special permission
|
public Void run() {
|
||||||
return AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
cons.setAccessible(true);
|
||||||
public Object run() {
|
return null;
|
||||||
return newInstance(cons, ih);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
return cons.newInstance(new Object[]{h});
|
||||||
|
} catch (IllegalAccessException|InstantiationException e) {
|
||||||
|
throw new InternalError(e.toString(), e);
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
Throwable t = e.getCause();
|
||||||
|
if (t instanceof RuntimeException) {
|
||||||
|
throw (RuntimeException) t;
|
||||||
} else {
|
} else {
|
||||||
return newInstance(cons, ih);
|
throw new InternalError(t.toString(), t);
|
||||||
}
|
}
|
||||||
} catch (NoSuchMethodException e) {
|
} catch (NoSuchMethodException e) {
|
||||||
throw new InternalError(e.toString(), e);
|
throw new InternalError(e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void checkNewProxyPermission(Class<?> caller, Class<?> proxyClass) {
|
||||||
|
SecurityManager sm = System.getSecurityManager();
|
||||||
|
if (sm != null) {
|
||||||
|
String pcn = proxyClass.getName();
|
||||||
|
if (pcn.startsWith(ReflectUtil.PROXY_PACKAGE + ".")) {
|
||||||
|
// all proxy interfaces are public
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClassLoader ccl = caller.getClassLoader();
|
||||||
|
ClassLoader pcl = proxyClass.getClassLoader();
|
||||||
|
|
||||||
|
// do permission check if the caller is in a different runtime package
|
||||||
|
// of the proxy class
|
||||||
|
int n = pcn.lastIndexOf('.');
|
||||||
|
String pkg = (n == -1) ? "" : pcn.substring(0, n);
|
||||||
|
|
||||||
|
n = caller.getName().lastIndexOf('.');
|
||||||
|
String callerPkg = (n == -1) ? "" : caller.getName().substring(0, n);
|
||||||
|
|
||||||
|
if (pcl != ccl || !pkg.equals(callerPkg)) {
|
||||||
|
sm.checkPermission(new ReflectPermission("newProxyInPackage." + pkg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static Object newInstance(Constructor<?> cons, InvocationHandler h) {
|
private static Object newInstance(Constructor<?> cons, InvocationHandler h) {
|
||||||
try {
|
try {
|
||||||
return cons.newInstance(new Object[] {h} );
|
return cons.newInstance(new Object[] {h} );
|
||||||
|
@ -26,12 +26,7 @@
|
|||||||
package java.lang.reflect;
|
package java.lang.reflect;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Permission class for reflective operations. A
|
* The Permission class for reflective operations.
|
||||||
* ReflectPermission is a <em>named permission</em> and has no
|
|
||||||
* actions. The only name currently defined is {@code suppressAccessChecks},
|
|
||||||
* which allows suppressing the standard Java language access checks
|
|
||||||
* -- for public, default (package) access, protected, and private
|
|
||||||
* members -- performed by reflected objects at their point of use.
|
|
||||||
* <P>
|
* <P>
|
||||||
* The following table
|
* The following table
|
||||||
* provides a summary description of what the permission allows,
|
* provides a summary description of what the permission allows,
|
||||||
@ -47,12 +42,22 @@ package java.lang.reflect;
|
|||||||
*
|
*
|
||||||
* <tr>
|
* <tr>
|
||||||
* <td>suppressAccessChecks</td>
|
* <td>suppressAccessChecks</td>
|
||||||
* <td>ability to access
|
* <td>ability to suppress the standard Java language access checks
|
||||||
* fields and invoke methods in a class. Note that this includes
|
* on fields and methods in a class; allow access not only public members
|
||||||
* not only public, but protected and private fields and methods as well.</td>
|
* but also allow access to default (package) access, protected,
|
||||||
|
* and private members.</td>
|
||||||
* <td>This is dangerous in that information (possibly confidential) and
|
* <td>This is dangerous in that information (possibly confidential) and
|
||||||
* methods normally unavailable would be accessible to malicious code.</td>
|
* methods normally unavailable would be accessible to malicious code.</td>
|
||||||
* </tr>
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td>newProxyInPackage.{package name}</td>
|
||||||
|
* <td>ability to create a proxy instance in the specified package of which
|
||||||
|
* the non-public interface that the proxy class implements.</td>
|
||||||
|
* <td>This gives code access to classes in packages to which it normally
|
||||||
|
* does not have access and the dynamic proxy class is in the system
|
||||||
|
* protection domain. Malicious code may use these classes to
|
||||||
|
* help in its attempt to compromise security in the system.</td>
|
||||||
|
* </tr>
|
||||||
*
|
*
|
||||||
* </table>
|
* </table>
|
||||||
*
|
*
|
||||||
@ -63,6 +68,7 @@ package java.lang.reflect;
|
|||||||
* @see Field#set
|
* @see Field#set
|
||||||
* @see Method#invoke
|
* @see Method#invoke
|
||||||
* @see Constructor#newInstance
|
* @see Constructor#newInstance
|
||||||
|
* @see Proxy#newProxyInstance
|
||||||
*
|
*
|
||||||
* @since 1.2
|
* @since 1.2
|
||||||
*/
|
*/
|
||||||
|
187
jdk/src/share/classes/java/util/DoubleSummaryStatistics.java
Normal file
187
jdk/src/share/classes/java/util/DoubleSummaryStatistics.java
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
/*
|
||||||
|
* 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.util;
|
||||||
|
|
||||||
|
import java.util.function.DoubleConsumer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A state object for collecting statistics such as count, min, max, sum, and
|
||||||
|
* average.
|
||||||
|
*
|
||||||
|
* <p>This class is designed to work with (though does not require)
|
||||||
|
* {@linkplain java.util.stream streams}. For example, you can compute
|
||||||
|
* summary statistics on a stream of doubles with:
|
||||||
|
* <pre> {@code
|
||||||
|
* DoubleSummaryStatistics stats = doubleStream.collect(DoubleSummaryStatistics::new,
|
||||||
|
* DoubleSummaryStatistics::accept,
|
||||||
|
* DoubleSummaryStatistics::combine);
|
||||||
|
* }</pre>
|
||||||
|
*
|
||||||
|
* <p>{@code DoubleSummaryStatistics} can be used as a
|
||||||
|
* {@linkplain java.util.stream.Stream#reduce(java.util.function.BinaryOperator) reduction}
|
||||||
|
* target for a {@linkplain java.util.stream.Stream stream}. For example:
|
||||||
|
*
|
||||||
|
* <pre> {@code
|
||||||
|
* DoubleSummaryStatistics stats = people.stream()
|
||||||
|
* .collect(Collectors.toDoubleSummaryStatistics(Person::getWeight));
|
||||||
|
*}</pre>
|
||||||
|
*
|
||||||
|
* This computes, in a single pass, the count of people, as well as the minimum,
|
||||||
|
* maximum, sum, and average of their weights.
|
||||||
|
*
|
||||||
|
* @implNote This implementation is not thread safe. However, it is safe to use
|
||||||
|
* {@link java.util.stream.Collectors#toDoubleSummaryStatistics(java.util.function.ToDoubleFunction)
|
||||||
|
* Collectors.toDoubleStatistics()} on a parallel stream, because the parallel
|
||||||
|
* implementation of {@link java.util.stream.Stream#collect Stream.collect()}
|
||||||
|
* provides the necessary partitioning, isolation, and merging of results for
|
||||||
|
* safe and efficient parallel execution.
|
||||||
|
* @since 1.8
|
||||||
|
*/
|
||||||
|
public class DoubleSummaryStatistics implements DoubleConsumer {
|
||||||
|
private long count;
|
||||||
|
private double sum;
|
||||||
|
private double min = Double.POSITIVE_INFINITY;
|
||||||
|
private double max = Double.NEGATIVE_INFINITY;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct an empty instance with zero count, zero sum,
|
||||||
|
* {@code Double.POSITIVE_INFINITY} min, {@code Double.NEGATIVE_INFINITY}
|
||||||
|
* max and zero average.
|
||||||
|
*/
|
||||||
|
public DoubleSummaryStatistics() { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Records another value into the summary information.
|
||||||
|
*
|
||||||
|
* @param value the input value
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void accept(double value) {
|
||||||
|
++count;
|
||||||
|
sum += value;
|
||||||
|
min = Math.min(min, value);
|
||||||
|
max = Math.max(max, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Combines the state of another {@code DoubleSummaryStatistics} into this
|
||||||
|
* one.
|
||||||
|
*
|
||||||
|
* @param other another {@code DoubleSummaryStatistics}
|
||||||
|
* @throws NullPointerException if {@code other} is null
|
||||||
|
*/
|
||||||
|
public void combine(DoubleSummaryStatistics other) {
|
||||||
|
count += other.count;
|
||||||
|
sum += other.sum;
|
||||||
|
min = Math.min(min, other.min);
|
||||||
|
max = Math.max(max, other.max);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the count of values recorded.
|
||||||
|
*
|
||||||
|
* @return the count of values
|
||||||
|
*/
|
||||||
|
public final long getCount() {
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the sum of values recorded, or zero if no values have been
|
||||||
|
* recorded. The sum returned can vary depending upon the order in which
|
||||||
|
* values are recorded. This is due to accumulated rounding error in
|
||||||
|
* addition of values of differing magnitudes. Values sorted by increasing
|
||||||
|
* absolute magnitude tend to yield more accurate results. If any recorded
|
||||||
|
* value is a {@code NaN} or the sum is at any point a {@code NaN} then the
|
||||||
|
* sum will be {@code NaN}.
|
||||||
|
*
|
||||||
|
* @return the sum of values, or zero if none
|
||||||
|
*/
|
||||||
|
public final double getSum() {
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the minimum recorded value, {@code Double.NaN} if any recorded
|
||||||
|
* value was NaN or {@code Double.POSITIVE_INFINITY} if no values were
|
||||||
|
* recorded. Unlike the numerical comparison operators, this method
|
||||||
|
* considers negative zero to be strictly smaller than positive zero.
|
||||||
|
*
|
||||||
|
* @return the minimum recorded value, {@code Double.NaN} if any recorded
|
||||||
|
* value was NaN or {@code Double.POSITIVE_INFINITY} if no values were
|
||||||
|
* recorded
|
||||||
|
*/
|
||||||
|
public final double getMin() {
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the maximum recorded value, {@code Double.NaN} if any recorded
|
||||||
|
* value was NaN or {@code Double.NEGATIVE_INFINITY} if no values were
|
||||||
|
* recorded. Unlike the numerical comparison operators, this method
|
||||||
|
* considers negative zero to be strictly smaller than positive zero.
|
||||||
|
*
|
||||||
|
* @return the maximum recorded value, {@code Double.NaN} if any recorded
|
||||||
|
* value was NaN or {@code Double.NEGATIVE_INFINITY} if no values were
|
||||||
|
* recorded
|
||||||
|
*/
|
||||||
|
public final double getMax() {
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the average of values recorded, or zero if no values have been
|
||||||
|
* recorded. The average returned can vary depending upon the order in
|
||||||
|
* which values are recorded. This is due to accumulated rounding error in
|
||||||
|
* addition of values of differing magnitudes. Values sorted by increasing
|
||||||
|
* absolute magnitude tend to yield more accurate results. If any recorded
|
||||||
|
* value is a {@code NaN} or the sum is at any point a {@code NaN} then the
|
||||||
|
* average will be {@code NaN}.
|
||||||
|
*
|
||||||
|
* @return the average of values, or zero if none
|
||||||
|
*/
|
||||||
|
public final double getAverage() {
|
||||||
|
return getCount() > 0 ? getSum() / getCount() : 0.0d;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* Returns a non-empty string representation of this object suitable for
|
||||||
|
* debugging. The exact presentation format is unspecified and may vary
|
||||||
|
* between implementations and versions.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format(
|
||||||
|
"%s{count=%d, sum=%f, min=%f, average=%f, max=%f}",
|
||||||
|
this.getClass().getSimpleName(),
|
||||||
|
getCount(),
|
||||||
|
getSum(),
|
||||||
|
getMin(),
|
||||||
|
getAverage(),
|
||||||
|
getMax());
|
||||||
|
}
|
||||||
|
}
|
170
jdk/src/share/classes/java/util/IntSummaryStatistics.java
Normal file
170
jdk/src/share/classes/java/util/IntSummaryStatistics.java
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
/*
|
||||||
|
* 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.util;
|
||||||
|
|
||||||
|
import java.util.function.IntConsumer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A state object for collecting statistics such as count, min, max, sum, and
|
||||||
|
* average.
|
||||||
|
*
|
||||||
|
* <p>This class is designed to work with (though does not require)
|
||||||
|
* {@linkplain java.util.stream streams}. For example, you can compute
|
||||||
|
* summary statistics on a stream of ints with:
|
||||||
|
* <pre> {@code
|
||||||
|
* IntSummaryStatistics stats = intStream.collect(IntSummaryStatistics::new,
|
||||||
|
* IntSummaryStatistics::accept,
|
||||||
|
* IntSummaryStatistics::combine);
|
||||||
|
* }</pre>
|
||||||
|
*
|
||||||
|
* <p>{@code IntSummaryStatistics} can be used as a
|
||||||
|
* {@linkplain java.util.stream.Stream#reduce(java.util.function.BinaryOperator) reduction}
|
||||||
|
* target for a {@linkplain java.util.stream.Stream stream}. For example:
|
||||||
|
*
|
||||||
|
* <pre> {@code
|
||||||
|
* IntSummaryStatistics stats = people.stream()
|
||||||
|
* .collect(Collectors.toIntSummaryStatistics(Person::getDependents));
|
||||||
|
*}</pre>
|
||||||
|
*
|
||||||
|
* This computes, in a single pass, the count of people, as well as the minimum,
|
||||||
|
* maximum, sum, and average of their number of dependents.
|
||||||
|
*
|
||||||
|
* @implNote This implementation is not thread safe. However, it is safe to use
|
||||||
|
* {@link java.util.stream.Collectors#toIntSummaryStatistics(java.util.function.ToIntFunction)
|
||||||
|
* Collectors.toIntStatistics()} on a parallel stream, because the parallel
|
||||||
|
* implementation of {@link java.util.stream.Stream#collect Stream.collect()}
|
||||||
|
* provides the necessary partitioning, isolation, and merging of results for
|
||||||
|
* safe and efficient parallel execution.
|
||||||
|
*
|
||||||
|
* <p>This implementation does not check for overflow of the sum.
|
||||||
|
* @since 1.8
|
||||||
|
*/
|
||||||
|
public class IntSummaryStatistics implements IntConsumer {
|
||||||
|
private long count;
|
||||||
|
private long sum;
|
||||||
|
private int min = Integer.MAX_VALUE;
|
||||||
|
private int max = Integer.MIN_VALUE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct an empty instance with zero count, zero sum,
|
||||||
|
* {@code Integer.MAX_VALUE} min, {@code Integer.MIN_VALUE} max and zero
|
||||||
|
* average.
|
||||||
|
*/
|
||||||
|
public IntSummaryStatistics() { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Records a new value into the summary information
|
||||||
|
*
|
||||||
|
* @param value the input value
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void accept(int value) {
|
||||||
|
++count;
|
||||||
|
sum += value;
|
||||||
|
min = Math.min(min, value);
|
||||||
|
max = Math.max(max, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Combines the state of another {@code IntSummaryStatistics} into this one.
|
||||||
|
*
|
||||||
|
* @param other another {@code IntSummaryStatistics}
|
||||||
|
* @throws NullPointerException if {@code other} is null
|
||||||
|
*/
|
||||||
|
public void combine(IntSummaryStatistics other) {
|
||||||
|
count += other.count;
|
||||||
|
sum += other.sum;
|
||||||
|
min = Math.min(min, other.min);
|
||||||
|
max = Math.max(max, other.max);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the count of values recorded.
|
||||||
|
*
|
||||||
|
* @return the count of values
|
||||||
|
*/
|
||||||
|
public final long getCount() {
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the sum of values recorded, or zero if no values have been
|
||||||
|
* recorded.
|
||||||
|
*
|
||||||
|
* @return the sum of values, or zero if none
|
||||||
|
*/
|
||||||
|
public final long getSum() {
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the minimum value recorded, or {@code Integer.MAX_VALUE} if no
|
||||||
|
* values have been recorded.
|
||||||
|
*
|
||||||
|
* @return the minimum value, or {@code Integer.MAX_VALUE} if none
|
||||||
|
*/
|
||||||
|
public final int getMin() {
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the maximum value recorded, or {@code Integer.MIN_VALUE} if no
|
||||||
|
* values have been recorded.
|
||||||
|
*
|
||||||
|
* @return the maximum value, or {@code Integer.MIN_VALUE} if none
|
||||||
|
*/
|
||||||
|
public final int getMax() {
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the average of values recorded, or zero if no values have been
|
||||||
|
* recorded.
|
||||||
|
*
|
||||||
|
* @return the average of values, or zero if none
|
||||||
|
*/
|
||||||
|
public final double getAverage() {
|
||||||
|
return getCount() > 0 ? (double) getSum() / getCount() : 0.0d;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* Returns a non-empty string representation of this object suitable for
|
||||||
|
* debugging. The exact presentation format is unspecified and may vary
|
||||||
|
* between implementations and versions.
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
return String.format(
|
||||||
|
"%s{count=%d, sum=%d, min=%d, average=%d, max=%d}",
|
||||||
|
this.getClass().getSimpleName(),
|
||||||
|
getCount(),
|
||||||
|
getSum(),
|
||||||
|
getMin(),
|
||||||
|
getAverage(),
|
||||||
|
getMax());
|
||||||
|
}
|
||||||
|
}
|
182
jdk/src/share/classes/java/util/LongSummaryStatistics.java
Normal file
182
jdk/src/share/classes/java/util/LongSummaryStatistics.java
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
/*
|
||||||
|
* 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.util;
|
||||||
|
|
||||||
|
import java.util.function.IntConsumer;
|
||||||
|
import java.util.function.LongConsumer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A state object for collecting statistics such as count, min, max, sum, and
|
||||||
|
* average.
|
||||||
|
*
|
||||||
|
* <p>This class is designed to work with (though does not require)
|
||||||
|
* {@linkplain java.util.stream streams}. For example, you can compute
|
||||||
|
* summary statistics on a stream of longs with:
|
||||||
|
* <pre> {@code
|
||||||
|
* LongSummaryStatistics stats = longStream.collect(LongSummaryStatistics::new,
|
||||||
|
* LongSummaryStatistics::accept,
|
||||||
|
* LongSummaryStatistics::combine);
|
||||||
|
* }</pre>
|
||||||
|
*
|
||||||
|
* <p>{@code LongSummaryStatistics} can be used as a
|
||||||
|
* {@linkplain java.util.stream.Stream#reduce(java.util.function.BinaryOperator) reduction}
|
||||||
|
* target for a {@linkplain java.util.stream.Stream stream}. For example:
|
||||||
|
*
|
||||||
|
* <pre> {@code
|
||||||
|
* LongSummaryStatistics stats = people.stream()
|
||||||
|
* .collect(Collectors.toLongSummaryStatistics(Person::getAge));
|
||||||
|
*}</pre>
|
||||||
|
*
|
||||||
|
* This computes, in a single pass, the count of people, as well as the minimum,
|
||||||
|
* maximum, sum, and average of their ages in milliseconds.
|
||||||
|
*
|
||||||
|
* @implNote This implementation is not thread safe. However, it is safe to use
|
||||||
|
* {@link java.util.stream.Collectors#toLongSummaryStatistics(java.util.function.ToLongFunction)
|
||||||
|
* Collectors.toLongStatistics()} on a parallel stream, because the parallel
|
||||||
|
* implementation of {@link java.util.stream.Stream#collect Stream.collect()}
|
||||||
|
* provides the necessary partitioning, isolation, and merging of results for
|
||||||
|
* safe and efficient parallel execution.
|
||||||
|
*
|
||||||
|
* <p>This implementation does not check for overflow of the sum.
|
||||||
|
* @since 1.8
|
||||||
|
*/
|
||||||
|
public class LongSummaryStatistics implements LongConsumer, IntConsumer {
|
||||||
|
private long count;
|
||||||
|
private long sum;
|
||||||
|
private long min = Long.MAX_VALUE;
|
||||||
|
private long max = Long.MIN_VALUE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct an empty instance with zero count, zero sum,
|
||||||
|
* {@code Long.MAX_VALUE} min, {@code Long.MIN_VALUE} max and zero
|
||||||
|
* average.
|
||||||
|
*/
|
||||||
|
public LongSummaryStatistics() { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Records a new {@code int} value into the summary information.
|
||||||
|
*
|
||||||
|
* @param value the input value
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void accept(int value) {
|
||||||
|
accept((long) value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Records a new {@code long} value into the summary information.
|
||||||
|
*
|
||||||
|
* @param value the input value
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void accept(long value) {
|
||||||
|
++count;
|
||||||
|
sum += value;
|
||||||
|
min = Math.min(min, value);
|
||||||
|
max = Math.max(max, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Combines the state of another {@code LongSummaryStatistics} into this
|
||||||
|
* one.
|
||||||
|
*
|
||||||
|
* @param other another {@code LongSummaryStatistics}
|
||||||
|
* @throws NullPointerException if {@code other} is null
|
||||||
|
*/
|
||||||
|
public void combine(LongSummaryStatistics other) {
|
||||||
|
count += other.count;
|
||||||
|
sum += other.sum;
|
||||||
|
min = Math.min(min, other.min);
|
||||||
|
max = Math.max(max, other.max);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the count of values recorded.
|
||||||
|
*
|
||||||
|
* @return the count of values
|
||||||
|
*/
|
||||||
|
public final long getCount() {
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the sum of values recorded, or zero if no values have been
|
||||||
|
* recorded.
|
||||||
|
*
|
||||||
|
* @return the sum of values, or zero if none
|
||||||
|
*/
|
||||||
|
public final long getSum() {
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the minimum value recorded, or {@code Long.MAX_VALUE} if no
|
||||||
|
* values have been recorded.
|
||||||
|
*
|
||||||
|
* @return the minimum value, or {@code Long.MAX_VALUE} if none
|
||||||
|
*/
|
||||||
|
public final long getMin() {
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the maximum value recorded, or {@code Long.MIN_VALUE} if no
|
||||||
|
* values have been recorded
|
||||||
|
*
|
||||||
|
* @return the maximum value, or {@code Long.MIN_VALUE} if none
|
||||||
|
*/
|
||||||
|
public final long getMax() {
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the average of values recorded, or zero if no values have been
|
||||||
|
* recorded.
|
||||||
|
*
|
||||||
|
* @return The average of values, or zero if none
|
||||||
|
*/
|
||||||
|
public final double getAverage() {
|
||||||
|
return getCount() > 0 ? (double) getSum() / getCount() : 0.0d;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* Returns a non-empty string representation of this object suitable for
|
||||||
|
* debugging. The exact presentation format is unspecified and may vary
|
||||||
|
* between implementations and versions.
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
return String.format(
|
||||||
|
"%s{count=%d, sum=%d, min=%d, average=%d, max=%d}",
|
||||||
|
this.getClass().getSimpleName(),
|
||||||
|
getCount(),
|
||||||
|
getSum(),
|
||||||
|
getMin(),
|
||||||
|
getAverage(),
|
||||||
|
getMax());
|
||||||
|
}
|
||||||
|
}
|
@ -27,11 +27,14 @@ package sun.misc;
|
|||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.lang.reflect.Array;
|
import java.lang.reflect.Array;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
@ -314,12 +317,25 @@ public class ProxyGenerator {
|
|||||||
"sun.misc.ProxyGenerator.saveGeneratedFiles")).booleanValue();
|
"sun.misc.ProxyGenerator.saveGeneratedFiles")).booleanValue();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a proxy class given a name and a list of proxy interfaces.
|
* Generate a public proxy class given a name and a list of proxy interfaces.
|
||||||
*/
|
*/
|
||||||
public static byte[] generateProxyClass(final String name,
|
public static byte[] generateProxyClass(final String name,
|
||||||
Class[] interfaces)
|
Class<?>[] interfaces) {
|
||||||
|
return generateProxyClass(name, interfaces, (ACC_PUBLIC | ACC_FINAL | ACC_SUPER));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a proxy class given a name and a list of proxy interfaces.
|
||||||
|
*
|
||||||
|
* @param name the class name of the proxy class
|
||||||
|
* @param interfaces proxy interfaces
|
||||||
|
* @param accessFlags access flags of the proxy class
|
||||||
|
*/
|
||||||
|
public static byte[] generateProxyClass(final String name,
|
||||||
|
Class<?>[] interfaces,
|
||||||
|
int accessFlags)
|
||||||
{
|
{
|
||||||
ProxyGenerator gen = new ProxyGenerator(name, interfaces);
|
ProxyGenerator gen = new ProxyGenerator(name, interfaces, accessFlags);
|
||||||
final byte[] classFile = gen.generateClassFile();
|
final byte[] classFile = gen.generateClassFile();
|
||||||
|
|
||||||
if (saveGeneratedFiles) {
|
if (saveGeneratedFiles) {
|
||||||
@ -327,10 +343,16 @@ public class ProxyGenerator {
|
|||||||
new java.security.PrivilegedAction<Void>() {
|
new java.security.PrivilegedAction<Void>() {
|
||||||
public Void run() {
|
public Void run() {
|
||||||
try {
|
try {
|
||||||
FileOutputStream file =
|
int i = name.lastIndexOf('.');
|
||||||
new FileOutputStream(dotToSlash(name) + ".class");
|
Path path;
|
||||||
file.write(classFile);
|
if (i > 0) {
|
||||||
file.close();
|
Path dir = Paths.get(name.substring(0, i).replace('.', File.separatorChar));
|
||||||
|
Files.createDirectories(dir);
|
||||||
|
path = dir.resolve(name.substring(i+1, name.length()) + ".class");
|
||||||
|
} else {
|
||||||
|
path = Paths.get(name + ".class");
|
||||||
|
}
|
||||||
|
Files.write(path, classFile);
|
||||||
return null;
|
return null;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new InternalError(
|
throw new InternalError(
|
||||||
@ -364,21 +386,23 @@ public class ProxyGenerator {
|
|||||||
/** proxy interfaces */
|
/** proxy interfaces */
|
||||||
private Class[] interfaces;
|
private Class[] interfaces;
|
||||||
|
|
||||||
|
/** proxy class access flags */
|
||||||
|
private int accessFlags;
|
||||||
|
|
||||||
/** constant pool of class being generated */
|
/** constant pool of class being generated */
|
||||||
private ConstantPool cp = new ConstantPool();
|
private ConstantPool cp = new ConstantPool();
|
||||||
|
|
||||||
/** FieldInfo struct for each field of generated class */
|
/** FieldInfo struct for each field of generated class */
|
||||||
private List<FieldInfo> fields = new ArrayList<FieldInfo>();
|
private List<FieldInfo> fields = new ArrayList<>();
|
||||||
|
|
||||||
/** MethodInfo struct for each method of generated class */
|
/** MethodInfo struct for each method of generated class */
|
||||||
private List<MethodInfo> methods = new ArrayList<MethodInfo>();
|
private List<MethodInfo> methods = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* maps method signature string to list of ProxyMethod objects for
|
* maps method signature string to list of ProxyMethod objects for
|
||||||
* proxy methods with that signature
|
* proxy methods with that signature
|
||||||
*/
|
*/
|
||||||
private Map<String, List<ProxyMethod>> proxyMethods =
|
private Map<String, List<ProxyMethod>> proxyMethods = new HashMap<>();
|
||||||
new HashMap<String,List<ProxyMethod>>();
|
|
||||||
|
|
||||||
/** count of ProxyMethod objects added to proxyMethods */
|
/** count of ProxyMethod objects added to proxyMethods */
|
||||||
private int proxyMethodCount = 0;
|
private int proxyMethodCount = 0;
|
||||||
@ -390,9 +414,10 @@ public class ProxyGenerator {
|
|||||||
* A ProxyGenerator object contains the state for the ongoing
|
* A ProxyGenerator object contains the state for the ongoing
|
||||||
* generation of a particular proxy class.
|
* generation of a particular proxy class.
|
||||||
*/
|
*/
|
||||||
private ProxyGenerator(String className, Class[] interfaces) {
|
private ProxyGenerator(String className, Class<?>[] interfaces, int accessFlags) {
|
||||||
this.className = className;
|
this.className = className;
|
||||||
this.interfaces = interfaces;
|
this.interfaces = interfaces;
|
||||||
|
this.accessFlags = accessFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -422,10 +447,9 @@ public class ProxyGenerator {
|
|||||||
* earlier interfaces precedence over later ones with duplicate
|
* earlier interfaces precedence over later ones with duplicate
|
||||||
* methods.
|
* methods.
|
||||||
*/
|
*/
|
||||||
for (int i = 0; i < interfaces.length; i++) {
|
for (Class<?> intf : interfaces) {
|
||||||
Method[] methods = interfaces[i].getMethods();
|
for (Method m : intf.getMethods()) {
|
||||||
for (int j = 0; j < methods.length; j++) {
|
addProxyMethod(m, intf);
|
||||||
addProxyMethod(methods[j], interfaces[i]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -480,8 +504,8 @@ public class ProxyGenerator {
|
|||||||
*/
|
*/
|
||||||
cp.getClass(dotToSlash(className));
|
cp.getClass(dotToSlash(className));
|
||||||
cp.getClass(superclassName);
|
cp.getClass(superclassName);
|
||||||
for (int i = 0; i < interfaces.length; i++) {
|
for (Class<?> intf: interfaces) {
|
||||||
cp.getClass(dotToSlash(interfaces[i].getName()));
|
cp.getClass(dotToSlash(intf.getName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -508,7 +532,7 @@ public class ProxyGenerator {
|
|||||||
cp.write(dout); // (write constant pool)
|
cp.write(dout); // (write constant pool)
|
||||||
|
|
||||||
// u2 access_flags;
|
// u2 access_flags;
|
||||||
dout.writeShort(ACC_PUBLIC | ACC_FINAL | ACC_SUPER);
|
dout.writeShort(accessFlags);
|
||||||
// u2 this_class;
|
// u2 this_class;
|
||||||
dout.writeShort(cp.getClass(dotToSlash(className)));
|
dout.writeShort(cp.getClass(dotToSlash(className)));
|
||||||
// u2 super_class;
|
// u2 super_class;
|
||||||
@ -517,9 +541,9 @@ public class ProxyGenerator {
|
|||||||
// u2 interfaces_count;
|
// u2 interfaces_count;
|
||||||
dout.writeShort(interfaces.length);
|
dout.writeShort(interfaces.length);
|
||||||
// u2 interfaces[interfaces_count];
|
// u2 interfaces[interfaces_count];
|
||||||
for (int i = 0; i < interfaces.length; i++) {
|
for (Class<?> intf : interfaces) {
|
||||||
dout.writeShort(cp.getClass(
|
dout.writeShort(cp.getClass(
|
||||||
dotToSlash(interfaces[i].getName())));
|
dotToSlash(intf.getName())));
|
||||||
}
|
}
|
||||||
|
|
||||||
// u2 fields_count;
|
// u2 fields_count;
|
||||||
@ -576,7 +600,7 @@ public class ProxyGenerator {
|
|||||||
* compatibly with the throws clauses of both
|
* compatibly with the throws clauses of both
|
||||||
* overridden methods.
|
* overridden methods.
|
||||||
*/
|
*/
|
||||||
List<Class<?>> legalExceptions = new ArrayList<Class<?>>();
|
List<Class<?>> legalExceptions = new ArrayList<>();
|
||||||
collectCompatibleTypes(
|
collectCompatibleTypes(
|
||||||
exceptionTypes, pm.exceptionTypes, legalExceptions);
|
exceptionTypes, pm.exceptionTypes, legalExceptions);
|
||||||
collectCompatibleTypes(
|
collectCompatibleTypes(
|
||||||
@ -588,7 +612,7 @@ public class ProxyGenerator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sigmethods = new ArrayList<ProxyMethod>(3);
|
sigmethods = new ArrayList<>(3);
|
||||||
proxyMethods.put(sig, sigmethods);
|
proxyMethods.put(sig, sigmethods);
|
||||||
}
|
}
|
||||||
sigmethods.add(new ProxyMethod(name, parameterTypes, returnType,
|
sigmethods.add(new ProxyMethod(name, parameterTypes, returnType,
|
||||||
@ -618,7 +642,7 @@ public class ProxyGenerator {
|
|||||||
* List of return types that are not yet known to be
|
* List of return types that are not yet known to be
|
||||||
* assignable from ("covered" by) any of the others.
|
* assignable from ("covered" by) any of the others.
|
||||||
*/
|
*/
|
||||||
LinkedList<Class<?>> uncoveredReturnTypes = new LinkedList<Class<?>>();
|
LinkedList<Class<?>> uncoveredReturnTypes = new LinkedList<>();
|
||||||
|
|
||||||
nextNewReturnType:
|
nextNewReturnType:
|
||||||
for (ProxyMethod pm : methods) {
|
for (ProxyMethod pm : methods) {
|
||||||
@ -833,8 +857,8 @@ public class ProxyGenerator {
|
|||||||
// u2 number_of_exceptions;
|
// u2 number_of_exceptions;
|
||||||
out.writeShort(declaredExceptions.length);
|
out.writeShort(declaredExceptions.length);
|
||||||
// u2 exception_index_table[number_of_exceptions];
|
// u2 exception_index_table[number_of_exceptions];
|
||||||
for (int i = 0; i < declaredExceptions.length; i++) {
|
for (short value : declaredExceptions) {
|
||||||
out.writeShort(declaredExceptions[i]);
|
out.writeShort(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1525,11 +1549,11 @@ public class ProxyGenerator {
|
|||||||
Class<?>[] with,
|
Class<?>[] with,
|
||||||
List<Class<?>> list)
|
List<Class<?>> list)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < from.length; i++) {
|
for (Class<?> fc: from) {
|
||||||
if (!list.contains(from[i])) {
|
if (!list.contains(fc)) {
|
||||||
for (int j = 0; j < with.length; j++) {
|
for (Class<?> wc: with) {
|
||||||
if (with[j].isAssignableFrom(from[i])) {
|
if (wc.isAssignableFrom(fc)) {
|
||||||
list.add(from[i]);
|
list.add(fc);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1559,15 +1583,14 @@ public class ProxyGenerator {
|
|||||||
* need to be caught.
|
* need to be caught.
|
||||||
*/
|
*/
|
||||||
private static List<Class<?>> computeUniqueCatchList(Class<?>[] exceptions) {
|
private static List<Class<?>> computeUniqueCatchList(Class<?>[] exceptions) {
|
||||||
List<Class<?>> uniqueList = new ArrayList<Class<?>>();
|
List<Class<?>> uniqueList = new ArrayList<>();
|
||||||
// unique exceptions to catch
|
// unique exceptions to catch
|
||||||
|
|
||||||
uniqueList.add(Error.class); // always catch/rethrow these
|
uniqueList.add(Error.class); // always catch/rethrow these
|
||||||
uniqueList.add(RuntimeException.class);
|
uniqueList.add(RuntimeException.class);
|
||||||
|
|
||||||
nextException:
|
nextException:
|
||||||
for (int i = 0; i < exceptions.length; i++) {
|
for (Class<?> ex: exceptions) {
|
||||||
Class<?> ex = exceptions[i];
|
|
||||||
if (ex.isAssignableFrom(Throwable.class)) {
|
if (ex.isAssignableFrom(Throwable.class)) {
|
||||||
/*
|
/*
|
||||||
* If Throwable is declared to be thrown by the proxy method,
|
* If Throwable is declared to be thrown by the proxy method,
|
||||||
|
@ -30,6 +30,8 @@ import java.util.*;
|
|||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.BufferUnderflowException;
|
import java.nio.BufferUnderflowException;
|
||||||
import java.lang.reflect.*;
|
import java.lang.reflect.*;
|
||||||
|
import java.security.AccessController;
|
||||||
|
import java.security.PrivilegedAction;
|
||||||
import sun.reflect.ConstantPool;
|
import sun.reflect.ConstantPool;
|
||||||
|
|
||||||
import sun.reflect.generics.parser.SignatureParser;
|
import sun.reflect.generics.parser.SignatureParser;
|
||||||
@ -253,12 +255,15 @@ public class AnnotationParser {
|
|||||||
* Returns an annotation of the given type backed by the given
|
* Returns an annotation of the given type backed by the given
|
||||||
* member -> value map.
|
* member -> value map.
|
||||||
*/
|
*/
|
||||||
public static Annotation annotationForMap(
|
public static Annotation annotationForMap(final Class<? extends Annotation> type,
|
||||||
Class<? extends Annotation> type, Map<String, Object> memberValues)
|
final Map<String, Object> memberValues)
|
||||||
{
|
{
|
||||||
|
return AccessController.doPrivileged(new PrivilegedAction<Annotation>() {
|
||||||
|
public Annotation run() {
|
||||||
return (Annotation) Proxy.newProxyInstance(
|
return (Annotation) Proxy.newProxyInstance(
|
||||||
type.getClassLoader(), new Class<?>[] { type },
|
type.getClassLoader(), new Class<?>[] { type },
|
||||||
new AnnotationInvocationHandler(type, memberValues));
|
new AnnotationInvocationHandler(type, memberValues));
|
||||||
|
}});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -48,6 +48,7 @@ import java.security.AccessController;
|
|||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
import java.security.DigestOutputStream;
|
import java.security.DigestOutputStream;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.PrivilegedAction;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -140,17 +141,20 @@ public final class Util {
|
|||||||
return createStub(remoteClass, clientRef);
|
return createStub(remoteClass, clientRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
ClassLoader loader = implClass.getClassLoader();
|
final ClassLoader loader = implClass.getClassLoader();
|
||||||
Class[] interfaces = getRemoteInterfaces(implClass);
|
final Class[] interfaces = getRemoteInterfaces(implClass);
|
||||||
InvocationHandler handler =
|
final InvocationHandler handler =
|
||||||
new RemoteObjectInvocationHandler(clientRef);
|
new RemoteObjectInvocationHandler(clientRef);
|
||||||
|
|
||||||
/* REMIND: private remote interfaces? */
|
/* REMIND: private remote interfaces? */
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
return AccessController.doPrivileged(new PrivilegedAction<Remote>() {
|
||||||
|
public Remote run() {
|
||||||
return (Remote) Proxy.newProxyInstance(loader,
|
return (Remote) Proxy.newProxyInstance(loader,
|
||||||
interfaces,
|
interfaces,
|
||||||
handler);
|
handler);
|
||||||
|
}});
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
throw new StubNotFoundException("unable to create proxy", e);
|
throw new StubNotFoundException("unable to create proxy", e);
|
||||||
}
|
}
|
||||||
|
@ -130,8 +130,12 @@ public abstract class ProviderSkeleton implements InvocationHandler, Provider {
|
|||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <T extends Provider> T newProxyInstance() {
|
public <T extends Provider> T newProxyInstance() {
|
||||||
|
final InvocationHandler ih = this;
|
||||||
|
return AccessController.doPrivileged(new PrivilegedAction<T>() {
|
||||||
|
public T run() {
|
||||||
return (T)Proxy.newProxyInstance(providerType.getClassLoader(),
|
return (T)Proxy.newProxyInstance(providerType.getClassLoader(),
|
||||||
new Class<?>[] { providerType }, this);
|
new Class<?>[] { providerType }, ih);
|
||||||
|
}});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,215 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.InvocationHandler;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.lang.reflect.Proxy;
|
||||||
|
import java.lang.reflect.ReflectPermission;
|
||||||
|
import java.security.AccessControlException;
|
||||||
|
import java.security.CodeSource;
|
||||||
|
import java.security.Permission;
|
||||||
|
import java.security.PermissionCollection;
|
||||||
|
import java.security.Permissions;
|
||||||
|
import java.security.Policy;
|
||||||
|
import java.security.ProtectionDomain;
|
||||||
|
import java.security.SecurityPermission;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 8004260
|
||||||
|
* @summary Test proxy classes that implement non-public interface
|
||||||
|
*
|
||||||
|
* @build p.Foo
|
||||||
|
* @run main/othervm NonPublicProxyClass grant
|
||||||
|
* @run main/othervm NonPublicProxyClass deny
|
||||||
|
* @run main/othervm NonPublicProxyClass
|
||||||
|
*/
|
||||||
|
public class NonPublicProxyClass {
|
||||||
|
public interface PublicInterface {
|
||||||
|
void foo();
|
||||||
|
}
|
||||||
|
interface NonPublicInterface {
|
||||||
|
void bar();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
ClassLoader loader = ClassLoader.getSystemClassLoader();
|
||||||
|
Class<?> zipConstantsClass = Class.forName("java.util.zip.ZipConstants", false, null);
|
||||||
|
Class<?> fooClass = Class.forName("p.Foo");
|
||||||
|
|
||||||
|
NonPublicProxyClass test1 =
|
||||||
|
new NonPublicProxyClass(loader, PublicInterface.class, NonPublicInterface.class);
|
||||||
|
NonPublicProxyClass test2 =
|
||||||
|
new NonPublicProxyClass(loader, fooClass, PublicInterface.class);
|
||||||
|
NonPublicProxyClass test3 =
|
||||||
|
new NonPublicProxyClass(null, zipConstantsClass);
|
||||||
|
|
||||||
|
if (args.length == 1) {
|
||||||
|
switch (args[0]) {
|
||||||
|
case "grant": Policy.setPolicy(new NewInstancePolicy(true));
|
||||||
|
break;
|
||||||
|
case "deny" : Policy.setPolicy(new NewInstancePolicy(false));
|
||||||
|
break;
|
||||||
|
default: throw new IllegalArgumentException(args[0]);
|
||||||
|
}
|
||||||
|
System.setSecurityManager(new SecurityManager());
|
||||||
|
}
|
||||||
|
|
||||||
|
test1.run();
|
||||||
|
test2.run();
|
||||||
|
test3.run();
|
||||||
|
System.out.format("Test passed: security %s%n",
|
||||||
|
(args.length == 0 ? "manager not installed" : Policy.getPolicy()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private final ClassLoader loader;
|
||||||
|
private final Class<?>[] interfaces;
|
||||||
|
private final InvocationHandler handler = newInvocationHandler();
|
||||||
|
private Class<?> proxyClass;
|
||||||
|
public NonPublicProxyClass(ClassLoader loader, Class<?> ... intfs) {
|
||||||
|
this.loader = loader;
|
||||||
|
this.interfaces = intfs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() throws Exception {
|
||||||
|
boolean hasAccess = loader != null || hasAccess();
|
||||||
|
try {
|
||||||
|
proxyClass = Proxy.getProxyClass(loader, interfaces);
|
||||||
|
if (!hasAccess) {
|
||||||
|
throw new RuntimeException("should have no permission to create proxy class");
|
||||||
|
}
|
||||||
|
} catch (AccessControlException e) {
|
||||||
|
if (hasAccess) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
if (e.getPermission().getClass() != RuntimePermission.class ||
|
||||||
|
!e.getPermission().getName().equals("getClassLoader")) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Modifier.isPublic(proxyClass.getModifiers())) {
|
||||||
|
throw new RuntimeException(proxyClass + " must be non-public");
|
||||||
|
}
|
||||||
|
newProxyInstance();
|
||||||
|
newInstanceFromConstructor(proxyClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasAccess() {
|
||||||
|
if (System.getSecurityManager() == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
NewInstancePolicy policy = NewInstancePolicy.class.cast(Policy.getPolicy());
|
||||||
|
return policy.grant;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final static String NEW_PROXY_IN_PKG = "newProxyInPackage.";
|
||||||
|
private void newProxyInstance() {
|
||||||
|
// expect newProxyInstance to succeed if it's in the same runtime package
|
||||||
|
int i = proxyClass.getName().lastIndexOf('.');
|
||||||
|
String pkg = (i != -1) ? proxyClass.getName().substring(0, i) : "";
|
||||||
|
boolean hasAccess = pkg.isEmpty() || hasAccess();
|
||||||
|
try {
|
||||||
|
Proxy.newProxyInstance(loader, interfaces, handler);
|
||||||
|
if (!hasAccess) {
|
||||||
|
throw new RuntimeException("ERROR: Proxy.newProxyInstance should fail " + proxyClass);
|
||||||
|
}
|
||||||
|
} catch (AccessControlException e) {
|
||||||
|
if (hasAccess) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
if (e.getPermission().getClass() != ReflectPermission.class ||
|
||||||
|
!e.getPermission().getName().equals(NEW_PROXY_IN_PKG + pkg)) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void newInstanceFromConstructor(Class<?> proxyClass)
|
||||||
|
throws Exception
|
||||||
|
{
|
||||||
|
// expect newInstance to succeed if it's in the same runtime package
|
||||||
|
boolean isSamePackage = proxyClass.getName().lastIndexOf('.') == -1;
|
||||||
|
try {
|
||||||
|
Constructor cons = proxyClass.getConstructor(InvocationHandler.class);
|
||||||
|
cons.newInstance(newInvocationHandler());
|
||||||
|
if (!isSamePackage) {
|
||||||
|
throw new RuntimeException("ERROR: Constructor.newInstance should not succeed");
|
||||||
|
}
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
if (isSamePackage) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static InvocationHandler newInvocationHandler() {
|
||||||
|
return new InvocationHandler() {
|
||||||
|
public Object invoke(Object proxy, Method method, Object[] args)
|
||||||
|
throws Throwable {
|
||||||
|
Class<?>[] intfs = proxy.getClass().getInterfaces();
|
||||||
|
System.out.println("Proxy for " + Arrays.toString(intfs)
|
||||||
|
+ " " + method.getName() + " is being invoked");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static class NewInstancePolicy extends Policy {
|
||||||
|
final PermissionCollection permissions = new Permissions();
|
||||||
|
final boolean grant;
|
||||||
|
NewInstancePolicy(boolean grant) {
|
||||||
|
this.grant = grant;
|
||||||
|
permissions.add(new SecurityPermission("getPolicy"));
|
||||||
|
if (grant) {
|
||||||
|
permissions.add(new RuntimePermission("getClassLoader"));
|
||||||
|
permissions.add(new ReflectPermission(NEW_PROXY_IN_PKG + "p"));
|
||||||
|
permissions.add(new ReflectPermission(NEW_PROXY_IN_PKG + "java.util.zip"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public PermissionCollection getPermissions(ProtectionDomain domain) {
|
||||||
|
return permissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PermissionCollection getPermissions(CodeSource codesource) {
|
||||||
|
return permissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean implies(ProtectionDomain domain, Permission perm) {
|
||||||
|
return permissions.implies(perm);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder sb = new StringBuilder("policy: ");
|
||||||
|
Enumeration<Permission> perms = permissions.elements();
|
||||||
|
while (perms.hasMoreElements()) {
|
||||||
|
sb.append("\n").append(perms.nextElement().toString());
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.lang.reflect.*;
|
||||||
|
import java.security.*;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 8004260
|
||||||
|
* @summary Test making a proxy instance that implements a non-public
|
||||||
|
* interface with and without security manager installed
|
||||||
|
* @build p.Foo p.Bar
|
||||||
|
* @run main SimpleProxy
|
||||||
|
*/
|
||||||
|
public class SimpleProxy {
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
ClassLoader loader = SimpleProxy.class.getClassLoader();
|
||||||
|
Class<?> fooClass = Class.forName("p.Foo");
|
||||||
|
Class<?> barClass = Class.forName("p.Bar");
|
||||||
|
|
||||||
|
makeProxy(loader, fooClass);
|
||||||
|
|
||||||
|
System.setSecurityManager(new SecurityManager());
|
||||||
|
try {
|
||||||
|
makeProxy(loader, barClass);
|
||||||
|
throw new RuntimeException("should fail to new proxy instance of a non-public interface");
|
||||||
|
} catch (AccessControlException e) {
|
||||||
|
if (e.getPermission().getClass() != ReflectPermission.class ||
|
||||||
|
!e.getPermission().getName().equals("newProxyInPackage.p")) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void makeProxy(ClassLoader loader, Class<?> cls) {
|
||||||
|
Class<?>[] intfs = new Class<?>[] { cls };
|
||||||
|
Proxy.newProxyInstance(loader, intfs, new InvocationHandler() {
|
||||||
|
public Object invoke(Object proxy, Method method, Object[] args)
|
||||||
|
throws Throwable {
|
||||||
|
Class<?>[] intfs = proxy.getClass().getInterfaces();
|
||||||
|
System.out.println("Proxy for " + Arrays.toString(intfs)
|
||||||
|
+ " " + method.getName() + " is being invoked");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
26
jdk/test/java/lang/reflect/Proxy/nonPublicProxy/p/Bar.java
Normal file
26
jdk/test/java/lang/reflect/Proxy/nonPublicProxy/p/Bar.java
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 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.
|
||||||
|
*
|
||||||
|
* 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 p;
|
||||||
|
interface Bar {
|
||||||
|
}
|
26
jdk/test/java/lang/reflect/Proxy/nonPublicProxy/p/Foo.java
Normal file
26
jdk/test/java/lang/reflect/Proxy/nonPublicProxy/p/Foo.java
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 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.
|
||||||
|
*
|
||||||
|
* 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 p;
|
||||||
|
interface Foo {
|
||||||
|
}
|
@ -16,6 +16,9 @@ grant {
|
|||||||
permission java.lang.RuntimePermission "getClassLoader";
|
permission java.lang.RuntimePermission "getClassLoader";
|
||||||
permission java.lang.RuntimePermission "setContextClassLoader";
|
permission java.lang.RuntimePermission "setContextClassLoader";
|
||||||
|
|
||||||
|
permission java.lang.reflect.ReflectPermission "newProxyInPackage.";
|
||||||
|
permission java.lang.reflect.ReflectPermission "newProxyInPackage.java.util.zip";
|
||||||
|
|
||||||
// used by TestLibrary to determine test environment
|
// used by TestLibrary to determine test environment
|
||||||
permission java.util.PropertyPermission "test.classes", "read";
|
permission java.util.PropertyPermission "test.classes", "read";
|
||||||
permission java.util.PropertyPermission "test.src", "read";
|
permission java.util.PropertyPermission "test.src", "read";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user