Hi Alan,

I just tried to get an overview to answer what you have asked and some of
the internal types being used are for example the specific JMX bean
implementations rather than their interfaces to expose some additional
metrics that someone at customer ops required at some time following the
commit history. Those are part reflection, part hard-coded, mainly
depending on a type's visibility. To be honest, the containing modules do
not change much and are not recompiled often, I guess neither did people
care too much as long as things worked. There is still a lot of "old" code
that does not even use generics yet and there are compiler warnings all
over the place. Unfortunaely, code migration jobs tend to surpass code
segments that people do not often work with. To stop using internal types
is not even the first thing I would like to see changed in this part of the
code base.

About our own reflective code, here is a very common pattern of the
application in question that I found especially problematic and which is
one of the reasons I went for the "weak modules only approach". Consider
the following code:

package com.acme;
interface Foo {
  Foo getInstance() { return new Bar(); }
  void qux();
}

package com.acme.internal;
class Bar implements Foo {
  public void qux() { /* something */ }
}

<rules-engine>
  <rule>
    <method>qux</method>
  </rule>
</rules-engine>

triggering in the following reflective invocation in the Java layer of the
rule engine's module:

Object foo = Foo.getInstance();
foo.getClass().getMethod("qux").invoke(foo); // Causes IllegalAccessError

In the actual application, the type of Foo is of course not given at this
point, this is a simpliciation. As the above reflection implicitly invokes
"qux" on WorldImpl rather than World, this results in an
IllegalAccessError. Neither is the Bar class supposed to be exposed from
the module but when Java 4 came out and XML was still cool, this is what
people went for.

For this and many other reasons, as for this particular application, I do
not believe it will ever make it past the "weak module" phase. A lot of
code was built based on the assumption that reflection can just cut
through. And while the hack with the agent is of course not show-casing my
personal preference of how to structure an application, it is an easy
work-around for us to make code work correctly that would be non-trivial to
change or is contained in a third-party library. Probably, this solution
will make the customer the happiest, too, considering how expensive
development hours are.

After making my first actual Java 9 experiences, I also want to add just
one personal comment given my background in enterprise programming: Jigsaw
is a great addition and I do really want to use modules. Having them feels
very right and adding them immediately uncovers poorly structured Maven
modules. I am sure, this will greatly influence application design of
future Java applications. However, for the adoption process, I think it is
crucial that non-modularized code behaves as it did before, i.e. that
non-modularized code shows the same behavior when its run on a Java 9 VM.
Given the enormous landscape of Java libraries and so many millions of code
lines being written, I think this reflective access restriction will
furstrate many users as it is difficult to make isolated changes that do
not trigger global effects. In this context, it will always be the easiest
to drop the module migration alltogether and it would be a shame if Jigsaw
modules were not used as much as they should be only for this reason.

Thanks for taking so much time giving feedback on my experience report.
Best regards, Rafael


2016-10-01 21:29 GMT+02:00 Alan Bateman <alan.bate...@oracle.com>:

> On 30/09/2016 16:16, Rafael Winterhalter wrote:
>
>
> With the newest EA build, out of 7000 unit tests, only
>>> 42 tests still fail and those are all because of using non-exported API
>>> of
>>> the JCL.
>>>
>> Just curious, what is "JCL" here?
>>
>
> I mean "Java class library", the classes that are part of the JVM.
>
> Are there many JDK internal APIs bring used? Are all these usages using
> core reflection (and so not found by jdeps).
>
>
>
> :
>
> I was using reflection for this functionality and offered a fallback or
> offered a proper failure message. I did however manage to fix most of these
> problems in the last hours by revisiting them. I am currently down to a
> single failing unit test which relates to Class.forName(typeName, false,
> classLoader) not returning its loaded classes if the class loader is an
> instance of "DelegatingClassLoader". I worked around this by reading the
> class containing vector for instances of this class loader and wrote a unit
> tests that is no longer executable. As it only affects the test, this does
> however not really matter.
>
> Is the DelegatingClassLoader that is used in the internal reflection
> implementation or is it something else?
>
>
>
> :
>
> I hope this is clear now from my above clarification. I was trying out
> explicit, "proper" modules and added dependent jars as automatic modules.
>
> Just on this, I'm interested to know if the modules names that were chosen
> for the automatic modules work out okay? When you migrated automatic
> modules to explicit modules then did you keep the module name?
>
> -Alan
>

Reply via email to