Hi Stephan,

I thin this is a classical problem with reflection access checking that existed before jigsaw, but is now encountered even more frequently. The problem is that your ReflectionWrapper, given an instnace of some object, takes its runtime Class and searches methods in that class. The runtime class of the object may not be accessible to the world (i.e. the ReflectionWrapper). When you search for a method in such class you may end up with a Method object that represents the method declared in such inaccessible class (in your example, this seems to be com.sun.tools.javac.api.JavacTrees::getTree(Element)). Access checks for such method then fail, because com.sun.tools.javac.api.JavacTrees is not publicly accessible (it is in a non-exported package).

I recommend that you modify your ReflectionWrapper so that it takes a "Class type" parameter in addition to the "Object instance" and then use this "type" (which should always represent some publicly accessible supertype of the runtime type of the instance) to search for methods...

ReflectionWrapper(Class type, Object instance) {
        this.type = type;
        this.instance = type.cast(instance);
}


And then:

final class Trees extends ReflectionWrapper {

    private Trees(Object instance) {
        super(com.sun.source.util.Trees.class, instance);
    }

...


I think this should work.


Regards, Peter


On 11/28/2016 09:41 AM, Stéphane Nicoll wrote:
Jon,

We invoke `com.sun.source.util.Trees#instance(ProcessingEnvironment)`
reflectively[1] as this class may not be available. This gives us access to
`Tree` that we handle reflectively as well[2]. There is no reference
anywhere to com.sun.tools.javac.api.JavacTrees in our codebase so I guess
this exception is an attempt of us invoking that method reflectively?

In any case, that's what we ended up doing to retrieve the init value of
fields in an annotation processor. If there is any other way using a public
API, I am more happy than replace that code. Should I raise that question
on compiler-dev?

Thanks a lot,
S.




[1]
https://github.com/spring-projects/spring-boot/blob/master/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/fieldvalues/javac/Trees.java#L41-L46
[2]
https://github.com/spring-projects/spring-boot/blob/master/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/fieldvalues/javac/Tree.java


On Sun, Nov 27, 2016 at 4:57 PM, Jonathan Gibbons <
jonathan.gibb...@oracle.com> wrote:

Stéphan,

You say you are using com.sun.tools.javac.api.JavacTrees. Although that
class is not exported from jdk.compiler, it is an implementation of the
interface com.sun.source.util.Trees, which is exported.  Is the interface
sufficient to your needs? If not, what methods are you calling?

-- Jon



On 11/27/16 1:16 AM, Stéphane Nicoll wrote:

Hey,

Thanks for all the feedback so far. Any idea about the annotation
processor
question? Is there a dedicated dev list for it maybe?

Thank you,
S.


On Thu, Nov 24, 2016 at 3:22 PM, Stéphane Nicoll <snic...@pivotal.io>
wrote:

Hi,
I am working on the Spring Boot project[1] and I am trying to make sure
our codebase compiles with the current JDK9 build[2]. So far I've hit two
major issues:

We use "sun.misc.VMSupport" to retrieve the port being used by the Java
remote debugging. You can find the actual code in
RemoteDebugPortProvider[3]

We have an annotation processor that inspects all classes annotated with
@ConfigurationProperties and generates some meta-data about them. One
important piece of this is to extract the default value assigned to
fields.
Consider the following example

@ConfigurationProperties
public class Foo {

    private static final String DEFAULT_NAME = "name";

    private String name = DEFAULT_NAME;

    private Integer counter = 42;

    private List<String> hosts = Collections.singletonList("localhost");


}

What we've build is a visitor that navigates to those elements and
extracts the default values assigned to each field, including navigating
to
parent element (the "name" constant there) or inferring value from method
parameters ("localhost"). The  current code relies on a feature of the
JDK
that is no longer exported[4]:


java.lang.IllegalAccessException: class org.springframework.boot.
configurationprocessor.fieldvalues.javac.Trees cannot access class
com.sun.tools.javac.api.JavacTrees (in module jdk.compiler) because
module jdk.compiler does not export com.sun.tools.javac.api to unnamed
module @5a7fe64
<https://github.com/spring-projects/spring-boot/commit/5a7fe64f>

Does anybody has some insight as how we could migrate those two use
cases?
In particular, the second use case could be implemented with a contract
of
javax.lang.model but we haven't found how to do it.

Thank you,
S.



[1] https://github.com/spring-projects/spring-boot
[2] https://github.com/spring-projects/spring-boot/issues/7226
[3] https://github.com/spring-projects/spring-boot/blob/
master/spring-boot-devtools/src/main/java/org/
springframework/boot/devtools/tunnel/server/RemoteDebugPortProvider.java
[4] https://github.com/spring-projects/spring-boot/blob/
master/spring-boot-tools/spring-boot-configuration-
processor/src/main/java/org/springframework/boot/configurationprocessor/
fieldvalues/javac/Trees.java







Reply via email to