src/jdk/nashorn/internal/runtime/NativeJavaPackage.java

Wed, 20 Aug 2014 10:25:28 +0200

author
attila
date
Wed, 20 Aug 2014 10:25:28 +0200
changeset 962
ac62e33a99b0
parent 771
5ab19753ce4a
child 963
e2497b11a021
permissions
-rw-r--r--

8044638: Tidy up Nashorn codebase for code standards
8055199: Tidy up Nashorn codebase for code standards (August 2014)
Reviewed-by: lagergren, sundar

jlaskey@3 1 /*
jlaskey@7 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
jlaskey@3 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jlaskey@3 4 *
jlaskey@3 5 * This code is free software; you can redistribute it and/or modify it
jlaskey@3 6 * under the terms of the GNU General Public License version 2 only, as
jlaskey@3 7 * published by the Free Software Foundation. Oracle designates this
jlaskey@3 8 * particular file as subject to the "Classpath" exception as provided
jlaskey@3 9 * by Oracle in the LICENSE file that accompanied this code.
jlaskey@3 10 *
jlaskey@3 11 * This code is distributed in the hope that it will be useful, but WITHOUT
jlaskey@3 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jlaskey@3 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
jlaskey@3 14 * version 2 for more details (a copy is included in the LICENSE file that
jlaskey@3 15 * accompanied this code).
jlaskey@3 16 *
jlaskey@3 17 * You should have received a copy of the GNU General Public License version
jlaskey@3 18 * 2 along with this work; if not, write to the Free Software Foundation,
jlaskey@3 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jlaskey@3 20 *
jlaskey@3 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
jlaskey@3 22 * or visit www.oracle.com if you need additional information or have any
jlaskey@3 23 * questions.
jlaskey@3 24 */
jlaskey@3 25
jlaskey@3 26 package jdk.nashorn.internal.runtime;
jlaskey@3 27
attila@281 28 import java.lang.invoke.MethodHandle;
attila@281 29 import java.lang.invoke.MethodHandles;
attila@281 30 import java.lang.invoke.MethodType;
attila@90 31 import jdk.internal.dynalink.CallSiteDescriptor;
attila@90 32 import jdk.internal.dynalink.beans.StaticClass;
attila@90 33 import jdk.internal.dynalink.linker.GuardedInvocation;
attila@90 34 import jdk.internal.dynalink.linker.LinkRequest;
attila@281 35 import jdk.internal.dynalink.support.Guards;
attila@281 36 import jdk.nashorn.internal.lookup.MethodHandleFactory;
attila@281 37 import jdk.nashorn.internal.lookup.MethodHandleFunctionality;
jlaskey@3 38 import jdk.nashorn.internal.objects.annotations.Attribute;
jlaskey@3 39 import jdk.nashorn.internal.objects.annotations.Function;
jlaskey@3 40
jlaskey@3 41 /**
jlaskey@3 42 * An object that exposes Java packages and classes as its properties. Packages are exposed as objects that have further
jlaskey@3 43 * sub-packages and classes as their properties. Normally, three instances of this class are exposed as built-in objects
jlaskey@3 44 * in Nashorn: {@code "Packages"}, {@code "java"}, and {@code "javax"}. Typical usages are:
jlaskey@3 45 * <pre>
jlaskey@3 46 * var list = new java.util.ArrayList()
jlaskey@3 47 * var sprocket = new Packages.com.acme.Sprocket()
jlaskey@3 48 * </pre>
jlaskey@3 49 * or you can store the type objects in a variable for later reuse:
jlaskey@3 50 * <pre>
jlaskey@3 51 * var ArrayList = java.util.ArrayList
jlaskey@3 52 * var list = new ArrayList
jlaskey@3 53 * </pre>
sundar@771 54 * You can also use {@link jdk.nashorn.internal.objects.NativeJava#type(Object, Object)} to access Java classes. These two statements are mostly
jlaskey@3 55 * equivalent:
jlaskey@3 56 * <pre>
jlaskey@3 57 * var listType1 = java.util.ArrayList
jlaskey@3 58 * var listType2 = Java.type("java.util.ArrayList")
jlaskey@3 59 * </pre>
jlaskey@3 60 * The difference is that {@code Java.type()} will throw an error if the class does not exist, while the first
jlaskey@3 61 * expression will return an empty object, as it must treat all non-existent classes as potentially being further
jlaskey@3 62 * subpackages. As such, {@code Java.type()} has the potential to catch typos earlier. A further difference is that
jlaskey@3 63 * {@code Java.type()} doesn't recognize {@code .} (dot) as the separator between outer class name and inner class name,
jlaskey@3 64 * it only recognizes the dollar sign. These are equivalent:
jlaskey@3 65 * <pre>
jlaskey@3 66 * var ftype1 = java.awt.geom.Arc2D$Float
jlaskey@3 67 * var ftype2 = java.awt.geom.Arc2D.Float
jlaskey@3 68 * var ftype3 = Java.asType("java.awt.geom.Arc2D$Float")
jlaskey@3 69 * var ftype4 = Java.asType("java.awt.geom.Arc2D").Float
jlaskey@3 70 * </pre>
jlaskey@3 71 */
sundar@82 72 public final class NativeJavaPackage extends ScriptObject {
attila@281 73 private static final MethodHandleFunctionality MH = MethodHandleFactory.getFunctionality();
attila@281 74 private static final MethodHandle CLASS_NOT_FOUND = findOwnMH("classNotFound", Void.TYPE, NativeJavaPackage.class);
attila@281 75 private static final MethodHandle TYPE_GUARD = Guards.getClassGuard(NativeJavaPackage.class);
attila@281 76
jlaskey@3 77 /** Full name of package (includes path.) */
jlaskey@3 78 private final String name;
jlaskey@3 79
jlaskey@3 80 /**
jlaskey@3 81 * Public constructor to be accessible from {@link jdk.nashorn.internal.objects.Global}
jlaskey@3 82 * @param name package name
jlaskey@3 83 * @param proto proto
jlaskey@3 84 */
jlaskey@3 85 public NativeJavaPackage(final String name, final ScriptObject proto) {
sundar@456 86 super(proto, null);
attila@719 87 // defense-in-path, check here for sensitive packages
attila@719 88 Context.checkPackageAccess(name);
jlaskey@3 89 this.name = name;
jlaskey@3 90 }
jlaskey@3 91
jlaskey@3 92 @Override
jlaskey@3 93 public String getClassName() {
jlaskey@3 94 return "JavaPackage";
jlaskey@3 95 }
jlaskey@3 96
jlaskey@3 97 @Override
jlaskey@3 98 public boolean equals(final Object other) {
jlaskey@3 99 if (other instanceof NativeJavaPackage) {
jlaskey@3 100 return name.equals(((NativeJavaPackage)other).name);
jlaskey@3 101 }
jlaskey@3 102 return false;
jlaskey@3 103 }
jlaskey@3 104
jlaskey@3 105 @Override
jlaskey@3 106 public int hashCode() {
jlaskey@3 107 return name == null ? 0 : name.hashCode();
jlaskey@3 108 }
jlaskey@3 109
jlaskey@3 110 /**
jlaskey@3 111 * Get the full name of the package
jlaskey@3 112 * @return the name
jlaskey@3 113 */
jlaskey@3 114 public String getName() {
jlaskey@3 115 return name;
jlaskey@3 116 }
jlaskey@3 117
jlaskey@3 118 @Override
jlaskey@3 119 public String safeToString() {
jlaskey@3 120 return toString();
jlaskey@3 121 }
jlaskey@3 122
jlaskey@3 123 @Override
jlaskey@3 124 public String toString() {
jlaskey@3 125 return "[JavaPackage " + name + "]";
jlaskey@3 126 }
jlaskey@3 127
jlaskey@3 128 @Override
jlaskey@3 129 public Object getDefaultValue(final Class<?> hint) {
jlaskey@3 130 if (hint == String.class) {
jlaskey@3 131 return toString();
jlaskey@3 132 }
jlaskey@3 133
jlaskey@3 134 return super.getDefaultValue(hint);
jlaskey@3 135 }
jlaskey@3 136
attila@281 137 @Override
attila@962 138 protected GuardedInvocation findNewMethod(final CallSiteDescriptor desc) {
attila@281 139 return createClassNotFoundInvocation(desc);
attila@281 140 }
attila@281 141
attila@281 142 @Override
attila@962 143 protected GuardedInvocation findCallMethod(final CallSiteDescriptor desc, final LinkRequest request) {
attila@281 144 return createClassNotFoundInvocation(desc);
attila@281 145 }
attila@281 146
attila@281 147 private static GuardedInvocation createClassNotFoundInvocation(final CallSiteDescriptor desc) {
attila@281 148 // If NativeJavaPackage is invoked either as a constructor or as a function, throw a ClassNotFoundException as
attila@281 149 // we can assume the user attempted to instantiate a non-existent class.
attila@281 150 final MethodType type = desc.getMethodType();
attila@281 151 return new GuardedInvocation(
attila@281 152 MH.dropArguments(CLASS_NOT_FOUND, 1, type.parameterList().subList(1, type.parameterCount())),
attila@281 153 type.parameterType(0) == NativeJavaPackage.class ? null : TYPE_GUARD);
attila@281 154 }
attila@281 155
attila@281 156 @SuppressWarnings("unused")
attila@281 157 private static void classNotFound(final NativeJavaPackage pkg) throws ClassNotFoundException {
attila@281 158 throw new ClassNotFoundException(pkg.name);
attila@281 159 }
attila@281 160
jlaskey@3 161 /**
jlaskey@3 162 * "No such property" call placeholder.
jlaskey@3 163 *
jlaskey@3 164 * This can never be called as we override {@link ScriptObject#noSuchProperty}. We do declare it here as it's a signal
jlaskey@3 165 * to {@link WithObject} that it's worth trying doing a {@code noSuchProperty} on this object.
jlaskey@3 166 *
jlaskey@3 167 * @param self self reference
jlaskey@3 168 * @param name property name
jlaskey@3 169 * @return never returns
jlaskey@3 170 */
jlaskey@3 171 @Function(attributes = Attribute.NOT_ENUMERABLE)
jlaskey@3 172 public static Object __noSuchProperty__(final Object self, final Object name) {
jlaskey@3 173 throw new AssertionError("__noSuchProperty__ placeholder called");
jlaskey@3 174 }
jlaskey@3 175
jlaskey@3 176 /**
jlaskey@3 177 * "No such method call" placeholder
jlaskey@3 178 *
jlaskey@3 179 * This can never be called as we override {@link ScriptObject#noSuchMethod}. We do declare it here as it's a signal
jlaskey@3 180 * to {@link WithObject} that it's worth trying doing a noSuchProperty on this object.
jlaskey@3 181 *
jlaskey@3 182 * @param self self reference
jlaskey@3 183 * @param args arguments to method
jlaskey@3 184 * @return never returns
jlaskey@3 185 */
jlaskey@3 186 @Function(attributes = Attribute.NOT_ENUMERABLE)
jlaskey@3 187 public static Object __noSuchMethod__(final Object self, final Object... args) {
jlaskey@3 188 throw new AssertionError("__noSuchMethod__ placeholder called");
jlaskey@3 189 }
jlaskey@3 190
jlaskey@3 191 /**
jlaskey@3 192 * Handle creation of new attribute.
jlaskey@3 193 * @param desc the call site descriptor
hannesw@51 194 * @param request the link request
jlaskey@3 195 * @return Link to be invoked at call site.
jlaskey@3 196 */
jlaskey@3 197 @Override
hannesw@51 198 public GuardedInvocation noSuchProperty(final CallSiteDescriptor desc, final LinkRequest request) {
jlaskey@3 199 final String propertyName = desc.getNameToken(2);
sundar@757 200 createProperty(propertyName);
sundar@757 201 return super.lookup(desc, request);
sundar@757 202 }
jlaskey@3 203
sundar@757 204 @Override
sundar@757 205 protected Object invokeNoSuchProperty(final String name) {
sundar@757 206 return createProperty(name);
jlaskey@3 207 }
jlaskey@3 208
jlaskey@3 209 @Override
hannesw@51 210 public GuardedInvocation noSuchMethod(final CallSiteDescriptor desc, final LinkRequest request) {
hannesw@51 211 return noSuchProperty(desc, request);
jlaskey@3 212 }
jlaskey@3 213
attila@281 214 private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
attila@281 215 return MH.findStatic(MethodHandles.lookup(), NativeJavaPackage.class, name, MH.type(rtype, types));
attila@281 216 }
sundar@757 217
sundar@757 218 private Object createProperty(final String propertyName) {
sundar@757 219 final String fullName = name.isEmpty() ? propertyName : name + "." + propertyName;
sundar@757 220 final Context context = Context.getContextTrusted();
sundar@757 221
sundar@757 222 Class<?> javaClass = null;
sundar@757 223 try {
sundar@757 224 javaClass = context.findClass(fullName);
sundar@757 225 } catch (final NoClassDefFoundError | ClassNotFoundException e) {
sundar@757 226 //ignored
sundar@757 227 }
sundar@757 228
sundar@757 229 final Object propertyValue;
sundar@757 230 if (javaClass == null) {
sundar@757 231 propertyValue = new NativeJavaPackage(fullName, getProto());
sundar@757 232 } else {
sundar@757 233 propertyValue = StaticClass.forClass(javaClass);
sundar@757 234 }
sundar@757 235
sundar@757 236 set(propertyName, propertyValue, false);
sundar@757 237 return propertyValue;
sundar@757 238 }
jlaskey@3 239 }

mercurial