8023630: Implement Java.super() as the preferred way to call super methods
Reviewed-by: jlaskey, lagergren, sundar
This commit is contained in:
parent
8940235d91
commit
3a14dde3d2
@ -32,7 +32,6 @@ import java.lang.reflect.Array;
|
||||
import java.util.Collection;
|
||||
import java.util.Deque;
|
||||
import java.util.List;
|
||||
|
||||
import jdk.internal.dynalink.beans.StaticClass;
|
||||
import jdk.internal.dynalink.support.TypeUtilities;
|
||||
import jdk.nashorn.internal.objects.annotations.Attribute;
|
||||
@ -44,6 +43,7 @@ import jdk.nashorn.internal.runtime.JSType;
|
||||
import jdk.nashorn.internal.runtime.ListAdapter;
|
||||
import jdk.nashorn.internal.runtime.PropertyMap;
|
||||
import jdk.nashorn.internal.runtime.ScriptObject;
|
||||
import jdk.nashorn.internal.runtime.linker.Bootstrap;
|
||||
import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory;
|
||||
|
||||
/**
|
||||
@ -539,4 +539,25 @@ public final class NativeJava {
|
||||
}
|
||||
return JavaAdapterFactory.getAdapterClassFor(stypes, classOverrides);
|
||||
}
|
||||
|
||||
/**
|
||||
* When given an object created using {@code Java.extend()} or equivalent mechanism (that is, any JavaScript-to-Java
|
||||
* adapter), returns an object that can be used to invoke superclass methods on that object. E.g.:
|
||||
* <pre>
|
||||
* var cw = new FilterWriterAdapter(sw) {
|
||||
* write: function(s, off, len) {
|
||||
* s = capitalize(s, off, len)
|
||||
* cw_super.write(s, 0, s.length())
|
||||
* }
|
||||
* }
|
||||
* var cw_super = Java.super(cw)
|
||||
* </pre>
|
||||
* @param self the {@code Java} object itself - not used.
|
||||
* @param adapter the original Java adapter instance for which the super adapter is created.
|
||||
* @return a super adapter for the original adapter
|
||||
*/
|
||||
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR, name="super")
|
||||
public static Object _super(final Object self, final Object adapter) {
|
||||
return Bootstrap.createSuperAdapter(adapter);
|
||||
}
|
||||
}
|
||||
|
@ -30,11 +30,10 @@ import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.Locale;
|
||||
import jdk.internal.dynalink.beans.BeansLinker;
|
||||
import jdk.internal.dynalink.beans.StaticClass;
|
||||
import jdk.nashorn.api.scripting.ScriptObjectMirror;
|
||||
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
|
||||
import jdk.nashorn.internal.parser.Lexer;
|
||||
import jdk.nashorn.internal.runtime.linker.Bootstrap;
|
||||
|
||||
/**
|
||||
* Representation for ECMAScript types - this maps directly to the ECMA script standard
|
||||
@ -148,22 +147,10 @@ public enum JSType {
|
||||
return JSType.STRING;
|
||||
}
|
||||
|
||||
if (obj instanceof ScriptObject) {
|
||||
return (obj instanceof ScriptFunction) ? JSType.FUNCTION : JSType.OBJECT;
|
||||
}
|
||||
|
||||
if (obj instanceof StaticClass) {
|
||||
if (Bootstrap.isCallable(obj)) {
|
||||
return JSType.FUNCTION;
|
||||
}
|
||||
|
||||
if (BeansLinker.isDynamicMethod(obj)) {
|
||||
return JSType.FUNCTION;
|
||||
}
|
||||
|
||||
if (obj instanceof ScriptObjectMirror) {
|
||||
return ((ScriptObjectMirror)obj).isFunction()? JSType.FUNCTION : JSType.OBJECT;
|
||||
}
|
||||
|
||||
return JSType.OBJECT;
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,7 @@ import jdk.internal.dynalink.CallSiteDescriptor;
|
||||
import jdk.internal.dynalink.DynamicLinker;
|
||||
import jdk.internal.dynalink.DynamicLinkerFactory;
|
||||
import jdk.internal.dynalink.beans.BeansLinker;
|
||||
import jdk.internal.dynalink.beans.StaticClass;
|
||||
import jdk.internal.dynalink.linker.GuardedInvocation;
|
||||
import jdk.internal.dynalink.linker.LinkerServices;
|
||||
import jdk.nashorn.api.scripting.ScriptObjectMirror;
|
||||
@ -61,7 +62,7 @@ public final class Bootstrap {
|
||||
static {
|
||||
final DynamicLinkerFactory factory = new DynamicLinkerFactory();
|
||||
factory.setPrioritizedLinkers(new NashornLinker(), new NashornPrimitiveLinker(), new NashornStaticClassLinker(),
|
||||
new BoundDynamicMethodLinker(), new JSObjectLinker(), new ReflectionCheckLinker());
|
||||
new BoundDynamicMethodLinker(), new JavaSuperAdapterLinker(), new JSObjectLinker(), new ReflectionCheckLinker());
|
||||
factory.setFallbackLinkers(new BeansLinker(), new NashornBottomLinker());
|
||||
factory.setSyncOnRelink(true);
|
||||
final int relinkThreshold = Options.getIntProperty("nashorn.unstable.relink.threshold", -1);
|
||||
@ -88,7 +89,8 @@ public final class Bootstrap {
|
||||
return obj instanceof ScriptFunction ||
|
||||
((obj instanceof ScriptObjectMirror) && ((ScriptObjectMirror)obj).isFunction()) ||
|
||||
isDynamicMethod(obj) ||
|
||||
isFunctionalInterfaceObject(obj);
|
||||
isFunctionalInterfaceObject(obj) ||
|
||||
obj instanceof StaticClass;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -261,6 +263,16 @@ public final class Bootstrap {
|
||||
return new BoundDynamicMethod(dynamicMethod, boundThis);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a super-adapter for an adapter, that is, an adapter to the adapter that allows invocation of superclass
|
||||
* methods on it.
|
||||
* @param adapter the original adapter
|
||||
* @return a new adapter that can be used to invoke super methods on the original adapter.
|
||||
*/
|
||||
public static Object createSuperAdapter(final Object adapter) {
|
||||
return new JavaSuperAdapter(adapter);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the given class is a reflection-specific class (anything in {@code java.lang.reflect} and
|
||||
* {@code java.lang.invoke} package, as well a {@link Class} and any subclass of {@link ClassLoader}) and there is
|
||||
|
@ -67,11 +67,12 @@ final class BoundDynamicMethodLinker implements TypeBasedGuardingDynamicLinker {
|
||||
// BeansLinker.
|
||||
final CallSiteDescriptor descriptor = linkRequest.getCallSiteDescriptor();
|
||||
final MethodType type = descriptor.getMethodType();
|
||||
final Class<?> dynamicMethodClass = dynamicMethod.getClass();
|
||||
final CallSiteDescriptor newDescriptor = descriptor.changeMethodType(
|
||||
type.changeParameterType(0, dynamicMethod.getClass()).changeParameterType(1, boundThis.getClass()));
|
||||
type.changeParameterType(0, dynamicMethodClass).changeParameterType(1, boundThis.getClass()));
|
||||
|
||||
// Delegate to BeansLinker
|
||||
final GuardedInvocation inv = BeansLinker.getLinkerForClass(dynamicMethod.getClass()).getGuardedInvocation(
|
||||
final GuardedInvocation inv = BeansLinker.getLinkerForClass(dynamicMethodClass).getGuardedInvocation(
|
||||
linkRequest.replaceArguments(newDescriptor, args), linkerServices);
|
||||
if(inv == null) {
|
||||
return null;
|
||||
|
@ -174,7 +174,7 @@ final class JavaAdapterBytecodeGenerator {
|
||||
private static final String STATIC_GLOBAL_FIELD_NAME = "staticGlobal";
|
||||
|
||||
// Method name prefix for invoking super-methods
|
||||
private static final String SUPER_PREFIX = "super$";
|
||||
static final String SUPER_PREFIX = "super$";
|
||||
|
||||
/**
|
||||
* Collection of methods we never override: Object.clone(), Object.finalize().
|
||||
|
@ -34,7 +34,6 @@ import java.security.Permissions;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.security.SecureClassLoader;
|
||||
|
||||
import jdk.internal.dynalink.beans.StaticClass;
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 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 jdk.nashorn.internal.runtime.linker;
|
||||
|
||||
/**
|
||||
* Represents a an adapter for invoking superclass methods on an adapter instance generated by
|
||||
* {@link JavaAdapterBytecodeGenerator}. Note that objects of this class are just wrappers around the adapter instances,
|
||||
* without any behavior. All the behavior is defined in the {@code JavaSuperAdapterLinker}.
|
||||
*/
|
||||
class JavaSuperAdapter {
|
||||
private final Object adapter;
|
||||
|
||||
JavaSuperAdapter(final Object adapter) {
|
||||
adapter.getClass(); // NPE check
|
||||
this.adapter = adapter;
|
||||
}
|
||||
|
||||
public Object getAdapter() {
|
||||
return adapter;
|
||||
}
|
||||
}
|
@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 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 jdk.nashorn.internal.runtime.linker;
|
||||
|
||||
import static jdk.nashorn.internal.lookup.Lookup.EMPTY_GETTER;
|
||||
import static jdk.nashorn.internal.runtime.linker.JavaAdapterBytecodeGenerator.SUPER_PREFIX;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import jdk.internal.dynalink.CallSiteDescriptor;
|
||||
import jdk.internal.dynalink.beans.BeansLinker;
|
||||
import jdk.internal.dynalink.linker.GuardedInvocation;
|
||||
import jdk.internal.dynalink.linker.LinkRequest;
|
||||
import jdk.internal.dynalink.linker.LinkerServices;
|
||||
import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker;
|
||||
import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
|
||||
import jdk.internal.dynalink.support.Lookup;
|
||||
import jdk.nashorn.internal.runtime.ScriptRuntime;
|
||||
|
||||
/**
|
||||
* A linker for instances of {@link JavaSuperAdapter}. Only links {@code getMethod} calls, by forwarding them to the
|
||||
* bean linker for the adapter class and prepending {@code super$} to method names.
|
||||
*
|
||||
*/
|
||||
final class JavaSuperAdapterLinker implements TypeBasedGuardingDynamicLinker {
|
||||
private static final String GET_METHOD = "getMethod";
|
||||
private static final String DYN_GET_METHOD = "dyn:" + GET_METHOD;
|
||||
private static final String DYN_GET_METHOD_FIXED = DYN_GET_METHOD + ":" + SUPER_PREFIX;
|
||||
|
||||
private static final MethodHandle ADD_PREFIX_TO_METHOD_NAME;
|
||||
private static final MethodHandle BIND_DYNAMIC_METHOD;
|
||||
private static final MethodHandle GET_ADAPTER;
|
||||
private static final MethodHandle IS_ADAPTER_OF_CLASS;
|
||||
|
||||
static {
|
||||
final Lookup lookup = new Lookup(MethodHandles.lookup());
|
||||
ADD_PREFIX_TO_METHOD_NAME = lookup.findOwnStatic("addPrefixToMethodName", Object.class, Object.class);
|
||||
BIND_DYNAMIC_METHOD = lookup.findOwnStatic("bindDynamicMethod", Object.class, Object.class, Object.class);
|
||||
GET_ADAPTER = lookup.findVirtual(JavaSuperAdapter.class, "getAdapter", MethodType.methodType(Object.class));
|
||||
IS_ADAPTER_OF_CLASS = lookup.findOwnStatic("isAdapterOfClass", boolean.class, Class.class, Object.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canLinkType(final Class<?> type) {
|
||||
return type == JavaSuperAdapter.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices)
|
||||
throws Exception {
|
||||
final Object objSuperAdapter = linkRequest.getReceiver();
|
||||
if(!(objSuperAdapter instanceof JavaSuperAdapter)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final CallSiteDescriptor descriptor = linkRequest.getCallSiteDescriptor();
|
||||
if(!CallSiteDescriptorFactory.tokenizeOperators(descriptor).contains(GET_METHOD)) {
|
||||
// We only handle getMethod
|
||||
return null;
|
||||
}
|
||||
|
||||
final Object adapter = ((JavaSuperAdapter)objSuperAdapter).getAdapter();
|
||||
|
||||
// Replace argument (javaSuperAdapter, ...) => (adapter, ...) when delegating to BeansLinker
|
||||
final Object[] args = linkRequest.getArguments();
|
||||
args[0] = adapter;
|
||||
|
||||
// Use R(T0, ...) => R(adapter.class, ...) call site type when delegating to BeansLinker.
|
||||
final MethodType type = descriptor.getMethodType();
|
||||
final Class<?> adapterClass = adapter.getClass();
|
||||
final boolean hasFixedName = descriptor.getNameTokenCount() > 2;
|
||||
final String opName = hasFixedName ? (DYN_GET_METHOD_FIXED + descriptor.getNameToken(
|
||||
CallSiteDescriptor.NAME_OPERAND)) : DYN_GET_METHOD;
|
||||
|
||||
final CallSiteDescriptor newDescriptor = NashornCallSiteDescriptor.get(descriptor.getLookup(), opName,
|
||||
type.changeParameterType(0, adapterClass), 0);
|
||||
|
||||
// Delegate to BeansLinker
|
||||
final GuardedInvocation guardedInv = BeansLinker.getLinkerForClass(adapterClass).getGuardedInvocation(
|
||||
linkRequest.replaceArguments(newDescriptor, args), linkerServices);
|
||||
|
||||
final MethodHandle guard = IS_ADAPTER_OF_CLASS.bindTo(adapterClass);
|
||||
if(guardedInv == null) {
|
||||
// Short circuit the lookup here for non-existent methods by linking an empty getter. If we just returned
|
||||
// null instead, BeansLinker would find final methods on the JavaSuperAdapter instead: getClass() and
|
||||
// wait().
|
||||
return new GuardedInvocation(MethodHandles.dropArguments(EMPTY_GETTER, 1,type.parameterList().subList(1,
|
||||
type.parameterCount())), guard).asType(descriptor);
|
||||
}
|
||||
|
||||
final MethodHandle invocation = guardedInv.getInvocation();
|
||||
final MethodType invType = invocation.type();
|
||||
// For invocation typed R(T0, ...) create a dynamic method binder of type R(R, T0)
|
||||
final MethodHandle typedBinder = BIND_DYNAMIC_METHOD.asType(MethodType.methodType(invType.returnType(),
|
||||
invType.returnType(), invType.parameterType(0)));
|
||||
// For invocation typed R(T0, T1, ...) create a dynamic method binder of type R(R, T0, T1, ...)
|
||||
final MethodHandle droppingBinder = MethodHandles.dropArguments(typedBinder, 2,
|
||||
invType.parameterList().subList(1, invType.parameterCount()));
|
||||
// Finally, fold the invocation into the binder to produce a method handle that will bind every returned
|
||||
// DynamicMethod object from dyn:getMethod calls to the actual receiver
|
||||
// R(R(T0, T1, ...), T0, T1, ...)
|
||||
final MethodHandle bindingInvocation = MethodHandles.foldArguments(droppingBinder, invocation);
|
||||
|
||||
final MethodHandle typedGetAdapter = asFilterType(GET_ADAPTER, 0, invType, type);
|
||||
final MethodHandle adaptedInvocation;
|
||||
if(hasFixedName) {
|
||||
adaptedInvocation = MethodHandles.filterArguments(bindingInvocation, 0, typedGetAdapter);
|
||||
} else {
|
||||
// Add a filter that'll prepend "super$" to each name passed to the variable-name "dyn:getMethod".
|
||||
final MethodHandle typedAddPrefix = asFilterType(ADD_PREFIX_TO_METHOD_NAME, 1, invType, type);
|
||||
adaptedInvocation = MethodHandles.filterArguments(bindingInvocation, 0, typedGetAdapter, typedAddPrefix);
|
||||
}
|
||||
|
||||
return guardedInv.replaceMethods(adaptedInvocation, guard).asType(descriptor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapts the type of a method handle used as a filter in a position from a source method type to a target method type.
|
||||
* @param filter the filter method handle
|
||||
* @param pos the position in the argument list that it's filtering
|
||||
* @param targetType the target method type for filtering
|
||||
* @param sourceType the source method type for filtering
|
||||
* @return a type adapted filter
|
||||
*/
|
||||
private static MethodHandle asFilterType(final MethodHandle filter, int pos, MethodType targetType, MethodType sourceType) {
|
||||
return filter.asType(MethodType.methodType(targetType.parameterType(pos), sourceType.parameterType(pos)));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static Object addPrefixToMethodName(final Object name) {
|
||||
return SUPER_PREFIX.concat(String.valueOf(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to transform the return value of getMethod; transform a {@code DynamicMethod} into a
|
||||
* {@code BoundDynamicMethod} while also accounting for the possibility of a non-existent method.
|
||||
* @param dynamicMethod the dynamic method to bind
|
||||
* @param boundThis the adapter underlying a super adapter, to which the dynamic method is bound.
|
||||
* @return a dynamic method bound to the adapter instance.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private static Object bindDynamicMethod(final Object dynamicMethod, final Object boundThis) {
|
||||
return dynamicMethod == null ? ScriptRuntime.UNDEFINED : Bootstrap.bindDynamicMethod(dynamicMethod, boundThis);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used as the guard of linkages, as the receiver is not guaranteed to be a JavaSuperAdapter.
|
||||
* @param clazz the class the receiver's adapter is tested against.
|
||||
* @param obj receiver
|
||||
* @return true if the receiver is a super adapter, and its underlying adapter is of the specified class
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private static boolean isAdapterOfClass(Class<?> clazz, Object obj) {
|
||||
return obj instanceof JavaSuperAdapter && clazz == (((JavaSuperAdapter)obj).getAdapter()).getClass();
|
||||
}
|
||||
}
|
94
nashorn/test/script/basic/JDK-8023630.js
Normal file
94
nashorn/test/script/basic/JDK-8023630.js
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8023630: Implement Java.super() as the preferred way to call super methods
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
*/
|
||||
|
||||
var CharArray = Java.type("char[]")
|
||||
var jString = Java.type("java.lang.String")
|
||||
var Character = Java.type("java.lang.Character")
|
||||
|
||||
function capitalize(s) {
|
||||
if(s instanceof CharArray) {
|
||||
return new jString(s).toUpperCase()
|
||||
}
|
||||
if(s instanceof jString) {
|
||||
return s.toUpperCase()
|
||||
}
|
||||
return Character.toUpperCase(s) // must be int
|
||||
}
|
||||
|
||||
var sw = new (Java.type("java.io.StringWriter"))
|
||||
|
||||
var FilterWriterAdapter = Java.extend(Java.type("java.io.FilterWriter"))
|
||||
|
||||
var cw = new FilterWriterAdapter(sw) {
|
||||
write: function(s, off, len) {
|
||||
s = capitalize(s)
|
||||
// Must handle overloads by arity
|
||||
if(off === undefined) {
|
||||
cw_super.write(s, 0, s.length())
|
||||
} else if (typeof s === "string") {
|
||||
cw_super.write(s, off, len)
|
||||
}
|
||||
}
|
||||
}
|
||||
var cw_super = Java.super(cw)
|
||||
|
||||
cw.write("abcd")
|
||||
cw.write("e".charAt(0))
|
||||
cw.write("fgh".toCharArray())
|
||||
cw.write("**ijk**", 2, 3)
|
||||
cw.write("***lmno**".toCharArray(), 3, 4)
|
||||
cw.flush()
|
||||
print(sw)
|
||||
|
||||
// Can invoke super for Object methods
|
||||
print("cw_super has hashCode(): " + (typeof cw_super.hashCode === "function"))
|
||||
print("cw_super has super equals(): " + (typeof cw_super.equals === "function"))
|
||||
// Can't invoke super for final methods
|
||||
print("cw_super has no getClass(): " + (typeof cw_super.getClass === "undefined"))
|
||||
print("cw_super has no wait(): " + (typeof cw_super.wait === "undefined"))
|
||||
|
||||
var r = new (Java.type("java.lang.Runnable"))(function() {})
|
||||
var r_super = Java.super(r)
|
||||
|
||||
// Can't invoke super for abstract methods
|
||||
print("r_super has no run(): " + (typeof r_super.run === "undefined"))
|
||||
// Interfaces can also invoke super Object methods
|
||||
print("r_super has hashCode(): " + (typeof r_super.hashCode === "function"))
|
||||
print("r_super has equals(): " + (typeof r_super.equals === "function"))
|
||||
// But still can't invoke final methods
|
||||
print("r_super has no getClass(): " + (typeof r_super.getClass === "undefined"))
|
||||
print("r_super has no wait(): " + (typeof r_super.wait === "undefined"))
|
||||
|
||||
var name = "write"
|
||||
print("cw_super can access write through [] getter: " + (typeof cw_super[name] === "function"))
|
||||
var name = "hashCode"
|
||||
print("cw_super can access hashCode through [] getter: " + (typeof cw_super[name] === "function"))
|
||||
var name = "getClass"
|
||||
print("cw_super can not access getClass through [] getter: " + (typeof cw_super[name] === "undefined"))
|
13
nashorn/test/script/basic/JDK-8023630.js.EXPECTED
Normal file
13
nashorn/test/script/basic/JDK-8023630.js.EXPECTED
Normal file
@ -0,0 +1,13 @@
|
||||
ABCDEFGHIJKLMNO
|
||||
cw_super has hashCode(): true
|
||||
cw_super has super equals(): true
|
||||
cw_super has no getClass(): true
|
||||
cw_super has no wait(): true
|
||||
r_super has no run(): true
|
||||
r_super has hashCode(): true
|
||||
r_super has equals(): true
|
||||
r_super has no getClass(): true
|
||||
r_super has no wait(): true
|
||||
cw_super can access write through [] getter: true
|
||||
cw_super can access hashCode through [] getter: true
|
||||
cw_super can not access getClass through [] getter: true
|
@ -35,7 +35,10 @@ if (typeof (5).x !== 'number') {
|
||||
fail("typeof(5).x is not 'number'");
|
||||
}
|
||||
|
||||
if (typeof (java.lang.System.out) != 'object') {
|
||||
// It is function because PrintStream implements Closeable, which is
|
||||
// marked with @FunctionalInterface. Yes, this means calling a stream
|
||||
// like "stream()" closes it.
|
||||
if (typeof (java.lang.System.out) != 'function') {
|
||||
fail("typeof java.lang.System.out is not 'object'");
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user