Clojure

Cannot resolve public generic method from package-private base class

Details

  • Type: Defect Defect
  • Status: Open Open
  • Priority: Minor Minor
  • Resolution: Unresolved
  • Affects Version/s: Release 1.3, Release 1.4, Release 1.5
  • Fix Version/s: None
  • Component/s: None
  • Labels:

Description

The Clojure compiler cannot resolve a public generic method inherited from a package-private base class.

Instructions to reproduce:

  • In package P1
    • Define a package-private class A with generic type parameters
    • Define a public method M in A using generic types in either its arguments or return value
    • Define a public class B which extends A
  • In package P2
    • Construct an instance of B
    • Invoke B.M()

This is valid in Java. In Clojure, invoking B.M produces a reflection warning, followed by the error "java.lang.IllegalArgumentException: Can't call public method of non-public class." No amount of type-hinting prevents the warning or the error.

Attachment clj-1243-demo1.tar.gz contains sample code and script to demonstrate the problem.

Examples of Java projects which use public methods in package-private classes:

Activity

Hide
Stuart Sierra added a comment - - edited

It is also not possible to call the method reflectively from Java.

This may be a bug in Java reflection: JDK-4283544

But why does it only happen on generic methods?

Show
Stuart Sierra added a comment - - edited It is also not possible to call the method reflectively from Java. This may be a bug in Java reflection: JDK-4283544 But why does it only happen on generic methods?
Hide
Stuart Sierra added a comment -

According to Rich Hickey, the presence of bridge methods is unspecified and inconsistent across JDK versions.

A possible solution is to use ASM to examine the bytecode of third-party Java classes, instead of the reflection API. That way the Clojure compiler would have access to the same information as the Java compiler.

Show
Stuart Sierra added a comment - According to Rich Hickey, the presence of bridge methods is unspecified and inconsistent across JDK versions. A possible solution is to use ASM to examine the bytecode of third-party Java classes, instead of the reflection API. That way the Clojure compiler would have access to the same information as the Java compiler.
Hide
Andy Fingerhut added a comment -

CLJ-1183 was closed as a duplicate of this one. Mentioning it here in case anyone working on this ticket wants to follow the link to it and read discussion or test cases described there.

Show
Andy Fingerhut added a comment - CLJ-1183 was closed as a duplicate of this one. Mentioning it here in case anyone working on this ticket wants to follow the link to it and read discussion or test cases described there.
Hide
Noam Ben Ari added a comment -

The current work around I use is to define a new Java class, add a static method that does what I need, and call that from Clojure.

Show
Noam Ben Ari added a comment - The current work around I use is to define a new Java class, add a static method that does what I need, and call that from Clojure.
Hide
Noam Ben Ari added a comment -

Also, I'm seeing this issue in 1.6 and 1.7(alpha5) but the issue mentions only up to 1.5 .

Show
Noam Ben Ari added a comment - Also, I'm seeing this issue in 1.6 and 1.7(alpha5) but the issue mentions only up to 1.5 .
Hide
Adam Tait added a comment -

Just ran into this issue trying to use Google's Cloud APIs.
To use Google's Cloud Datastore, you need to access the .kind method on a protected generic subclass (BaseKey), to which KeyFactory extends.

Tested on both Clojure 1.7 & 1.8 at runtime, the following exception persists;

IllegalArgumentException Can't call public method of non-public class: public com.google.gcloud.datastore.BaseKey$Builder com.google.gcloud.datastore.BaseKey$Builder.kind(java.lang.String) clojure.lang.Reflector.invokeMatchingMethod (Reflector.java:88)

Show
Adam Tait added a comment - Just ran into this issue trying to use Google's Cloud APIs. To use Google's Cloud Datastore, you need to access the .kind method on a protected generic subclass (BaseKey), to which KeyFactory extends. Tested on both Clojure 1.7 & 1.8 at runtime, the following exception persists;
IllegalArgumentException Can't call public method of non-public class: public com.google.gcloud.datastore.BaseKey$Builder com.google.gcloud.datastore.BaseKey$Builder.kind(java.lang.String) clojure.lang.Reflector.invokeMatchingMethod (Reflector.java:88)
Hide
Kai Strempel added a comment -

I ran into the exact same issue with Google's Cloud API's.

Tested it with 1.8 and with 1.9.0-alpha7. Same Problem.

Show
Kai Strempel added a comment - I ran into the exact same issue with Google's Cloud API's. Tested it with 1.8 and with 1.9.0-alpha7. Same Problem.
Hide
Kai Strempel added a comment -

I ran into the exact same issue with Google's Cloud API's.

Tested it with 1.8 and with 1.9.0-alpha7. Same Problem.

Show
Kai Strempel added a comment - I ran into the exact same issue with Google's Cloud API's. Tested it with 1.8 and with 1.9.0-alpha7. Same Problem.
Hide
Michal Růžička added a comment - - edited

I ran into the same issue. The attached patch fixes the problem for me.
All tests in the project still pass, but this desperately needs a review of someone knowledgeable.

Show
Michal Růžička added a comment - - edited I ran into the same issue. The attached patch fixes the problem for me. All tests in the project still pass, but this desperately needs a review of someone knowledgeable.
Hide
Alex Miller added a comment -

Hey Michal,

Thanks for looking at it.

1. Please follow the instructions on how to create a patch in the proper format here: http://dev.clojure.org/display/community/Developing+Patches
2. If you can provide some explanation of the changes to aid in review that would be most helpful. Otherwise screeners have to re-engineer your thought processes from scratch.
3. Before getting screened, this change will also need some tests (admittedly not particularly fun to write, but I think it's necessary here)

Show
Alex Miller added a comment - Hey Michal, Thanks for looking at it. 1. Please follow the instructions on how to create a patch in the proper format here: http://dev.clojure.org/display/community/Developing+Patches 2. If you can provide some explanation of the changes to aid in review that would be most helpful. Otherwise screeners have to re-engineer your thought processes from scratch. 3. Before getting screened, this change will also need some tests (admittedly not particularly fun to write, but I think it's necessary here)

People

Vote (4)
Watch (4)

Dates

  • Created:
    Updated: