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

Reply via email to