- 
  Notifications
 You must be signed in to change notification settings 
- Fork 1.1k
Scala 3 Java interop: method on base class called instead of method on derived class #17073
 
 Unanswered
 
 
 
 
 christian-mibex
 
 
 
 asked this question in
 Compiler internals Q&A
 
 -
Not sure if it's a bug or to be expected. We ran into runtime issues after upgrading to Scala 3.
//> using scala 3 //> using repository "https://maven.atlassian.com/repository/public" //> using lib "com.atlassian.webhooks:atlassian-webhooks-api:6.1.6" //> using lib "com.atlassian.bitbucket.server:bitbucket-webhooks-api:7.14.0" import com.atlassian.bitbucket.webhook.WebhookScopeAdapter import com.atlassian.webhooks._ val createRequest = WebhookCreateRequest.builder .name("name") .url("url") .build() println("Runs with scala 2")
Basically the class hierarchy of WebhookCreateRequest looks like (simplified):
public class CreateRequest extends AbstractRequest { private CreateRequest(Builder builder) { super(builder); } public static Builder builder() { return new Builder();} public static class Builder extends AbstractRequest.AbstractBuilder<Builder> { protected Builder self() { return this; } public build() { return new CreateRequest(this);} } } public abstract class AbstractRequest { abstract static class AbstractBuilder<B extends AbstractBuilder<B>> { private String name; private String url; AbstractBuilder() {} protected abstract B self(); public B name(String value) { this.name = value; return this.self(); } public B url(String value) { this.url = value; return this.self(); } } }
Now the inner class AbstractBuilder is not public, and when the Scala compiler calls the method on it instead of CreateRequest an IllegalAccessException is called.
The bytecode output of Scala 2/ Java compilation
// 10: invokestatic #30 // Method .../WebhookCreateRequest.builder:()L.../WebhookCreateRequest$Builder;
// 13: ldc #32 // String name
// 15: invokevirtual #35 // Method .../WebhookCreateRequest$Builder.name:(Ljava/lang/String;)L.../AbstractWebhookRequest$AbstractBuilder;
// 18: checkcast #12 // class .../WebhookCreateRequest$Builder
// 21: ldc #37 // String url
// 23: invokevirtual #39 // Method .../WebhookCreateRequest$Builder.url:(Ljava/lang/String;)L.../AbstractWebhookRequest$AbstractBuilder;
Compared to Scala 3 (issue on last line)
// 10: invokestatic #34 // Method .../WebhookCreateRequest.builder:()L.../WebhookCreateRequest$Builder;
// 13: ldc #36 // String name
// 15: invokevirtual #39 // Method .../WebhookCreateRequest$Builder.name:(Ljava/lang/String;)L.../AbstractWebhookRequest$AbstractBuilder;
// 18: ldc #41 // String url
// 20: invokevirtual #43 // Method .../AbstractWebhookRequest$AbstractBuilder.url:(Ljava/lang/String;)L.../AbstractWebhookRequest$AbstractBuilder;
Is there a reason the second and all further chained builder calls (here the url()) call) are compiled to call the base class method?
Beta Was this translation helpful? Give feedback.
All reactions
Replies: 0 comments
 
 Sign up for free
 to join this conversation on GitHub.
 Already have an account?
 Sign in to comment