Exporting a package with no Java sources

classic Classic list List threaded Threaded
12 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Exporting a package with no Java sources

Alexander Udalov
I'm trying to figure out how to compile a mixed-language (in this
case, Java + Kotlin) JVM module and having a problem in case the
module tries to export a package without any .java sources in it. The
javac error I get is:

src/module-info.java:2: error: package is empty or does not exist: foo
    exports foo;
            ^

Now, through experiments, I found out that it's actually possible to
workaround this error by
1) always compiling non-.java sources first, and
2) compiling .java sources to the same directory where non-.java
sources are compiled to on step 1.

However, with Gradle deprecating single-output directory builds for
projects using multiple JVM languages [1], this workaround is not
always going to be possible.
Is there some other way to suggest to javac that .class files in a
particular location on the disk are a part of the same module, so that
it would be possible to export the package?
If there isn't, would it make sense to relax the severity of this
compiler message to a warning?

Thank you in advance!

Alexander

[1] https://docs.gradle.org/4.0/release-notes.html#multiple-class-directories-for-a-single-source-set
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Exporting a package with no Java sources

Peter Levart
Hi Alexander,

Have you tried to put a package-info.java into the exported package? It
might work.

Regards, Peter

On Jun 30, 2017 6:42 PM, "Alexander Udalov" <[hidden email]>
wrote:

> I'm trying to figure out how to compile a mixed-language (in this
> case, Java + Kotlin) JVM module and having a problem in case the
> module tries to export a package without any .java sources in it. The
> javac error I get is:
>
> src/module-info.java:2: error: package is empty or does not exist: foo
>     exports foo;
>             ^
>
> Now, through experiments, I found out that it's actually possible to
> workaround this error by
> 1) always compiling non-.java sources first, and
> 2) compiling .java sources to the same directory where non-.java
> sources are compiled to on step 1.
>
> However, with Gradle deprecating single-output directory builds for
> projects using multiple JVM languages [1], this workaround is not
> always going to be possible.
> Is there some other way to suggest to javac that .class files in a
> particular location on the disk are a part of the same module, so that
> it would be possible to export the package?
> If there isn't, would it make sense to relax the severity of this
> compiler message to a warning?
>
> Thank you in advance!
>
> Alexander
>
> [1] https://docs.gradle.org/4.0/release-notes.html#multiple-
> class-directories-for-a-single-source-set
>
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Exporting a package with no Java sources

Alan Bateman
On 01/07/2017 10:09, Peter Levart wrote:
> Hi Alexander,
>
> Have you tried to put a package-info.java into the exported package? It
> might work.
>
I don't think so, but a dummy class/interface will do (it doesn't have
to be public). There is a lengthy discussion on this topic in JIRA from
2016 that would be useful to link to (but I can't find it just now
because JIRA is down for maintenance).

-Alan
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Exporting a package with no Java sources

Jonathan Gibbons
Right now, javac only looks in one location (i.e. directory + its
subdirectories) for the compiled classes for a module.

It is too late to change this for JDK 9, and even if we could, I think
we are already pushing the limits of what can be specified on the
command line to configure the different paths for all the modules
involved in the compilation.

Converting the error to a warning (as was suggested in the original post
in this thread) would not address the case where the Java source code
needs to refer to types declared in class files generated from non-Java
sources.

-- Jon


On 7/1/17 3:08 AM, Alan Bateman wrote:

> On 01/07/2017 10:09, Peter Levart wrote:
>> Hi Alexander,
>>
>> Have you tried to put a package-info.java into the exported package? It
>> might work.
>>
> I don't think so, but a dummy class/interface will do (it doesn't have
> to be public). There is a lengthy discussion on this topic in JIRA
> from 2016 that would be useful to link to (but I can't find it just
> now because JIRA is down for maintenance).
>
> -Alan

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Exporting a package with no Java sources

Alexander Udalov
In reply to this post by Alan Bateman
 Hi Jonathan,

> Converting the error to a warning (as was suggested in the original post
> in this thread) would not address the case where the Java source code
> needs to refer to types declared in class files generated from non-Java
> sources.

You're right. For some reason, I was thinking of passing the non-Java
compiled classes directory on the _classpath_ to javac, assuming that
would make the classes there accessible to the Java source code.
However, this is not a solution because of course, we're compiling a
named module which does not read an unnamed module which would contain
everything on the classpath.

So it seems that the only way to reliably compile a mixed language
module would be to compile everything to the same destination
directory. But Gradle's decision to separate outputs for different
languages, which I mentioned in the first post and which looks pretty
logical to me, sort of directly contradicts with this conclusion.
Developers of Gradle plugins for other JVM languages would then, I
suppose, be required to use hacks like forcing the Java plugin to
compile into the same destination directory and then moving out all
the newly created files to the correct directory afterwards, right?

> It is too late to change this for JDK 9, and even if we could, I think
> we are already pushing the limits of what can be specified on the
> command line to configure the different paths for all the modules
> involved in the compilation.

Sure, I understand this is a wrong point in time to propose changes
into JDK 9. I'm rather trying to figure out if the situation I
described here is considered normal by the Jigsaw team and there could
be a sane workaround by us (JVM language engineers), or is considered
a problem that should be fixed in the JDK itself, probably in a future
update.

Thanks!

Alexander
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Exporting a package with no Java sources

Alexander Udalov
In reply to this post by Alan Bateman
Hi Alan,

> I don't think so, but a dummy class/interface will do (it doesn't have to be
> public). There is a lengthy discussion on this topic in JIRA from 2016 that
> would be useful to link to (but I can't find it just now because JIRA is
> down for maintenance).

Thanks, a dummy class certainly workarounds the problem of javac
reporting a compilation error here. However, I hope there's a better
way because it'd be a bit strange to force users to create a dummy
Java class in every exported package in pure X modules (replace X with
any JVM language that is not Java).

Moreover, as pointed by Jonathan in his answer, I failed to recognize
a larger problem initially, that it wouldn't be possible to refer to
non-Java classes from Java sources anyway. So what I'm really looking
for instead, is the way to "augment" the module currently compiled by
javac with a directory containing class files, emitted by another
compiler.

Still, this workaround could prove helpful for example if there are
not many exported packages in a module (which I assume would be true
for many modules out there), and there are no Java sources in that
module.

Thanks!

Alexander
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Exporting a package with no Java sources

Alan Bateman
On 03/07/2017 12:57, Alexander Udalov wrote:

> :
> Thanks, a dummy class certainly workarounds the problem of javac
> reporting a compilation error here. However, I hope there's a better
> way because it'd be a bit strange to force users to create a dummy
> Java class in every exported package in pure X modules (replace X with
> any JVM language that is not Java).
>
> Moreover, as pointed by Jonathan in his answer, I failed to recognize
> a larger problem initially, that it wouldn't be possible to refer to
> non-Java classes from Java sources anyway. So what I'm really looking
> for instead, is the way to "augment" the module currently compiled by
> javac with a directory containing class files, emitted by another
> compiler.
>
> Still, this workaround could prove helpful for example if there are
> not many exported packages in a module (which I assume would be true
> for many modules out there), and there are no Java sources in that
> module.
>
In the module, does the non-Java source code reference the Java code or
is it the other way around? It would be useful for thread to understand
the order that they need to be compiled. As you use the term "augment"
then I'm guessing that the Java code is compiled first, without
reference to the non-Java code.

Maybe a side point for now but I assume the Kotlin compiler doesn't
understand modules yet and so will compile the source "as if" it's in
the unnamed module. This could mean the resulting module is DOA if it
references types in modules that it won't read when the module is resolved.

-Alan
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Exporting a package with no Java sources

Alexander Udalov
> In the module, does the non-Java source code reference the Java code or is
> it the other way around? It would be useful for thread to understand the
> order that they need to be compiled. As you use the term "augment" then I'm
> guessing that the Java code is compiled first, without reference to the
> non-Java code.

Let's assume that there are both references from Java to non-Java and
from non-Java to Java. The compilation order is therefore fixed: first
non-Java sources are compiled, then Java sources are compiled. The
non-Java compiler is able to read both Java and non-Java sources, and
creates .class files for the latter. The Java compiler, on the other
hand, cannot read non-Java source files, so it reads the class files
compiled by the non-Java compiler on the first step. This is how build
tool plugins work today for Kotlin. Also, this is how it _would_ work
with Java 9 without any issues, if the destination directory was
guaranteed to be the same. But in circumstances where the destination
directory could be different for class files compiled by Java and
non-Java, I see no way to make the Java compiler read the class files
compiled by the non-Java compiler. If they're passed on the classpath
(as they are currently on Java 8 and earlier), the classes there are
not accessible in Java because the named module cannot read the
unnamed module. If they're passed on the module path, they would be
loaded in another module, which is incorrect because semantically it's
the same module. The original problem of exporting a package I
highlighted in the first post is thus only a consequence to this
inability to add compiled class files to the currently compiled
module.

> Maybe a side point for now but I assume the Kotlin compiler doesn't
> understand modules yet and so will compile the source "as if" it's in the
> unnamed module. This could mean the resulting module is DOA if it references
> types in modules that it won't read when the module is resolved.

We're working on this currently and this is going to be fixed by the
Kotlin compiler being able to read the module-info.java file of the
module being compiled, and determining which references are valid and
which are not.

Alexander
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Exporting a package with no Java sources

Sander Mak

On 3 Jul 2017, at 15:23, Alexander Udalov <[hidden email]<mailto:[hidden email]>> wrote:

 But in circumstances where the destination
directory could be different for class files compiled by Java and
non-Java, I see no way to make the Java compiler read the class files
compiled by the non-Java compiler. If they're passed on the classpath
(as they are currently on Java 8 and earlier), the classes there are
not accessible in Java because the named module cannot read the
unnamed module. If they're passed on the module path, they would be
loaded in another module, which is incorrect because semantically it's
the same module.

Have you tried using `--patch-module` during compilation of the Java sources (as described in http://openjdk.java.net/jeps/261)? Not sure if it works with class files in the patch directory as well, but it sounds like it could address your usecase.


Sander
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Exporting a package with no Java sources

Jonathan Gibbons


On 7/3/17 6:36 AM, Sander Mak wrote:

> On 3 Jul 2017, at 15:23, Alexander Udalov <[hidden email]<mailto:[hidden email]>> wrote:
>
>   But in circumstances where the destination
> directory could be different for class files compiled by Java and
> non-Java, I see no way to make the Java compiler read the class files
> compiled by the non-Java compiler. If they're passed on the classpath
> (as they are currently on Java 8 and earlier), the classes there are
> not accessible in Java because the named module cannot read the
> unnamed module. If they're passed on the module path, they would be
> loaded in another module, which is incorrect because semantically it's
> the same module.
>
> Have you tried using `--patch-module` during compilation of the Java sources (as described in http://openjdk.java.net/jeps/261)? Not sure if it works with class files in the patch directory as well, but it sounds like it could address your usecase.
>
>
> Sander

Yes, --patch-module should be able to help.

-- Jon
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Exporting a package with no Java sources

Alexander Udalov
In reply to this post by Alan Bateman
Hi Sander,

> Have you tried using `--patch-module` during compilation of the Java sources (as described in http://openjdk.java.net/jeps/261)? Not sure if it works with class files in the patch directory as well, but it sounds like it could address your usecase.

This fixes my problem completely (apart from the minor fact that
--patch-module's "use in production settings is strongly discouraged",
according to the JEP). I've confirmed with the Gradle team that this
approach would be fine to compile a mixed-language module.

Thank you!

On Mon, Jul 3, 2017 at 3:14 PM, Alan Bateman <[hidden email]> wrote:

> On 03/07/2017 12:57, Alexander Udalov wrote:
>>
>> :
>> Thanks, a dummy class certainly workarounds the problem of javac
>> reporting a compilation error here. However, I hope there's a better
>> way because it'd be a bit strange to force users to create a dummy
>> Java class in every exported package in pure X modules (replace X with
>> any JVM language that is not Java).
>>
>> Moreover, as pointed by Jonathan in his answer, I failed to recognize
>> a larger problem initially, that it wouldn't be possible to refer to
>> non-Java classes from Java sources anyway. So what I'm really looking
>> for instead, is the way to "augment" the module currently compiled by
>> javac with a directory containing class files, emitted by another
>> compiler.
>>
>> Still, this workaround could prove helpful for example if there are
>> not many exported packages in a module (which I assume would be true
>> for many modules out there), and there are no Java sources in that
>> module.
>>
> In the module, does the non-Java source code reference the Java code or is
> it the other way around? It would be useful for thread to understand the
> order that they need to be compiled. As you use the term "augment" then I'm
> guessing that the Java code is compiled first, without reference to the
> non-Java code.
>
> Maybe a side point for now but I assume the Kotlin compiler doesn't
> understand modules yet and so will compile the source "as if" it's in the
> unnamed module. This could mean the resulting module is DOA if it references
> types in modules that it won't read when the module is resolved.
>
> -Alan
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Exporting a package with no Java sources

Jonathan Gibbons


On 7/3/17 9:11 AM, Alexander Udalov wrote:
> Hi Sander,
>
>> Have you tried using `--patch-module` during compilation of the Java sources (as described in http://openjdk.java.net/jeps/261)? Not sure if it works with class files in the patch directory as well, but it sounds like it could address your usecase.
> This fixes my problem completely (apart from the minor fact that
> --patch-module's "use in production settings is strongly discouraged",
> according to the JEP). I've confirmed with the Gradle team that this
> approach would be fine to compile a mixed-language module.
>
> Thank you!
I think that exhortation applies more to use at runtime. If you're using
it at compile/build time to create a well-formed module that does not
itself need the use of --patch-module, that seems less of an issue.


>
> On Mon, Jul 3, 2017 at 3:14 PM, Alan Bateman <[hidden email]> wrote:
>> On 03/07/2017 12:57, Alexander Udalov wrote:
>>> :
>>> Thanks, a dummy class certainly workarounds the problem of javac
>>> reporting a compilation error here. However, I hope there's a better
>>> way because it'd be a bit strange to force users to create a dummy
>>> Java class in every exported package in pure X modules (replace X with
>>> any JVM language that is not Java).
>>>
>>> Moreover, as pointed by Jonathan in his answer, I failed to recognize
>>> a larger problem initially, that it wouldn't be possible to refer to
>>> non-Java classes from Java sources anyway. So what I'm really looking
>>> for instead, is the way to "augment" the module currently compiled by
>>> javac with a directory containing class files, emitted by another
>>> compiler.
>>>
>>> Still, this workaround could prove helpful for example if there are
>>> not many exported packages in a module (which I assume would be true
>>> for many modules out there), and there are no Java sources in that
>>> module.
>>>
>> In the module, does the non-Java source code reference the Java code or is
>> it the other way around? It would be useful for thread to understand the
>> order that they need to be compiled. As you use the term "augment" then I'm
>> guessing that the Java code is compiled first, without reference to the
>> non-Java code.
>>
>> Maybe a side point for now but I assume the Kotlin compiler doesn't
>> understand modules yet and so will compile the source "as if" it's in the
>> unnamed module. This could mean the resulting module is DOA if it references
>> types in modules that it won't read when the module is resolved.
>>
>> -Alan

Loading...