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

'Cannot delegate to an abstract method' for scoped bean with complex interfaces #17755

Closed
caalador opened this issue Jun 8, 2021 · 6 comments · Fixed by #17796
Closed

'Cannot delegate to an abstract method' for scoped bean with complex interfaces #17755

caalador opened this issue Jun 8, 2021 · 6 comments · Fixed by #17796
Assignees
Labels
area/arc Issue related to ARC (dependency injection) env/windows Impacts Windows machines kind/bug Something isn't working
Milestone

Comments

@caalador
Copy link

caalador commented Jun 8, 2021

Describe the bug

For a scoped bean with the setup:

MyBean extends Component implements HasSize constructor calls HasSize::setSize
interface HasSize extends HasElement has a default implementation setSize that calls HasElement::getElement
interface HasElement
class Component implements HasElement This has the actual implementation

Expected behavior

Bean can be instantiated and injected.

Actual behavior

Bean instantiation throws Cannot delegate to an abstract method

Caused by: java.lang.IllegalStateException: Cannot delegate to an abstract method
        at org.acme.MyBean_ClientProxy.getElement(MyBean_ClientProxy.zig:229)
        at org.acme.HasSize.setSize(HasSize.java:7)
        at org.acme.MyBean_ClientProxy.setSize(MyBean_ClientProxy.zig:168)
        at org.acme.MyBean.<init>(MyBean.java:11)
        at org.acme.MyBean_ClientProxy.<init>(MyBean_ClientProxy.zig:28)
        at org.acme.MyBean_Bean.proxy(MyBean_Bean.zig:37)
        at org.acme.MyBean_Bean.get(MyBean_Bean.zig:217)
        at org.acme.MyBean_Bean.get(MyBean_Bean.zig:233)
        at org.acme.GreetingResource_Bean.create(GreetingResource_Bean.zig:154)
        ... 37 more

To Reproduce

https://github.com/caalador/quarkus-scoped-bean

Steps to reproduce the behavior:

  1. run mvn clean package -Dquarkus.debug.generated-sources-dir=gen
  2. see that test fails
  3. Search gen/org/acme/MyBean_ClientProxy.zig for Method getElement and see that it has IllegalStateException for if bean not instantiated

To have a successful build with tests change @ApplicationScoped to @Singleton or implement in MyBean

@Override
public Object getElement() {
  return super.getElement();
}

Environment (please complete the following information):

windows 10

Output of java -version

Java version: 1.8.0_222 & Java version: 11.0.4

Quarkus version or git rev

1.10.5.Final, 1.13.6.Final, 2.0.0.CR3

Build tool (ie. output of mvnw --version or gradlew --version)

Apache Maven 3.8.1

@caalador caalador added the kind/bug Something isn't working label Jun 8, 2021
@quarkus-bot quarkus-bot bot added the env/windows Impacts Windows machines label Jun 8, 2021
@gsmet gsmet added the area/arc Issue related to ARC (dependency injection) label Jun 9, 2021
@gsmet
Copy link
Member

gsmet commented Jun 9, 2021

/cc @mkouba

@mkouba
Copy link
Contributor

mkouba commented Jun 9, 2021

Ok, so there are some limitations when invoking methods from within a bean's no-args constructor. First of all, keep in mind that this constructor is called twice for normal scoped beans. First time, when the client proxy instance is created. In your example, there is a class MyBean_ClientProxy which extends MyBean and it calls super() in its constructor. The client proxy is not fully initialized at that time and so instead of invoking the method upon the real bean instance we just call super.setSize(var1) etc. which may result in unexpected behavior. Second time, the constructor is called again when creating the actual bean instance of MyBean, i.e. the object that is put in the context.

I'd really recommend to avoid having initialization logic in the constructor and use a @PostConstruct callback instead. This is the idiomatic approach in CDI.

That said, the reason why we currently don't call super.getElement() and throw an IllegalStateException instead is that we iterate over interfaces first when collecting delegating methods. I'll try to propose a fix for this.

A workaround exists for the time being - just override the getElement() method on the MyBean class:

public class MyBean extends Component implements HasSize {
   @Override
   public Object getElement() {
      return super.getElement();
   }
}

@mkouba mkouba self-assigned this Jun 9, 2021
@mkouba
Copy link
Contributor

mkouba commented Jun 9, 2021

CC @manovotn @Ladicek

@caalador
Copy link
Author

Is the fix come with 2.0 or will it be waiting until 2.1?

@mkouba
Copy link
Contributor

mkouba commented Jun 10, 2021

It should be backported in 2.0. But as I said above, users are encouraged to switch to a more idiomatic approach instead ;-).

@caalador
Copy link
Author

The Vaadin framework has this issue with the components.
I perhaps do not expect users to have the issue immediately, but it will be confusing when they suddenly
meet this issue.

@gsmet gsmet modified the milestones: 2.1 - main, 2.0.0.Final Jun 10, 2021
gsmet pushed a commit to gsmet/quarkus that referenced this issue Jun 10, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/arc Issue related to ARC (dependency injection) env/windows Impacts Windows machines kind/bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants