NativeJavaImporter.java revision 1551:f3b883bec2d0
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.dynalink.CallSiteDescriptor;
32import jdk.dynalink.beans.StaticClass;
33import jdk.dynalink.linker.GuardedInvocation;
34import jdk.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;
46import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
47
48/**
49 * This is "JavaImporter" constructor. This constructor allows you to use Java types omitting explicit package names.
50 * Objects of this constructor are used along with {@code "with"} statements and as such are not usable in ECMAScript
51 * strict mode. Example:
52 * <pre>
53 *     var imports = new JavaImporter(java.util, java.io);
54 *     with (imports) {
55 *         var m = new HashMap(); // java.util.HashMap
56 *         var f = new File("."); // java.io.File
57 *         ...
58 *     }
59 * </pre>
60 * Note however that the preferred way for accessing Java types in Nashorn is through the use of
61 * {@link NativeJava#type(Object, Object) Java.type()} method.
62 */
63@ScriptClass("JavaImporter")
64public final class NativeJavaImporter extends ScriptObject {
65    private final Object[] args;
66
67    // initialized by nasgen
68    private static PropertyMap $nasgenmap$;
69
70    private NativeJavaImporter(final Object[] args, final ScriptObject proto, final PropertyMap map) {
71        super(proto, map);
72        this.args = args;
73    }
74
75    private NativeJavaImporter(final Object[] args, final Global global) {
76        this(args, global.getJavaImporterPrototype(), $nasgenmap$);
77    }
78
79    private NativeJavaImporter(final Object[] args) {
80        this(args, Global.instance());
81    }
82
83    @Override
84    public String getClassName() {
85        return "JavaImporter";
86    }
87
88    /**
89     * Constructor
90     * @param isNew is the new operator used for instantiating this NativeJavaImporter
91     * @param self self reference
92     * @param args arguments
93     * @return NativeJavaImporter instance
94     */
95    @Constructor(arity = 1)
96    public static NativeJavaImporter constructor(final boolean isNew, final Object self, final Object... args) {
97        return new NativeJavaImporter(args);
98    }
99
100    /**
101     * "No such property" handler.
102     *
103     * @param self self reference
104     * @param name property name
105     * @return value of the missing property
106     */
107    @Function(attributes = Attribute.NOT_ENUMERABLE)
108    public static Object __noSuchProperty__(final Object self, final Object name) {
109        if (! (self instanceof NativeJavaImporter)) {
110            throw typeError("not.a.java.importer", ScriptRuntime.safeToString(self));
111        }
112        return ((NativeJavaImporter)self).createProperty(JSType.toString(name));
113    }
114
115    /**
116     * "No such method call" handler
117     *
118     * @param self self reference
119     * @param args arguments to method
120     * @return never returns always throw TypeError
121     */
122    @Function(attributes = Attribute.NOT_ENUMERABLE)
123    public static Object __noSuchMethod__(final Object self, final Object... args) {
124       throw typeError("not.a.function", ScriptRuntime.safeToString(args[0]));
125    }
126
127    @Override
128    public GuardedInvocation noSuchProperty(final CallSiteDescriptor desc, final LinkRequest request) {
129        return createAndSetProperty(desc) ? super.lookup(desc, request) : super.noSuchProperty(desc, request);
130    }
131
132    @Override
133    public GuardedInvocation noSuchMethod(final CallSiteDescriptor desc, final LinkRequest request) {
134        return createAndSetProperty(desc) ? super.lookup(desc, request) : super.noSuchMethod(desc, request);
135    }
136
137    @Override
138    protected Object invokeNoSuchProperty(final Object key, final boolean isScope, final int programPoint) {
139        if (!(key instanceof String)) {
140            return super.invokeNoSuchProperty(key, isScope, programPoint);
141        }
142        final Object retval = createProperty((String) key);
143        if (isValid(programPoint)) {
144            throw new UnwarrantedOptimismException(retval, programPoint);
145        }
146        return retval;
147    }
148
149    private boolean createAndSetProperty(final CallSiteDescriptor desc) {
150        final String name = NashornCallSiteDescriptor.getOperand(desc);
151        final Object value = createProperty(name);
152        if(value != null) {
153            set(name, value, 0);
154            return true;
155        }
156        return false;
157    }
158
159    private Object createProperty(final String name) {
160        final int len = args.length;
161
162        for (int i = len - 1; i > -1; i--) {
163            final Object obj = args[i];
164
165            if (obj instanceof StaticClass) {
166                if (((StaticClass)obj).getRepresentedClass().getSimpleName().equals(name)) {
167                    return obj;
168                }
169            } else if (obj instanceof NativeJavaPackage) {
170                final String pkgName  = ((NativeJavaPackage)obj).getName();
171                final String fullName = pkgName.isEmpty() ? name : (pkgName + "." + name);
172                final Context context = Global.instance().getContext();
173                try {
174                    return StaticClass.forClass(context.findClass(fullName));
175                } catch (final ClassNotFoundException e) {
176                    // IGNORE
177                }
178            }
179        }
180        return null;
181    }
182}
183