Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

please support java class access, eg: java.lang.Object.class #757

Open
tangjfn opened this issue Aug 7, 2020 · 17 comments · May be fixed by #1679
Open

please support java class access, eg: java.lang.Object.class #757

tangjfn opened this issue Aug 7, 2020 · 17 comments · May be fixed by #1679
Labels
feature Issues considered a new feature good first issue Great place to start if you're looking to start an open source "resume"

Comments

@tangjfn
Copy link

tangjfn commented Aug 7, 2020

No description provided.

@tonygermano
Copy link
Contributor

This would be nice to have, but there are a few workarounds if you need it right now.

If you have an instance of the class you want, you can call getClass() on it

var objectClass = new java.lang.Object().getClass()

You can get the current Thread's context ClassLoader and load the class from there.

If you pass java.lang.Object (I believe this is an instance of NativeJavaClass) as an argument to a java method, it will get converted to a java.lang.Class. So, if you need to pass it to a java method, you can let Rhino handle it for you. That also means if you are trying to get an instance of java.lang.Class to work within a Rhino script, you can do this,

var objectClass = java.util.Collections.singletonList(java.lang.Object).get(0);

@tonygermano
Copy link
Contributor

just found another way to do it

var objectClass = org.mozilla.javascript.Context.jsToJava(java.lang.Object, java.lang.Class)

@tangjfn
Copy link
Author

tangjfn commented Aug 21, 2020

just found another way to do it

var objectClass = org.mozilla.javascript.Context.jsToJava(java.lang.Object, java.lang.Class)

thank you very mach!

@tuchida
Copy link
Contributor

tuchida commented Jan 5, 2021

js> java.lang.Object.__javaObject__;
class java.lang.Object

// Special property for getting the underlying Java class object.
static final String javaClassPropertyName = "__javaObject__";

@tonygermano
Copy link
Contributor

@tuchida thanks for pointing that out! Is there any reason why the property shouldn't just be class instead of __javaObject__? I think the only reason not to would be to avoid potential conflicts. However, I think that could only happen if there was a static field or method as part of the class definition named class, which should be prohibited since "class" is a keyword.

@tuchida
Copy link
Contributor

tuchida commented May 19, 2021

I don't know why __javaObject__.

which should be prohibited since "class" is a keyword.

The ECMAScript specification allows for the use of reserved words in property names.

var a = { class: 123 };
a.class; // 123

Also, Rhino specification allows shorthand notation for beans, so you can write .getClass() as .class.

var o = java.lang.Object();
o.class; // class java.lang.Object
o.getClass() === o.class; // true

@tonygermano
Copy link
Contributor

I meant "class" should be prohibited as a java static field or method on the underlying java class, so I think there should not be a conflict when trying to access a "class" property of the NativeJavaClass via the get method.

The NativeJavaClass represents the class itself, which is used to access static members and constructors. It doesn't have a getClass method, as only instances of Java classes do, so the shorthand does not work in this case.

@tonygermano
Copy link
Contributor

I guess another reason to believe there is no chance of conflict is that java.lang.Object.class is exactly how you would accomplish obtaining an instance of java.lang.Class that refers to java.lang.Object in Java.

@tuchida
Copy link
Contributor

tuchida commented May 19, 2021

I see.
I think it was only in ES5 that it was specified that reserved words could be used in property names, so there must be some historical background.

@tuchida
Copy link
Contributor

tuchida commented May 19, 2021

It seems that even now, depending on your settings, you cannot use reserved words as identifiers.

if (result != Token.RESERVED) {
return result;
} else if (parser.compilerEnv.getLanguageVersion() >= Context.VERSION_ES6) {
return result;
} else if (!parser.compilerEnv.isReservedKeywordAsIdentifier()) {
return result;
}

@tonygermano
Copy link
Contributor

I don't think properties are identifiers, so that shouldn't be a problem.

@p-bakker
Copy link
Collaborator

This works in Rhino, at least when using Context.VERSION_ES6 as language level: new java.lang.String().class.getField("CASE_INSENSITIVE_ORDER")

Can this issue be closed?

@p-bakker p-bakker reopened this Jun 25, 2021
@tonygermano
Copy link
Contributor

@p-bakker I think this is still an issue to be addressed. It's already been pointed out above that it works on an instance of a class (because it ends up calling the .getClass() method on the object.) The goal here is to get an instance of java.lang.Class without first needing to instantiate an object of the target class.

I don't see any reason to not add another property to NativeJavaObject called class that functions in exactly the same way as the __javaObject__ property. I'd just as soon change it if not for that whole backwards compatibility thing. This would make it work in the same way as a java class literal, which is the logical way to access it.

@p-bakker
Copy link
Collaborator

p-bakker commented Jun 26, 2021

Ahh, missed that detail

Well, as all classes extend Object, Object defines a getClass() method and static methods cannot mirror instance methods and because 'class' in Java is a reserved word, so it cannot be used as the name of a (static) field, I personally don't see a (backwards or forward) compatibility issue with adding a 'class' property to NativeJavaObject that mimics the 'class' property of types in Java.

More self-explanatory than the obscure (and I think undocumented) '__javaObject__'.

Only question is from which Context.VERSION_Xxxx onwards we should, as using 'class' as a propertyName want always allowed I think

@p-bakker
Copy link
Collaborator

Mmm, I guess there is sort of an odd scenario: if there is a class out there that is used icw Rhino and accessing that class as a NativeJavaObject and a class defines a static void setClass(Class cls);.

Likelyhood of that happening? Very slim if you'd ask me.

We could support that scenario by in that case making the NativeJavaObject's class property a writable property (should be a non-writable property in all other cases I think)

@p-bakker p-bakker added good first issue Great place to start if you're looking to start an open source "resume" feature Issues considered a new feature labels Jun 29, 2021
@rPraml
Copy link
Contributor

rPraml commented Oct 7, 2024

Only question is from which Context.VERSION_Xxxx onwards we should, as using 'class' as a propertyName want always allowed I think

Other question: ES6 is from 2015. We are in 2024 now. Are there still use cases, where you use rhino not in ES6 mode?
Could we consider removing all previous script versions with e.g. Rhino 2.0? Then we wouldn't have this problem. Alternatively, we could force at least ES6 as a requirement for LiveConnect.

@andreabergia
Copy link
Contributor

For us at ServiceNow, keeping old versions around and executing code in the same way is a fundamental requirement.
Changing defaults is good, but (unfortunately) we need to maintain very strong backward compatibility.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Issues considered a new feature good first issue Great place to start if you're looking to start an open source "resume"
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants