Scala project as "sub-project" of Java project in eclipse - java

I'm writing a Scala "plugin" to a Java project. (Essentially I'm writing a Scala class that is a subclass of a Java class. It is intended to run in the Java application.) I can create both the Java project and the Scala project in the Scala/eclipse IDE, and I can tell one of them to refer to the other. But when I try to tell each to refer to the other I get an error message saying that I have a cycle in my build path. When I leave out the reference from the Java project to the Scala project (but include the reference from the Scala project to the Java project) I'm able to write the subclass and refer to the required Java classes. But now the Java application can't see the Scala subclass. Is there a good way to accomplish something like this?
Thanks.

It is impossible in general to create cyclic references between projects. And it is quite natural. Suppose you have projects 'A' and 'B' which are interdependent. This means that in order to compile 'B' you should have 'A' already compiled. But to compile 'A' you need 'B' to be compiled. How do you break such loop?
That said, in some particular cases it may be possible. For example, if there are no dependency cycles between classes in these projects, i.e. there are no dependency loops like com.a.X -> com.b.Y -> com.b.Z -> com.a.X, then it may be possible to compile both projects in chunks until both of them are fully compiled. But this would require sophisticated algorithms and dependency tracking system which is just not worth it.
Plugin-based systems usually are structured in the following way. Main project is separated in two: actual program and its plugin API (actual program depends on this API). Then there are plugins which depend on the API but not on the main program. The main program now can have dependencies on plugins, because there are no loops now.
+------------------------+
| |
+-> Plugin 1 --+ Project
| | |
+-> Plugin 2 --+--+ V
| | +--> API
+-> Plugin 3 --+
Even better is to link the program with plugins at runtime. Then there are no compile-time dependencies of Project on plugins at all. Runtime system (e.g. OSGi or JBoss Modules or something custom) becomes responsible for finding and loading plugins at runtime. This approach will require some changes in the build system and in the way you launch your project, but it may be worth it. This depends on your actual requirements, of course.

This StackOverflow question seems to solve my problem. Its solution is to "Add Scala Nature" to the Java project: right click the project and select Configure > Add Scala Nature. After doing that it's possible to include Scala files within a Java project! That's it.

Related

What is the idiomatic way to compile a subset of the packages of a project?

We are replacing our home grown java build setup with gradle. It is a multi-project setup, and ne of the sub projects has a package structure like this:
com.whatever.ourproduct.api
com.whatever.ourproduct.base
com.whatever.ourproduct.foo
com.whatever.ourproduct.bar....
The "primary" requirement is simply to compile all packages together. But now we are told that com.whatever.ourproduct.api also needs to be compiled (with different javac options) to a different output location.
Now I am wondering whether there is a canonical/idiomatic way to achieve this. Should there be a separate project just for that one package?

How to setup a project with multiple levels of modules for local development

I have multiple app projects of of roughly this layout:
example app (Java)
Java Wrapper with additional functionality
C++ + Shallow Java Wrapper
2nd example app (flutter)
flutter wrapper
Java Wrapper with additional functionality
C++ + Shallow Java Wrapper
3rd example app
flutter wrapper
Java Wrapper with additional functionality
C++ + Shallow Java Wrapper
All apps share the same main dependency (java Wrapper with additional functionality) and its dependency tree. Now I am developing on each app all the way down to C++ code. They are managed as git submodules in their respective parent project.
As there is a high change rate along the whole process, I want the final example to be built for testing from all sources.
I tried several approaches for tying this together into one gradle build:
1. Preferred (but failing) solution: settings.gradle in each project, each project only includes direct dependencies
Now I want this full tree to be managed in one flutter build. So I add the direct dependencies in each projects settings.gradle, just to learn that gradle only supports one toplevel settings.gradle. So this does not work. The presented solutions in aforementioned question mostly try to emulate support for multiple settings.gradle files.
2. Functioning but Ugly: Add all dependency projects are included in the toplevel settings.gradle
Do I really have to include all subprojects manually in the toplevel settings.gradle, when each of the subprojects knows its dependencies perfectly fine? Furthermore, since there are multiple projects depending on this, do I have to do this manually for each of them?
(And don't even get me startet about gradle not telling me, I have a wrong projectDir because I got a typo in the 100rth level of recursive descend!)
3. Probably Working Solution: Use composite builds
This will trigger the builds but now I have to resolve the build artifacts instead of the projects. So same problem with other artifacts.
4. Probably Working solution: Publish dependency projects to a maven (or other) repository and pull that into the app
I did not try this because I find the idea abhorent: I want to test one small change in the C++ code and now have to push that to a repository and potentially do the same on every project above?
This works for a stable project but not for flexible exploratory development. Sure, I want to publish something at the end but I don't want to publish every little step in between.
This left me wondering: Am I doing something unusual? I mean: is there nobody who has the same requirements that gradle does not seem able to fit:
live updates from all the way down to quick test local changes
no repeating of transitive dependencies on the toplevel
What is the common practice in this case?
After Lukas Körfer's comment I took a closer look at composite builds again and noticed that I had a misconception about them. I did not understand that their dependency resolution will solve the finding of the build artifacts for me.
Now I use the composite builds to tie together the whole build while using
implementation 'my.group:project'
to import the code of the subprojects and
includeBuild '../path/to/subproject/'
to pull them in.

Maven compile multi-module project with cyclic dependencies

I am working on my little OSS project in which I am using Maven as build tool. I split the project into smaller sub-projects to simplify development. Thus I have following structure:
project
+-- main-module
| |
| +- pom.xml
|
+-- submodule1
| |
| +- pom.xml
|
+ pom.xml
My thought was that main-module should provide interfaces which each submodule should be implementing in order to be plugged into whole application. Therefore submodule1/pom.xml contains compile time dependency reference to main-module. In its turn I also need to be able to test whole application and thus main-module/pom.xml contains test scope dependency reference to submodule1. As the result maven refuses to compile projects saying that they contain cyclic references.
My thought was that maven could first compile classes of main-module as it does not require any compile time dependency on any of submodules, then it using compiled classes of main-module could compile classes of submodule1 and after that compile test classes of main-module (to be able run tests). But seems that maven compiler does not take in account the scope of dependency and I somehow need to work around that.
The only solution I can see is to move away tests from main-module, which doesn't really make sense for me as only that module provides main logic.
My question - is there any other way around this issue except for moving away tests? Or maybe something is wrong with my understanding of how maven-reactor-plugin should work?
Instead of moving your tests away, you could move all of your API into it's own module. Then your main module would contain the application and you can freely distribute your application's API to allow others to access it. If they want to develop new functionality they do not necessarily need the sources of your app.
I consider this a much better style, because sub modules with specific functionality can now clearly separate between what is your applications API and what is the code your application needs to startup/shutdown, etc.
This is in my mind the intended way of how maven projects should look like. It also sticks with the single responsibility principle. The main modules responsibility is to startup/shutdown, etc your application. The API modules responsibility is to show how other developers can access your application. And the other submodule provide specific functionality for your application.
I know this is more of a comment, but might provide you with (not so pretty) solution:
You can seet your submodule1 as a dependency of maven-surefire-plugin (so that reactor is forced to build it) and then play with its settings... i.e. childDelegation or additionalClasspathElements

How to make IntelliJ IDEA use javac for Java and scalac for Scala?

In my IDEA project a Scala module depends on a Java module. When I try to compile the Scala module, only scalac is triggered. It compiles both Java and Scala sources.
I'd like scalac to compile only the Scala module, because javac is much faster for Java sources (and my Java project is a big one).
How to make IDEA use different compiler for different modules?
My workaround is to (for each dependency to Java module):
Delete module dependency in project configuration
Add dependency to appropriate compile output directory "MyJavaModule/target/classes"
Obviously I'm not happy with that, because every time I reimport Maven project I need to repeat all of this to have fast compilation. I hope somebody knows a better way.
Clarification: I'd like to stress, that tools like SBT or Maven don't solve my problem. It is not about compilation alone. It's about compilation in IDEA, required for things like Scala Worksheet or running unit tests from IDEA. My goal is to have full range of IDEA niceties (syntax highlighting, intelligent auto-completion, auto-imports, etc) with compilation speed of SBT. Now I have to either tolerate long compilation times (due to dependencies to my Java module) or to use bare-bones REPL and testing in SBT.
Randall Schulz has asked the right question in the comment: "Why does it matter which tool does the compilation?"
Up until now I believed that IDEA needs to compile all classes itself if you want to use its nice features (like IDEA's Scala Console or running tests from within it). I was wrong.
In fact, IDEA will pick up classes compiled by any other tool (like the great SBT for instance). You just need to assure that all classes are up-to-date before using any of IDEA's helpful features. The best way to do it is:
launch continuous incremental compilation in the background (for
example by issuing "~ compile" in SBT)
remove "make" step in IDEA's
run configurations
That's all! You can then use all cool features of IDEA (not only syntax highlighting and code completion, but all auto-imports in Scala Console, quickly running selected unit tests) without switching between different windows.
That's the workflow I missed until now! Thanks to everybody for all the comments about the issue.
You should look at using a dependency management suite like Apache Ivy or Apache Maven. Then put your Java source in a separate artifact, and have your Scala project be dependent on the Java project artifact.
If you go the Maven route, there is a Scala plugin.
Probably the simplest way to get compiled Scala and Java files is SBT - Simple Build Tool. Just create a project (+ add dependencies and so on) and compile it. Scala + Java compilation works out of the box. I've switched to SBT from Maven.
If you have a complex POM or if you have another reason not to migrate to SBT, you can try to configure the POM. Just adding (and possibly configuring) the Scala plugin should be enough. I hope it will not break the Java support.

How do I enforce a package-level build order in eclipse

Explanation:
Say package A is always built first and then package B. I need to configure my eclipse workspace such that it mimics the build environment and shows compilation errors when sources in package A refer package B. Is this possible? If yes, how?
You'd need to build them as separate projects, with project B referring to project A but not the other way round.
If you want even tighter enforcement, you can make your projects OSGi bundles/Eclipse plugins. This allows you to specify which packages are exported from a bundle, and you can even specify that only specific bundles can access certain packages.
Take a look to: Arquitecture Rules or Macker
These tools are able to warn you when some rule is broken. They both support the rule "some package should not invoke some other package".
I do not know if there is an eclipse plugin for any of them, sorry.

Categories