NativeJavaImporter.java revision 1428:c209abbe9b24
1/*
2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package jdk.nashorn.internal.objects;
27
28import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
29import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
30
31import jdk.internal.dynalink.CallSiteDescriptor;
32import jdk.internal.dynalink.beans.StaticClass;
33import jdk.internal.dynalink.linker.GuardedInvocation;
34import jdk.internal.dynalink.linker.LinkRequest;
35import jdk.nashorn.internal.objects.annotations.Attribute;
36import jdk.nashorn.internal.objects.annotations.Constructor;
37import jdk.nashorn.internal.objects.annotations.Function;
38import jdk.nashorn.internal.objects.annotations.ScriptClass;
39import jdk.nashorn.internal.runtime.Context;
40import jdk.nashorn.internal.runtime.JSType;
41import jdk.nashorn.internal.runtime.NativeJavaPackage;
42import jdk.nashorn.internal.runtime.PropertyMap;
43import jdk.nashorn.internal.runtime.ScriptObject;
44import jdk.nashorn.internal.runtime.ScriptRuntime;
45import jdk.nashorn.internal.runtime.UnwarrantedOptimismException;
46
47/**
48 * This is "JavaImporter" constructor. This constructor allows you to use Java types omitting explicit package names.
49 * Objects of this constructor are used along with {@code "with"} statements and as such are not usable in ECMAScript
50 * strict mode. Example:
51 * <pre>
52 *     var imports = new JavaImporter(java.util, java.io);
53 *     with (imports) {
54 *         var m = new HashMap(); // java.util.HashMap
55 *         var f = new File("."); // java.io.File
56 *         ...
57 *     }
58 * </pre>
59 * Note however that the preferred way for accessing Java types in Nashorn is through the use of
60 * {@link NativeJava#type(Object, Object) Java.type()} method.
61 */
62@ScriptClass("JavaImporter")
63public final class NativeJavaImporter extends ScriptObject {
64    private final Object[] args;
65
66    // initialized by nasgen
67    private static PropertyMap $nasgenmap$;
68
69    private NativeJavaImporter(final Object[] args, final ScriptObject proto, final PropertyMap map) {
70        super(proto, map);
71        this.args = args;
72    }
73
74    private NativeJavaImporter(final Object[] args, final Global global) {
75        this(args, global.getJavaImporterPrototype(), $nasgenmap$);
76    }
77
78    private NativeJavaImporter(final Object[] args) {
79        this(args, Global.instance());
80    }
81
82    @Override
83    public String getClassName() {
84        return "JavaImporter";
85    }
86
87    /**
88     * Constructor
89     * @param isNew is the new operator used for instantiating this NativeJavaImporter
90     * @param self self reference
91     * @param args arguments
92     * @return NativeJavaImporter instance
93     */
94    @Constructor(arity = 1)
95    public static NativeJavaImporter constructor(final boolean isNew, final Object self, final Object... args) {
96        return new NativeJavaImporter(args);
97    }
98
99    /**
100     * "No such property" handler.
101     *
102     * @param self self reference
103     * @param name property name
104     * @return value of the missing property
105     */
106    @Function(attributes = Attribute.NOT_ENUMERABLE)
107    public static Object __noSuchProperty__(final Object self, final Object name) {
108        if (! (self instanceof NativeJavaImporter)) {
109            throw typeError("not.a.java.importer", ScriptRuntime.safeToString(self));
110        }
111        return ((NativeJavaImporter)self).createProperty(JSType.toString(name));
112    }
113
114    /**
115     * "No such method call" handler
116     *
117     * @param self self reference
118     * @param args arguments to method
119     * @return never returns always throw TypeError
120     */
121    @Function(attributes = Attribute.NOT_ENUMERABLE)
122    public static Object __noSuchMethod__(final Object self, final Object... args) {
123       throw typeError("not.a.function", ScriptRuntime.safeToString(args[0]));
124    }
125
126    @Override
127    public GuardedInvocation noSuchProperty(final CallSiteDescriptor desc, final LinkRequest request) {
128        return createAndSetProperty(desc) ? super.lookup(desc, request) : super.noSuchProperty(desc, request);
129    }
130
131    @Override
132    public GuardedInvocation noSuchMethod(final CallSiteDescriptor desc, final LinkRequest request) {
133        return createAndSetProperty(desc) ? super.lookup(desc, request) : super.noSuchMethod(desc, request);
134    }
135
136    @Override
137    protected Object invokeNoSuchProperty(final String name, final boolean isScope, final int programPoint) {
138        final Object retval = createProperty(name);
139        if (isValid(programPoint)) {
140            throw new UnwarrantedOptimismException(retval, programPoint);
141        }
142        return retval;
143    }
144
145    private boolean createAndSetProperty(final CallSiteDescriptor desc) {
146        final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
147        final Object value = createProperty(name);
148        if(value != null) {
149            set(name, value, 0);
150            return true;
151        }
152        return false;
153    }
154
155    private Object createProperty(final String name) {
156        final int len = args.length;
157
158        for (int i = len - 1; i > -1; i--) {
159            final Object obj = args[i];
160
161            if (obj instanceof StaticClass) {
162                if (((StaticClass)obj).getRepresentedClass().getSimpleName().equals(name)) {
163                    return obj;
164                }
165            } else if (obj instanceof NativeJavaPackage) {
166                final String pkgName  = ((NativeJavaPackage)obj).getName();
167                final String fullName = pkgName.isEmpty() ? name : (pkgName + "." + name);
168                final Context context = Global.instance().getContext();
169                try {
170                    return StaticClass.forClass(context.findClass(fullName));
171                } catch (final ClassNotFoundException e) {
172                    // IGNORE
173                }
174            }
175        }
176        return null;
177    }
178}
179