Right,
So even the interface is optional (as it does not exist on some
platforms). The important thing is that it is public and exported. The
following idiom might have been OK before jigsaw:
instance.getClass().getMethod(...);
But even then you might have ended up with a Method in a non-public
class, so you were forced to use .setAccessible(true) to invoke it.
After jigsaw, it is very likely that the implementation class is not
even exported.
Regards, Peter
On 09/12/2015 01:14 PM, Uwe Schindler wrote:
Hi Peter,
we fixed that already (in Elasticsearch and Apache Solr): https://goo.gl/st9mm7
(variant of Apache Solr)
The issue is: you cannot "import" the sun.management bean into your source
code, because this makes it fail to compile with other non-Oracle/OpenJDK JVMs, like
IBM's J9 or Android. So we need reflection here.
But what you can do is: use Class#forName() to look up the sun.management bean interface
class and then reflect on that one. As the interface is public and exported, this works
without setAccessible. You then just need to cast the OperatingSystemMXBean to that
interface and invoke the previously reflected "public" interface method. This
is what the above patch does.
Uwe
P.S.: This is why we use the "forbidden-apis" Maven/Ant/Gradle plugin to detect
stuff like using non-standardized or unsafe APIs:
https://github.com/policeman-tools/forbidden-apis ; this tool will fail your build
whenever you use methods wich are not part of the Standard JDK. You can also forbid
methods like String#toLowerCase(), because its locale dependent... You will not find any
use of String#toLowerCase() without an explicit Locale anywhere in
Lucene/Solr/Elasticsearch source code.
-----
Uwe Schindler
uschind...@apache.org
ASF Member, Apache Lucene PMC / Committer
Bremen, Germany
http://lucene.apache.org/
-----Original Message-----
From: jigsaw-dev [mailto:jigsaw-dev-boun...@openjdk.java.net] On Behalf
Of Peter Levart
Sent: Saturday, September 12, 2015 12:27 PM
To: Robert Muir; Alan Bateman
Cc: jigsaw-dev@openjdk.java.net
Subject: Re: Jigsaw EA feedback for elasticsearch
Hi Robert,
On 09/11/2015 10:58 PM, Robert Muir wrote:
On Fri, Sep 11, 2015 at 6:09 AM, Alan Bateman
<alan.bate...@oracle.com> wrote:
I'm not sure that I understand the issue here but just to say that
the com.sun.management API is a documented/supported API and it
exported by module jdk.management:
$ java -listmods:jdk.management
jdk.management@9.0
requires public java.management
requires mandated java.base
exports com.sun.management
conceals com.sun.management.internal
provides sun.management.spi.PlatformMBeanProvider with
com.sun.management.internal.PlatformMBeanProviderImpl
Here is code that fails:
import java.lang.reflect.*;
import java.lang.management.*;
public class test {
public static void main(String args[]) throws Exception {
OperatingSystemMXBean osMxBean =
ManagementFactory.getOperatingSystemMXBean();
Method getTotalPhysicalMemorySize =
osMxBean.getClass().getMethod("getTotalPhysicalMemorySize");
getTotalPhysicalMemorySize.setAccessible(true);
System.out.println(getTotalPhysicalMemorySize.invoke(osMxBean));
}
}
Exception in thread "main"
java.lang.reflect.InaccessibleObjectException: Unable to make member
of class com.sun.management.internal.OperatingSystemImpl accessible:
module jdk.management does not export com.sun.management.internal
to
<unnamed module @5f375618>
at
sun.reflect.Reflection.throwInaccessibleObjectException(java.base@9.0/Ref
lection.java:462)
at
java.lang.reflect.AccessibleObject.checkCanSetAccessible(java.base@9.0/Ac
cessibleObject.java:194)
at
java.lang.reflect.AccessibleObject.setAccessible(java.base@9.0/AccessibleO
bject.java:157)
at test.main(test.java:8)
I guess there will be lots of similar issues discovered in various codebases
when trying to run them with jigsaw. The problem of the above code is that it
uses reflection to look up the optional method on the implementation class
of the object (and that class is in some internal package, not exported and
inaccessible to other modules) instead of looking it up on the public API class
(the interface). You get two different methods that way - one is accessible
and the other is not, but invoking either of them should be equivalent, since
the dispatch is always virtual. So the correct way to "test" whether the
method exists (maybe because it has been added on a praticular version of
the
platform) and then to invoke it is the following:
public class test {
public static void main(String args[]) throws Exception {
Method getTotalPhysicalMemorySize =
OperatingSystemMXBean.class.getMethod("getTotalPhysicalMemorySize");
OperatingSystemMXBean osMxBean =
ManagementFactory.getOperatingSystemMXBean();
System.out.println(getTotalPhysicalMemorySize.invoke(osMxBean));
}
}
And you don't even need to set it Method.setAccessible(true), since both
the interface and method are public.
Regards, Peter