===============
  Migration_1
Single application module
Direct dependencies (only) on modulepath, everything else on classpath
===============

BEFORE WE BEGIN, you are *strongly* motivated to update your libraries to those that have "Java 11 support,"
or at least have a release date 2018 or later.  Often, these only need to be "point release" updates,
e.g., Hibernate 5.2 to 5.3 or 5.4, and are unlikely to introduce any breaking changes.

Updated libraries, if not yet modular, are still likely to have defined a stable Automatic-Module-Name, 
and have fixed any illegal-access violations, deprecated usages, split-packages, etc.

This is *especially* true for the runtime code generation and bytecode manipulation libraries:
  cglib gave way a number of years ago to javassist, and javassist has generally now been dropped in favor of bytebuddy.
  This progression has been in some part a result of more "platform-friendly" approaches to this type of work.
  Indeed, we saw some low-level javassist issues already.

REMINDER: you *only* need to perform the TODO tasks, all the rest is just reading for now, reference for later.


STEP 0  Obtain newer version of Hibernate and its dependencies - 5.4.2.
------
We created this new branch for the application, with mlib and lib directories for libraries.
We placed all JARs in lib to start - this is the classpath.  mlib is the modulepath.
You'll copy the application JAR (javatunes-test-db.jar) into the new branch's dist directory.

We will gradually move selected JARs from lib to mlib, as necessary.
The runtime launch script will have this general form:

$ java --module-path dist;mlib -classpath lib\* --module javatunes.db.test

Unix NOTE: Our examples use Windows-style paths.  If you're on *nix, then replace \ with / and ; with :
Unix NOTE: lib/* has to be in quotes for the classpath
Unix NOTE: Remember this for all commands at the terminal!  Only Windows version shown in rest of file.
$ java --module-path dist:mlib -classpath "lib/*" --module javatunes.db.test


TODO: note the contents of the lib directory -> hibernate-core-5.4.2 and its dependencies,
including javassist-3.24.0-GA (we know about that one) and also a JAXB implementation (and we know why).

  
STEP 1  Use jdeps to analyze our dependencies.  We run it on the classpath-based migration.
------
TODO: copy the dist directory from Migration_0 to Migration_1 (this is our application JAR).
TODO: open a command prompt to the Migration_1 directory and run jdeps on our application JAR:

$ jdeps -summary -classpath lib\* dist\javatunes-db-test.jar

Unix:
$ jdeps -summary -classpath "lib/*" dist/javatunes-db-test.jar

RESULT:
Error: byte-buddy-1.9.10.jar is a multi-release jar file but --multi-release option is not set.

It's true: it's a modular JAR with module-info.class, but it's in META-INF/versions/9 instead of at the root (for no good reason).

TODO: try it again, this time with the --multi-release argument:

$ jdeps -summary --multi-release 11 -classpath lib\* dist\javatunes-db-test.jar

RESULT:
javatunes-db-test.jar -> java.base
javatunes-db-test.jar -> java.sql
javatunes-db-test.jar -> lib\javax.persistence-api-2.2.jar

Our platform dependencies are java.base (of course) and java.sql.
Our direct library dependencies consist only of lib\javax.persistence-api-2.2.jar.

TODO: move this JAR from lib to mlib.  This will place it on the modulepath when we run it.


STEP 2  Move source code to the new branch, put it in a single module, and recompile.
------
ISSUE: we need to declare our dependencies in module-info.java.

From the jdeps output above, it's clear that we need java.sql, but what about the library JAR?
Is it a proper named module or an automatic module, and if so, what is its module name?

We need to inspect it!

TODO: run the jar utility on it with the --describe-module option:

$ jar --file mlib\javax.persistence-api-2.2.jar --describe-module

RESULT:
No module descriptor found. Derived automatic module.
java.persistence@2.2 automatic
...

You can deduce that it has the Automatic-Module-Name manifest attribute set, 
because the filename-based name would be javax.persistence.api.

Now we can write the module-info.java file, then compile the module.

TODO: open src\javatunes.db.test\module-info.java with a text editor and add the dependencies:

module javatunes.db.test {
  requires java.sql;
  requires java.persistence;  // Automatic-Module-Name [javax.persistence-api-2.2.jar]
}

Now we can compile the module.  In order to build the application JAR, we'll need to copy some resource
files into the modules directory, alongside our compiled .class files.  This includes log4j.properties
and the META-INF/persistence.xml file (standard JPA config file).

TODO: compile the module and build the application JAR: use the supplied build script (.cmd or .sh).


STEP 3  Run it with java.persistence on modulepath, everything else on classpath.
------
We'll start with the simplest launch configuration possible.

TODO: run it via the supplied run script (.cmd or .sh), which is simply this command below:

$ java --module-path dist;mlib -classpath lib\* --module javatunes.db.test

RESULT:
java.lang.reflect.InaccessibleObjectException: Unable to make field private java.lang.Long com.javatunes.domain.MusicItem.id accessible: [middle of stacktrace]
module javatunes.db.test does not "opens com.javatunes.domain" to unnamed module @515ebef3

NOTE in particular that it's the *unnamed module* that wants to do private reflection on our com.javatunes.domain package.
Of course, you know in your heart that it's really Hibernate that wants to do it...that's a hint for later.

How will we "opens" our com.javatunes.domain package to the unnamed module?  AND SHOULD WE?
This doesn't feel right, but we're going to try it.
As a general tip, when working with frameworks and libraries that do code generation and bytecode manipulation,
it's advisable to just "give them everything they want" to start, then you can fine-tune it later.

We can of course "blanket opens" the package to the universe, right in the module descriptor:
  opens com.javatunes.domain;

It can also be done as follows, using the command line directive instead:
  --add-opens javatunes.db.test/com.javatunes.domain=ALL-UNNAMED

Since this is *our* module, we'll just add the "opens" directive to the module descriptor.

TODO: add the opens directive to module-info.java, as shown below:

module javatunes.db.test {
  requires java.sql;
  requires java.persistence;
  opens com.javatunes.domain;
}

Then we rebuild the module and run it again, using the same launch command as before.

TODO: execute the build script, and then the run script (.cmd or .sh).

RESULT:
Even worse now!  The stacktrace starts with Hibernate problems, then spirals downward into java.base/jdk.internal.reflect, 
followed by bytebuddy dynamic class injector issues, and then this, the final nail in the coffin:

java.lang.IllegalAccessError: superinterface check failed: class com.javatunes.domain.MusicItem$HibernateProxy$Jzao9Zeg
(in module javatunes.db.test) cannot access class org.hibernate.proxy.ProxyConfiguration (in unnamed module @0x639aba11) 
because module javatunes.db.test does not read unnamed module @0x639aba11

Key in on that last bit: "module javatunes.db.test does not read unnamed module ..."
Well, we know that!  Our code is in a module, and it can't read the unnamed module!

The lesson here is this: although our module does not *literally* depend directly on Hibernate 
(we have no "import org.hibernate" declarations in our code), the errors are telling us that it really does 
need to interact with Hibernate as a module, and so we promote the main Hibernate JAR to the modulepath.


STEP 4  Move the hibernate-core JAR from lib to mlib, all others remain on the classpath.
------
TODO: move the hibernate-core JAR file from lib to mlib.  This will place it on the modulepath when we run it.

Even though we don't need to "requires" it in our module descriptor, we should inspect it.

TODO: run the jar utility on it with the --describe-module option:
$ jar --file mlib\hibernate-core-5.4.2.Final.jar --describe-module

No module descriptor found. Derived automatic module.
org.hibernate.orm.core@5.4.2.Final automatic
...

You can again deduce that it has the Automatic-Module-Name manifest attribute set, 
because the filename-based name would be hibernate.core.

Run it again, using the same launch command as before.  No need to rebuild, as all we did was move 
the hibernate-core JAR from classpath (lib) to modulepath (mlib).

TODO: execute the run script (.cmd or .sh).

RESULT:
BINGO!  Migration Level 1 complete!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

OPTIONAL STEPS
--------------
1 Change "opens" directive in module descriptor to be a "qualified opens"
  opens com.javatunes.domain to org.hibernate.orm.core;

2 Remove the directive from the module descriptor entirely, and replace with the command line directive
  --add-opens javatunes.db.test/com.javatunes.domain=org.hibernate.orm.core

NOTE that both of these steps will require a rebuild (obviously - you've changed source code).