Skip to content

Commit

Permalink
Merge pull request quarkusio#30001 from Sgitario/29885
Browse files Browse the repository at this point in the history
Fix AbstractMethodError when injecting generated resource
  • Loading branch information
geoand authored Dec 21, 2022
2 parents 6faa967 + 0fd9456 commit 9bf4af9
Show file tree
Hide file tree
Showing 16 changed files with 307 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,25 @@ public interface DataAccessImplementor {
*/
ResultHandle findById(BytecodeCreator creator, ResultHandle id);

/**
* Find all entities.
*
* @param creator Bytecode creator that should be used for implementation.
* @param page Page instance that should be used in a query. Might be null if pagination is disabled.
* @return Entity list
*/
ResultHandle findAll(BytecodeCreator creator, ResultHandle page);

/**
* Find all entities.
*
* @param creator Bytecode creator that should be used for implementation.
* @param page Page instance that should be used in a query. Might be null if pagination is disabled.
* @param sort Sort instance that should be used in a query.
* @return Entity list
*/
ResultHandle findAll(BytecodeCreator creator, ResultHandle page, ResultHandle sort);

/**
* Find all entities.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,29 @@ public ResultHandle findById(BytecodeCreator creator, ResultHandle id) {
id);
}

/**
* Implements <code>Entity.findAll().page(page).list()</code>
*/
@Override
public ResultHandle findAll(BytecodeCreator creator, ResultHandle page) {
ResultHandle query = creator.invokeStaticMethod(ofMethod(entityClassName, "findAll", PanacheQuery.class));
creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "page", PanacheQuery.class, Page.class), query,
page);
return creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "list", List.class), query);
}

/**
* Implements <code>Entity.findAll(sort).page(page).list()</code>
*/
@Override
public ResultHandle findAll(BytecodeCreator creator, ResultHandle page, ResultHandle sort) {
ResultHandle query = creator.invokeStaticMethod(
ofMethod(entityClassName, "findAll", PanacheQuery.class, Sort.class), sort);
creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "page", PanacheQuery.class, Page.class), query,
page);
return creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "list", List.class), query);
}

/**
* Implements <code>Entity.find(query, params).page(page).list()</code>
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,29 @@ public ResultHandle findById(BytecodeCreator creator, ResultHandle id) {
getRepositoryInstance(creator), id);
}

/**
* Implements <code>repository.findAll().page(page).list()</code>
*/
@Override
public ResultHandle findAll(BytecodeCreator creator, ResultHandle page) {
ResultHandle query = creator.invokeInterfaceMethod(
ofMethod(PanacheRepositoryBase.class, "findAll", PanacheQuery.class), getRepositoryInstance(creator));
creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "page", PanacheQuery.class, Page.class), query, page);
return creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "list", List.class), query);
}

/**
* Implements <code>repository.findAll(sort).page(page).list()</code>
*/
@Override
public ResultHandle findAll(BytecodeCreator creator, ResultHandle page, ResultHandle sort) {
ResultHandle query = creator.invokeInterfaceMethod(
ofMethod(PanacheRepositoryBase.class, "findAll", PanacheQuery.class, Sort.class),
getRepositoryInstance(creator), sort);
creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "page", PanacheQuery.class, Page.class), query, page);
return creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "list", List.class), query);
}

/**
* Implements <code>repository.find(query, params).page(page).list()</code>
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
import java.util.List;
import java.util.Map;

import javax.annotation.Priority;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Alternative;
import javax.transaction.Transactional;

import org.jboss.jandex.ClassInfo;
Expand Down Expand Up @@ -55,11 +57,16 @@ String implement(ClassOutput classOutput, DataAccessImplementor dataAccessImplem
.build();

classCreator.addAnnotation(ApplicationScoped.class);
// The same resource is generated as part of the JaxRsResourceImplementor, so we need to avoid ambiguous resolution
// when injecting the resource in user beans:
classCreator.addAnnotation(Alternative.class);
classCreator.addAnnotation(Priority.class).add("value", Integer.MAX_VALUE);

ResourceMethodListenerImplementor listenerImplementor = new ResourceMethodListenerImplementor(classCreator,
resourceMethodListeners, false);

implementList(classCreator, dataAccessImplementor);
implementListWithQuery(classCreator, dataAccessImplementor);
implementListPageCount(classCreator, dataAccessImplementor);
implementCount(classCreator, dataAccessImplementor);
implementGet(classCreator, dataAccessImplementor);
Expand All @@ -73,6 +80,20 @@ String implement(ClassOutput classOutput, DataAccessImplementor dataAccessImplem
}

private void implementList(ClassCreator classCreator, DataAccessImplementor dataAccessImplementor) {
MethodCreator methodCreator = classCreator.getMethodCreator("list", List.class, Page.class, Sort.class);
ResultHandle page = methodCreator.getMethodParam(0);
ResultHandle sort = methodCreator.getMethodParam(1);
ResultHandle columns = methodCreator.invokeVirtualMethod(ofMethod(Sort.class, "getColumns", List.class), sort);
ResultHandle isEmptySort = methodCreator.invokeInterfaceMethod(ofMethod(List.class, "isEmpty", boolean.class), columns);

BranchResult isEmptySortBranch = methodCreator.ifTrue(isEmptySort);
isEmptySortBranch.trueBranch().returnValue(dataAccessImplementor.findAll(isEmptySortBranch.trueBranch(), page));
isEmptySortBranch.falseBranch().returnValue(dataAccessImplementor.findAll(isEmptySortBranch.falseBranch(), page, sort));

methodCreator.close();
}

private void implementListWithQuery(ClassCreator classCreator, DataAccessImplementor dataAccessImplementor) {
MethodCreator methodCreator = classCreator.getMethodCreator("list", List.class, Page.class, Sort.class,
String.class, Map.class);
ResultHandle page = methodCreator.getMethodParam(0);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package io.quarkus.hibernate.orm.rest.data.panache.deployment;

import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.contains;

import org.junit.jupiter.api.Test;

public abstract class AbstractInjectResourcesMethodTest {

@Test
void shouldGetListOfItems() {
given().accept("application/json")
.when().get("/call/resource/items")
.then().statusCode(200)
.and().body("id", contains(1, 2));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package io.quarkus.hibernate.orm.rest.data.panache.deployment.entity;

import java.util.List;

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import io.quarkus.panache.common.Page;
import io.quarkus.panache.common.Sort;

@Path("/call/resource")
public class InjectionResource {

@Inject
ItemsResource itemsResource;

@GET
@Path("/items")
@Produces(MediaType.APPLICATION_JSON)
public List<Item> items() {
return itemsResource.list(new Page(5), Sort.by("id"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package io.quarkus.hibernate.orm.rest.data.panache.deployment.entity;

import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkus.hibernate.orm.panache.PanacheEntity;
import io.quarkus.hibernate.orm.panache.PanacheEntityBase;
import io.quarkus.hibernate.orm.rest.data.panache.deployment.AbstractInjectResourcesMethodTest;
import io.quarkus.test.QuarkusUnitTest;

class PanacheEntityResourceInjectResourcesMethodTest extends AbstractInjectResourcesMethodTest {

@RegisterExtension
static final QuarkusUnitTest TEST = new QuarkusUnitTest()
.withApplicationRoot((jar) -> jar
.addClasses(PanacheEntityBase.class, PanacheEntity.class, Collection.class, CollectionsResource.class,
AbstractEntity.class, AbstractItem.class, Item.class, ItemsResource.class, InjectionResource.class)
.addAsResource("application.properties")
.addAsResource("import.sql"));
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,25 @@ public interface DataAccessImplementor {
*/
ResultHandle findById(BytecodeCreator creator, ResultHandle id);

/**
* Find all entities.
*
* @param creator Bytecode creator that should be used for implementation.
* @param page Page instance that should be used in a query. Might be null if pagination is disabled.
* @return Entity list
*/
ResultHandle findAll(BytecodeCreator creator, ResultHandle page);

/**
* Find all entities.
*
* @param creator Bytecode creator that should be used for implementation.
* @param page Page instance that should be used in a query. Might be null if pagination is disabled.
* @param sort Sort instance that should be used in a query.
* @return Entity list
*/
ResultHandle findAll(BytecodeCreator creator, ResultHandle page, ResultHandle sort);

/**
* Find all entities.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,29 @@ public ResultHandle findById(BytecodeCreator creator, ResultHandle id) {
id);
}

/**
* Implements <code>Entity.findAll().page(page).list()</code>
*/
@Override
public ResultHandle findAll(BytecodeCreator creator, ResultHandle page) {
ResultHandle query = creator.invokeStaticMethod(ofMethod(entityClassName, "findAll", PanacheQuery.class));
creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "page", PanacheQuery.class, Page.class), query,
page);
return creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "list", Uni.class), query);
}

/**
* Implements <code>Entity.findAll(sort).page(page).list()</code>
*/
@Override
public ResultHandle findAll(BytecodeCreator creator, ResultHandle page, ResultHandle sort) {
ResultHandle query = creator.invokeStaticMethod(
ofMethod(entityClassName, "findAll", PanacheQuery.class, Sort.class), sort);
creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "page", PanacheQuery.class, Page.class), query,
page);
return creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "list", Uni.class), query);
}

/**
* Implements <code>Entity.findAll(query, params).page(page).list()</code>
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,29 @@ public ResultHandle findById(BytecodeCreator creator, ResultHandle id) {
getRepositoryInstance(creator), id);
}

/**
* Implements <code>repository.findAll().page(page).list()</code>
*/
@Override
public ResultHandle findAll(BytecodeCreator creator, ResultHandle page) {
ResultHandle query = creator.invokeInterfaceMethod(
ofMethod(PanacheRepositoryBase.class, "findAll", PanacheQuery.class), getRepositoryInstance(creator));
creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "page", PanacheQuery.class, Page.class), query, page);
return creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "list", Uni.class), query);
}

/**
* Implements <code>repository.findAll(sort).page(page).list()</code>
*/
@Override
public ResultHandle findAll(BytecodeCreator creator, ResultHandle page, ResultHandle sort) {
ResultHandle query = creator.invokeInterfaceMethod(
ofMethod(PanacheRepositoryBase.class, "findAll", PanacheQuery.class, Sort.class),
getRepositoryInstance(creator), sort);
creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "page", PanacheQuery.class, Page.class), query, page);
return creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "list", Uni.class), query);
}

/**
* Implements <code>repository.find(query, params).page(page).list()</code>
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
import java.util.List;
import java.util.Map;

import javax.annotation.Priority;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Alternative;

import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.FieldInfo;
Expand Down Expand Up @@ -56,13 +58,18 @@ String implement(ClassOutput classOutput, DataAccessImplementor dataAccessImplem
.build();

classCreator.addAnnotation(ApplicationScoped.class);
// The same resource is generated as part of the JaxRsResourceImplementor, so we need to avoid ambiguous resolution
// when injecting the resource in user beans:
classCreator.addAnnotation(Alternative.class);
classCreator.addAnnotation(Priority.class).add("value", Integer.MAX_VALUE);

ResourceMethodListenerImplementor resourceMethodListenerImplementor = new ResourceMethodListenerImplementor(
classCreator, resourceMethodListeners, true);

implementList(classCreator, dataAccessImplementor);
implementCount(classCreator, dataAccessImplementor);
implementListWithQuery(classCreator, dataAccessImplementor);
implementListPageCount(classCreator, dataAccessImplementor);
implementCount(classCreator, dataAccessImplementor);
implementGet(classCreator, dataAccessImplementor);
implementAdd(classCreator, dataAccessImplementor, resourceMethodListenerImplementor);
implementUpdate(classCreator, dataAccessImplementor, entityType, resourceMethodListenerImplementor);
Expand All @@ -74,6 +81,20 @@ String implement(ClassOutput classOutput, DataAccessImplementor dataAccessImplem
}

private void implementList(ClassCreator classCreator, DataAccessImplementor dataAccessImplementor) {
MethodCreator methodCreator = classCreator.getMethodCreator("list", Uni.class, Page.class, Sort.class);
ResultHandle page = methodCreator.getMethodParam(0);
ResultHandle sort = methodCreator.getMethodParam(1);
ResultHandle columns = methodCreator.invokeVirtualMethod(ofMethod(Sort.class, "getColumns", List.class), sort);
ResultHandle isEmptySort = methodCreator.invokeInterfaceMethod(ofMethod(List.class, "isEmpty", boolean.class), columns);

BranchResult isEmptySortBranch = methodCreator.ifTrue(isEmptySort);
isEmptySortBranch.trueBranch().returnValue(dataAccessImplementor.findAll(isEmptySortBranch.trueBranch(), page));
isEmptySortBranch.falseBranch().returnValue(dataAccessImplementor.findAll(isEmptySortBranch.falseBranch(), page, sort));

methodCreator.close();
}

private void implementListWithQuery(ClassCreator classCreator, DataAccessImplementor dataAccessImplementor) {
MethodCreator methodCreator = classCreator.getMethodCreator("list", Uni.class, Page.class, Sort.class,
String.class, Map.class);
ResultHandle page = methodCreator.getMethodParam(0);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package io.quarkus.hibernate.reactive.rest.data.panache.deployment;

import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.contains;

import org.junit.jupiter.api.Test;

public abstract class AbstractInjectResourcesMethodTest {

@Test
void shouldGetListOfItems() {
given().accept("application/json")
.when().get("/call/resource/items")
.then().statusCode(200)
.and().body("id", contains(1, 2));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package io.quarkus.hibernate.reactive.rest.data.panache.deployment.entity;

import java.util.List;

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import io.quarkus.panache.common.Page;
import io.quarkus.panache.common.Sort;
import io.smallrye.mutiny.Uni;

@Path("/call/resource")
public class InjectionResource {

@Inject
ItemsResource itemsResource;

@GET
@Path("/items")
@Produces(MediaType.APPLICATION_JSON)
public Uni<List<Item>> items() {
return itemsResource.list(new Page(5), Sort.by("id"));
}
}
Loading

0 comments on commit 9bf4af9

Please sign in to comment.