I am currently taking over old Scala application with main goal to write new functionality in Java, but leveraging old common code. Up till now repository looked more-or-less like this:
├──common-scala-module-1
│ ├── src
│ │ ├── scala
│ │ │ ├── **/*.scala
│ │ ├── test
│ │ │ ├── **/*.scala
├──common-scala-module-2
│ ├── src
│ │ ├── scala
│ │ │ ├── **/*.scala
│ │ ├── test
│ │ │ ├── **/*.scala
├──scala-module-3
│ ├── src
│ │ ├── scala
│ │ │ ├── **/*.scala
│ │ ├── test
│ │ │ ├── **/*.scala
├──scala-module-4
│ ├── src
│ │ ├── scala
│ │ │ ├── **/*.scala
│ │ ├── test
│ │ │ ├── **/*.scala
├── build.sbt
├── .gitignore
└── (other scala files that doesn't matter for this problem)
All of those 4 produce jar modules, but the ones that really do matter for production code are from scala-module-3
and scala-module-4
(which depend on classes in both common modules). I need to start writing new code (new modules, like scala-module-3
) but in Java from this point onward. I will still need however to maintain the old code if such need arises. There are two main concerns that I have and which I'd like to get architectural advice on (I wrote what I currently believe is the best path in parentheses after question):
NOTE: I do have pretty extensive Java background in multiple projects and I do know Scala basics (like that it leverages JVM technology and that SBT should work even if I'd just start putting Java code into the repository out of the blue). I am just looking for architectural advice in order to know the trade-offs and make my (and maybe someday others) life easier as this application is now leaving Scala behind (outside of bugs/maintenance).
Your primary problem is not to choose between Maven or Gradle.
Your primary problem is that you most likely cannot directly use any of those dependencies in your Java code (the fact that it compiles to JVM bytecode doesn't matter because you will not write your future packages in bytecode).
The reasons why you cannot directly use any of these dependencies are:
implicit
s / given
s, let alone macros. Thus, exposing the given
s is like screaming into an abyss, and not getting any response back, i.e. noisy & pointless.One reasonable thing that you might attempt:
common-scala-module-1
, common-scala-module-2
etc.<P>
, either create additional <P>-javaapi
subproject (i.e. common-scala-module-1-javaapi
, common-scala-module-2-javaapi
etc.), or create an additional <P>/javaapi
subpackage (i.e. common-scala-module-1/src/main/java/org/whatever/tool/javaapi
)<P>-javaapi
subproject / subpackage:
<P>
, but written as idiomatic Java. Brace yourself for FactoryFactories
and pages upon pages of repetitive generics.<P>
<P>-javaapi
with SBT (the -javaapi
is a mixed Scala/Java project, so probably better to build it with SBT)-javaapi
packages.This should work, because:
scala.jdk.CollectionConverters
etc. is trivial.-javaapi
packages with SBT should work fine.By the end, you obtain bunch of packages common-scala-module-1-javaapi
... common-scala-module-N-javaapi
that are practically indistinguishable from any Java packages not only on bytecode level, but also on the level of exported types, interfaces, and documentation. The only difference is that they would have weird dependencies (but you won't notice it while using them).
Unless your code is a tightly coupled mess that prevents you from testing common-scala-module-N
s without also modifying and rerunning all your non-common-modules, then it's probably better to create a separate repo with separate java-module-0
, java-module-1
etc. and build them with Maven (or Gradle).