Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

java.lang.IllegalAccessError: failed to access class when calling Java API #13841

Closed
RaasAhsan opened this issue Oct 28, 2021 · 7 comments · Fixed by #21362
Closed

java.lang.IllegalAccessError: failed to access class when calling Java API #13841

RaasAhsan opened this issue Oct 28, 2021 · 7 comments · Fixed by #21362
Labels
itype:bug stat:needs minimization Needs a self contained minimization
Milestone

Comments

@RaasAhsan
Copy link

RaasAhsan commented Oct 28, 2021

Environment

Compiler: 3.0.2, 3.1.0
JVM: tested on AdoptOpenJDK 8, Temurin 11 (compiler and runtime)
OS: tested on darwin x86_64 and darwin arm64

Minimized code

build.sbt

libraryDependencies ++= Seq(
  "software.amazon.smithy" % "smithy-model" % "1.12.0"
)

Main.scala

import software.amazon.smithy.model.shapes._
object Main {
  def main(args: Array[String]): Unit = {
    val string = StringShape.builder.id("com.example#String").build
    val int = IntegerShape.builder.id("com.example#Integer").build
    val foo = StructureShape.builder
      .id("com.example#Foo")
      .addMember("bar", string.getId)
      .addMember("baz", int.getId)
    // commenting out the second addMember 
    // or explicitly typing the expression before it to `StructureShape.Builder` makes it compile
  }
}

Output

Exception in thread main: java.lang.Exception: java.lang.IllegalAccessError: failed to access class software.amazon.smithy.model.shapes.NamedMembersShape$Builder from class Main$ (software.amazon.smithy.model.shapes.NamedMembersShape$Builder and Main$ are in unnamed module of loader 'app')

Expectation

Snippet should terminate without raising an exception. Snippet compiles and terminates successfully on 2.13.5 compiler. This builder pattern is used considerably throughout AWS SDK so likely affects other AWS libraries as well.

@michelou
Copy link
Contributor

@RaasAhsan Please also specify Java version and execution environment.

@RaasAhsan
Copy link
Author

Done, let me know if the provided information is sufficient

@som-snytt
Copy link
Contributor

som-snytt commented Oct 28, 2021

With quick glance at smithy-model, is the difference in inference that addMember is overloaded but id is not?

That is, both return B typearg, but addMember call is typed without expected type? (I don't know if this was a specific improvement in Scala 2.)

@RaasAhsan
Copy link
Author

It looks like the specific overload of id being called in the snippet is inherited from AbstractShapeBuilder but it defers to another overload which is overriden by NamedMembersShape.Builder. addMember has 3 overloads which are inherited from NamedMembersShape.Builder.

@odersky
Copy link
Contributor

odersky commented Nov 4, 2021

To address this, we will need a minimization that does not involve third part libraries.

@som-snytt
Copy link
Contributor

The issue is that the parent of the concrete builder is package-private, but javap shows it using that interface in the second call

        50: invokevirtual #87                 // Method software/amazon/smithy/model/shapes/StructureShape$Builder.addMember:(Ljava/lang/String;Lsoftware/amazon/smithy/model/shapes/ShapeId;)Lsoftware/amazon/smithy/model/shapes/NamedMembersShape$Builder;
        53: ldc           #89                 // String baz
        55: aload_2
        56: invokevirtual #90                 // Method software/amazon/smithy/model/shapes/IntegerShape.getId:()Lsoftware/amazon/smithy/model/shapes/ShapeId;
        59: invokevirtual #91                 // Method software/amazon/smithy/model/shapes/NamedMembersShape$Builder.addMember:(Ljava/lang/String;Lsoftware/amazon/smithy/model/shapes/ShapeId;)Lsoftware/amazon/smithy/model/shapes/NamedMembersShape$Builder;
        62: checkcast     #22                 // class software/amazon/smithy/model/shapes/StructureShape$Builder

After erasure, there is a missing cast

[info]           val foo: software.amazon.smithy.model.shapes.StructureShape.Builder =
[info]             software.amazon.smithy.model.shapes.StructureShape.builder().id(
[info]               "com.example#Foo"
[info]             ).asInstanceOf[
[info]               software.amazon.smithy.model.shapes.StructureShape.Builder
[info]             ].addMember("bar", string.getId()).addMember("baz", int.getId()).
[info]               asInstanceOf
[info]             [software.amazon.smithy.model.shapes.StructureShape.Builder]

The reproductive element is that a method (it need not be an overload) is introduced in the package-private subclass, which is used from the client. The interface used to select the method is the private subclass instead of the public child class.

The public superclass is required, or actually not.

package smithlike;

abstract class B0 {
        abstract static class B0Builder<B extends B0Builder<?, ?>, S> {
                public B z() { return (B) this; }
        }
}
package smithlike;

public final class B1 extends B0 {
        public static B1Builder builder() { return new B1Builder(); }

        public static class B1Builder extends B0Builder<B1Builder, String> {
        }
}
package smithclient

import smithlike.*

@main def test() = println {
  B1.builder.z().z()
}

scala 2 also shows only the first cast at erasure, so it must be just a backend issue for the second invocation.

scala.Predef.println(smithlike.B1.builder().z().$asInstanceOf[smithlike.B1.B1Builder]().z())

@eed3si9n
Copy link
Member

Here's a PR for this, which backports @lrytz's scala/scala#6023 from Scala 2.x - #21362

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
itype:bug stat:needs minimization Needs a self contained minimization
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants