Replacement for JDK8 APIs

Peter Levart peter.levart at gmail.com
Mon Nov 28 09:39:14 UTC 2016


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.gibbons at 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 <snicoll at 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
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>



More information about the jigsaw-dev mailing list