BoxLang: Our new JVM Dynamic Language made by Ortus! Check it out: https://www.boxlang.io

Import nested classes

Description

Importing classes from a package works but importing an inner class does not.

This code works

import java.net.http.HttpRequest;

This code errors

import java.net.http.HttpRequest.BodyPublishers;


It produces the following error

ortus.boxlang.runtime.types.exceptions.ClassNotFoundBoxLangException: The requested class [BodyPublishers] has not been located in any class resolver. at ortus.boxlang.runtime.loader.ClassLocator.resolveFromSystem(ClassLocator.java:602) at ortus.boxlang.runtime.loader.ClassLocator.load(ClassLocator.java:350) at boxgenerated.scripts.Script_928bd8458d65347179fdf98c152aaf3e._invoke(Script_928bd8458d65347179fdf98c152aaf3e.java:84) at ortus.boxlang.runtime.runnables.BoxScript.invoke(BoxScript.java:77) at ortus.boxlang.runtime.BoxRuntime.executeSource(BoxRuntime.java:1396) at ortus.boxlang.runtime.BoxRuntime.executeSource(BoxRuntime.java:1366) at ortus.boxlang.runtime.interop.DynamicInteropServiceTest.testFunc(DynamicInteropServiceTest.java:852) at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)

Activity

Show:

Brad Wood October 7, 2024 at 9:57 PM

This passes now

@Test public void testJavaNestedClassImport() { instance.executeSource( """ import java.net.http.HttpRequest$BodyPublishers; result = BodyPublishers.noBody(); """, context ); assertThat( variables.get( result ) ).isNotNull(); assertThat( BodyPublisher.class.isAssignableFrom( variables.get( result ).getClass() ) ).isTrue(); }

Brad Wood October 7, 2024 at 9:42 PM

You have to use the full parent and child class to reference the import: HttpRequest$BodyPublishers

I don’t think that’s actually correct. We’re defaulting the import name if there is no alias to the last item in the dot path:

// If there is no alias, use the last part of the class name as the alias String[] parts = className.split( "\\." ); alias = parts[ parts.length - 1 ];

but if there is a dollar sign, we should prolly be taking the bit after it. Unfortunately, it sort of is annoying that Java does technically allow dollar signs in class names but also uses a convention of a dollar sign to represent nested classes in class loaders. That means that it’s possible to have something like

import foo.com.Bar$Baz$Bum$Qux;

and it’s not really clear if there is a nested class at all, or how many of them. The resolution of the dollar sign is done automatically by Java’s ClassLoader as it’s a JVM bytecode specification, so we don’t really have any control over it. I think the best approach is to assume that if there is at least one dollar sign in the name, take the last segment after the last dollar sign and assume it represented an inner class. ChatGPT claims that while dollar signs are possible, they are discouraged for this reason.

I’ll make this change to the default alias name. in the meantime, you can use an explicit alias so your code doesn't break in the next release.

import java.net.http.HttpRequest$BodyPublishers as BodyPublishers;

Jacob Beers October 7, 2024 at 7:15 PM

Using the “$” worked.

import java.net.http.HttpRequest$BodyPublishers;

You have to use the full parent and child class to reference the import: HttpRequest$BodyPublishers

Brad Wood October 7, 2024 at 6:37 PM

I would expect the correct syntax to be

import path.to.OuterClass$InnerClass;

just like we use with createObjecft( 'java', 'path.to.OuterClass$InnerClass' )

Please test, and if that works, we may just need to ensure the docs are updated. Note, our import syntax isn’t necessarily an exact duplicate of Java’s.

Fixed
Pinned fields
Click on the next to a field label to start pinning.

Details

Assignee

Reporter

Fix versions

Priority

Sentry

Created October 5, 2024 at 3:58 AM
Updated October 7, 2024 at 9:58 PM
Resolved October 7, 2024 at 9:58 PM

Flag notifications