Skip to content

Commit

Permalink
Merge pull request #35149 from gsmet/3.2.3-backports-2
Browse files Browse the repository at this point in the history
3.2.3 backports 2
  • Loading branch information
gsmet authored Aug 2, 2023
2 parents 851f588 + 7a94383 commit e8ce818
Show file tree
Hide file tree
Showing 36 changed files with 471 additions and 85 deletions.
4 changes: 2 additions & 2 deletions docs/src/main/asciidoc/duplicated-context.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ That thread is dedicated to this specific processing until the processing comple
Thus, you can use _Thread Locals_ to propagate data along the processing, and no other processing unit will use that thread until the completion of the current one.

With the reactive model, the code runs on event loop threads.
These event loops execute multiple concurrent processing units. F
or example, the same event loop can handle multiple concurrent HTTP requests.
These event loops execute multiple concurrent processing units. For example,
the same event loop can handle multiple concurrent HTTP requests.
The following picture illustrates this reactive execution model:

image::reactive-continuation.png[alt=Continuation in the reactive execution model, width=80%, align=center]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,11 @@ void findEntityResources(CombinedIndexBuildItem index,
ResourceImplementor resourceImplementor = new ResourceImplementor(new EntityClassHelper(index.getComputingIndex()));
ClassOutput classOutput = new GeneratedBeanGizmoAdaptor(implementationsProducer);

for (ClassInfo classInfo : index.getComputingIndex().getKnownDirectImplementors(PANACHE_ENTITY_RESOURCE_INTERFACE)) {
validateResource(index.getComputingIndex(), classInfo);
for (ClassInfo resourceInterface : index.getComputingIndex()
.getKnownDirectImplementors(PANACHE_ENTITY_RESOURCE_INTERFACE)) {
validateResource(index.getComputingIndex(), resourceInterface);

List<Type> generics = getGenericTypes(classInfo);
String resourceInterface = classInfo.name().toString();
List<Type> generics = getGenericTypes(resourceInterface);
String entityType = generics.get(0).name().toString();
String idType = generics.get(1).name().toString();

Expand Down Expand Up @@ -120,12 +120,11 @@ void findRepositoryResources(CombinedIndexBuildItem index,
ResourceImplementor resourceImplementor = new ResourceImplementor(new EntityClassHelper(index.getComputingIndex()));
ClassOutput classOutput = new GeneratedBeanGizmoAdaptor(implementationsProducer);

for (ClassInfo classInfo : index.getComputingIndex()
for (ClassInfo resourceInterface : index.getComputingIndex()
.getKnownDirectImplementors(PANACHE_REPOSITORY_RESOURCE_INTERFACE)) {
validateResource(index.getComputingIndex(), classInfo);
validateResource(index.getComputingIndex(), resourceInterface);

List<Type> generics = getGenericTypes(classInfo);
String resourceInterface = classInfo.name().toString();
List<Type> generics = getGenericTypes(resourceInterface);
String repositoryClassName = generics.get(0).name().toString();
String entityType = generics.get(1).name().toString();
String idType = generics.get(2).name().toString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,9 @@ class ResourceImplementor {
* Implements {@link io.quarkus.rest.data.panache.RestDataResource} interfaces defined in a user application.
* Instances of this class are registered as beans and are later used in the generated JAX-RS controllers.
*/
String implement(ClassOutput classOutput, DataAccessImplementor dataAccessImplementor, String resourceType,
String implement(ClassOutput classOutput, DataAccessImplementor dataAccessImplementor, ClassInfo resourceInterface,
String entityType, List<ClassInfo> resourceMethodListeners) {
String resourceType = resourceInterface.name().toString();
String className = resourceType + "Impl_" + HashUtil.sha1(resourceType);
LOGGER.tracef("Starting generation of '%s'", className);
ClassCreator classCreator = ClassCreator.builder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import java.util.Collections;
import java.util.List;

import jakarta.transaction.Transactional;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;

Expand All @@ -22,4 +24,15 @@ default Collection findByName(@PathParam("name") String name) {

return collections.get(0);
}

@Transactional
@POST
@Path("/name/{name}")
default Collection addByName(@PathParam("name") String name) {
Collection collection = new Collection();
collection.id = name;
collection.name = name;
Collection.persist(collection);
return collection;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package io.quarkus.hibernate.orm.rest.data.panache.deployment.entity;

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

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

import io.quarkus.hibernate.orm.rest.data.panache.deployment.AbstractPostMethodTest;
Expand All @@ -14,4 +18,13 @@ class PanacheEntityResourcePostMethodTest extends AbstractPostMethodTest {
Item.class, ItemsResource.class)
.addAsResource("application.properties")
.addAsResource("import.sql"));

@Test
void shouldCopyUserMethodsAnnotatedWithTransactional() {
given().accept("application/json")
.when().post("/collections/name/mycollection")
.then().statusCode(200)
.and().body("id", is("mycollection"))
.and().body("name", is("mycollection"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package io.quarkus.hibernate.reactive.panache.common.deployment;

import jakarta.persistence.NamedQueries;
import jakarta.persistence.NamedQuery;

import org.jboss.jandex.DotName;

import io.quarkus.hibernate.reactive.panache.common.WithSession;
import io.quarkus.hibernate.reactive.panache.common.WithSessionOnDemand;
import io.quarkus.hibernate.reactive.panache.common.WithTransaction;
import io.quarkus.hibernate.reactive.panache.common.runtime.ReactiveTransactional;
import io.smallrye.mutiny.Uni;

final class DotNames {

static final DotName DOTNAME_NAMED_QUERY = DotName.createSimple(NamedQuery.class.getName());
static final DotName DOTNAME_NAMED_QUERIES = DotName.createSimple(NamedQueries.class.getName());
static final DotName REACTIVE_TRANSACTIONAL = DotName.createSimple(ReactiveTransactional.class.getName());
static final DotName WITH_SESSION_ON_DEMAND = DotName.createSimple(WithSessionOnDemand.class.getName());
static final DotName WITH_SESSION = DotName.createSimple(WithSession.class.getName());
static final DotName WITH_TRANSACTION = DotName.createSimple(WithTransaction.class.getName());
static final DotName UNI = DotName.createSimple(Uni.class.getName());

static final DotName PANACHE_ENTITY_BASE = DotName
.createSimple("io.quarkus.hibernate.reactive.panache.PanacheEntityBase");
static final DotName PANACHE_ENTITY = DotName.createSimple("io.quarkus.hibernate.reactive.panache.PanacheEntity");
static final DotName PANACHE_KOTLIN_ENTITY_BASE = DotName
.createSimple("io.quarkus.hibernate.reactive.panache.kotlin.PanacheEntityBase");
static final DotName PANACHE_KOTLIN_ENTITY = DotName
.createSimple("io.quarkus.hibernate.reactive.panache.kotlin.PanacheEntity");

static final DotName PANACHE_REPOSITORY_BASE = DotName
.createSimple("io.quarkus.hibernate.reactive.panache.PanacheRepositoryBase");
static final DotName PANACHE_REPOSITORY = DotName.createSimple("io.quarkus.hibernate.reactive.panache.PanacheRepository");
static final DotName PANACHE_KOTLIN_REPOSITORY_BASE = DotName
.createSimple("io.quarkus.hibernate.reactive.panache.kotlin.PanacheRepositoryBase");
static final DotName PANACHE_KOTLIN_REPOSITORY = DotName
.createSimple("io.quarkus.hibernate.reactive.panache.kotlin.PanacheRepository");

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@

import jakarta.annotation.Priority;
import jakarta.interceptor.Interceptor;
import jakarta.persistence.NamedQueries;
import jakarta.persistence.NamedQuery;

import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.AnnotationTarget.Kind;
Expand Down Expand Up @@ -46,39 +44,19 @@
import io.quarkus.gizmo.ClassCreator;
import io.quarkus.hibernate.orm.deployment.HibernateOrmEnabled;
import io.quarkus.hibernate.orm.deployment.JpaModelBuildItem;
import io.quarkus.hibernate.reactive.panache.common.WithSession;
import io.quarkus.hibernate.reactive.panache.common.WithSessionOnDemand;
import io.quarkus.hibernate.reactive.panache.common.WithTransaction;
import io.quarkus.hibernate.reactive.panache.common.runtime.PanacheHibernateRecorder;
import io.quarkus.hibernate.reactive.panache.common.runtime.ReactiveTransactional;
import io.quarkus.hibernate.reactive.panache.common.runtime.ReactiveTransactionalInterceptor;
import io.quarkus.hibernate.reactive.panache.common.runtime.TestReactiveTransactionalInterceptor;
import io.quarkus.hibernate.reactive.panache.common.runtime.WithSessionInterceptor;
import io.quarkus.hibernate.reactive.panache.common.runtime.WithSessionOnDemandInterceptor;
import io.smallrye.mutiny.Uni;

@BuildSteps(onlyIf = HibernateOrmEnabled.class)
public final class PanacheJpaCommonResourceProcessor {

private static final Logger LOG = Logger.getLogger(PanacheJpaCommonResourceProcessor.class);

private static final DotName DOTNAME_NAMED_QUERY = DotName.createSimple(NamedQuery.class.getName());
private static final DotName DOTNAME_NAMED_QUERIES = DotName.createSimple(NamedQueries.class.getName());
private static final String TEST_REACTIVE_TRANSACTION = "io.quarkus.test.TestReactiveTransaction";

private static final DotName REACTIVE_TRANSACTIONAL = DotName.createSimple(ReactiveTransactional.class.getName());
private static final DotName WITH_SESSION_ON_DEMAND = DotName.createSimple(WithSessionOnDemand.class.getName());
private static final DotName WITH_SESSION = DotName.createSimple(WithSession.class.getName());
private static final DotName WITH_TRANSACTION = DotName.createSimple(WithTransaction.class.getName());
private static final DotName UNI = DotName.createSimple(Uni.class.getName());
private static final DotName PANACHE_ENTITY_BASE = DotName
.createSimple("io.quarkus.hibernate.reactive.panache.PanacheEntityBase");
private static final DotName PANACHE_ENTITY = DotName.createSimple("io.quarkus.hibernate.reactive.panache.PanacheEntity");
private static final DotName PANACHE_KOTLIN_ENTITY_BASE = DotName
.createSimple("io.quarkus.hibernate.reactive.panache.kotlin.PanacheEntityBase");
private static final DotName PANACHE_KOTLIN_ENTITY = DotName
.createSimple("io.quarkus.hibernate.reactive.panache.kotlin.PanacheEntity");

@BuildStep(onlyIf = IsTest.class)
void testTx(BuildProducer<GeneratedBeanBuildItem> generatedBeanBuildItemBuildProducer,
BuildProducer<AdditionalBeanBuildItem> additionalBeans) {
Expand Down Expand Up @@ -109,11 +87,12 @@ void registerInterceptors(BuildProducer<AdditionalBeanBuildItem> additionalBeans
@BuildStep
void validateInterceptedMethods(ValidationPhaseBuildItem validationPhase,
BuildProducer<ValidationErrorBuildItem> errors) {
List<DotName> bindings = List.of(REACTIVE_TRANSACTIONAL, WITH_SESSION, WITH_SESSION_ON_DEMAND, WITH_TRANSACTION);
List<DotName> bindings = List.of(DotNames.REACTIVE_TRANSACTIONAL, DotNames.WITH_SESSION,
DotNames.WITH_SESSION_ON_DEMAND, DotNames.WITH_TRANSACTION);
for (BeanInfo bean : validationPhase.getContext().beans().withAroundInvokeInterceptor()) {
for (Entry<MethodInfo, Set<AnnotationInstance>> e : bean.getInterceptedMethodsBindings().entrySet()) {
DotName returnTypeName = e.getKey().returnType().name();
if (returnTypeName.equals(UNI)) {
if (returnTypeName.equals(DotNames.UNI)) {
// Method returns Uni - no need to iterate over the bindings
continue;
}
Expand All @@ -132,24 +111,41 @@ void transformResourceMethods(CombinedIndexBuildItem index, Capabilities capabil
DotName.createSimple("jakarta.ws.rs.DELETE"), DotName.createSimple("jakarta.ws.rs.OPTIONS"),
DotName.createSimple("jakarta.ws.rs.PATCH"), DotName.createSimple("jakarta.ws.rs.POST"),
DotName.createSimple("jakarta.ws.rs.PUT"));
List<DotName> bindings = List.of(REACTIVE_TRANSACTIONAL, WITH_SESSION, WITH_SESSION_ON_DEMAND, WITH_TRANSACTION);
List<DotName> bindings = List.of(DotNames.REACTIVE_TRANSACTIONAL, DotNames.WITH_SESSION,
DotNames.WITH_SESSION_ON_DEMAND, DotNames.WITH_TRANSACTION);

// Collect all panache entities
// Collect all Panache entities and repositories
Set<DotName> entities = new HashSet<>();
for (ClassInfo subclass : index.getIndex().getAllKnownSubclasses(PANACHE_ENTITY_BASE)) {
if (!subclass.name().equals(PANACHE_ENTITY)) {
for (ClassInfo subclass : index.getIndex().getAllKnownSubclasses(DotNames.PANACHE_ENTITY_BASE)) {
if (!subclass.name().equals(DotNames.PANACHE_ENTITY)) {
entities.add(subclass.name());
}
}
for (ClassInfo subclass : index.getIndex().getAllKnownImplementors(PANACHE_KOTLIN_ENTITY_BASE)) {
if (!subclass.name().equals(PANACHE_KOTLIN_ENTITY)) {
entities.add(subclass.name());
for (ClassInfo implementor : index.getIndex().getAllKnownImplementors(DotNames.PANACHE_KOTLIN_ENTITY_BASE)) {
if (!implementor.name().equals(DotNames.PANACHE_KOTLIN_ENTITY)) {
entities.add(implementor.name());
}
}
Set<DotName> repos = new HashSet<>();
for (ClassInfo subclass : index.getIndex().getAllKnownImplementors(DotNames.PANACHE_REPOSITORY_BASE)) {
if (!subclass.name().equals(DotNames.PANACHE_REPOSITORY)) {
repos.add(subclass.name());
}
}
Set<DotName> entityUsers = new HashSet<>();
for (ClassInfo implementor : index.getIndex().getAllKnownImplementors(DotNames.PANACHE_KOTLIN_REPOSITORY_BASE)) {
if (!implementor.name().equals(DotNames.PANACHE_KOTLIN_REPOSITORY)) {
repos.add(implementor.name());
}
}
Set<DotName> entityReposUsers = new HashSet<>();
for (DotName entity : entities) {
for (ClassInfo user : index.getIndex().getKnownUsers(entity)) {
entityUsers.add(user.name());
entityReposUsers.add(user.name());
}
}
for (DotName repo : repos) {
for (ClassInfo user : index.getIndex().getKnownUsers(repo)) {
entityReposUsers.add(user.name());
}
}

Expand All @@ -166,8 +162,8 @@ public void transform(TransformationContext context) {
if (method.isSynthetic()
|| Modifier.isStatic(method.flags())
|| method.declaringClass().isInterface()
|| !method.returnType().name().equals(UNI)
|| !entityUsers.contains(method.declaringClass().name())
|| !method.returnType().name().equals(DotNames.UNI)
|| !entityReposUsers.contains(method.declaringClass().name())
|| !Annotations.containsAny(annotations, designators)
|| Annotations.containsAny(annotations, bindings)) {
return;
Expand All @@ -176,10 +172,10 @@ public void transform(TransformationContext context) {
// - is not static
// - is not synthetic
// - returns Uni
// - is declared in a class that uses a panache entity
// - is declared in a class that uses a panache entity/repository
// - is annotated with @GET, @POST, @PUT, @DELETE ,@PATCH ,@HEAD or @OPTIONS
// - is not annotated with @ReactiveTransactional, @WithSession, @WithSessionOnDemand, or @WithTransaction
context.transform().add(WITH_SESSION_ON_DEMAND).done();
context.transform().add(DotNames.WITH_SESSION_ON_DEMAND).done();
}
}));
}
Expand Down Expand Up @@ -221,15 +217,15 @@ private void lookupNamedQueries(CombinedIndexBuildItem index, DotName name, Map<
return;
}

List<AnnotationInstance> namedQueryInstances = classInfo.annotationsMap().get(DOTNAME_NAMED_QUERY);
List<AnnotationInstance> namedQueryInstances = classInfo.annotationsMap().get(DotNames.DOTNAME_NAMED_QUERY);
if (namedQueryInstances != null) {
for (AnnotationInstance namedQueryInstance : namedQueryInstances) {
namedQueries.put(namedQueryInstance.value("name").asString(),
namedQueryInstance.value("query").asString());
}
}

List<AnnotationInstance> namedQueriesInstances = classInfo.annotationsMap().get(DOTNAME_NAMED_QUERIES);
List<AnnotationInstance> namedQueriesInstances = classInfo.annotationsMap().get(DotNames.DOTNAME_NAMED_QUERIES);
if (namedQueriesInstances != null) {
for (AnnotationInstance namedQueriesInstance : namedQueriesInstances) {
AnnotationValue value = namedQueriesInstance.value();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,10 @@ void findEntityResources(CombinedIndexBuildItem indexBuildItem,
ResourceImplementor resourceImplementor = new ResourceImplementor(new EntityClassHelper(index));
ClassOutput classOutput = new GeneratedBeanGizmoAdaptor(implementationsProducer);

for (ClassInfo classInfo : index.getKnownDirectImplementors(PANACHE_ENTITY_RESOURCE_INTERFACE)) {
validateResource(index, classInfo);
for (ClassInfo resourceInterface : index.getKnownDirectImplementors(PANACHE_ENTITY_RESOURCE_INTERFACE)) {
validateResource(index, resourceInterface);

List<Type> generics = getGenericTypes(classInfo);
String resourceInterface = classInfo.name().toString();
List<Type> generics = getGenericTypes(resourceInterface);
String entityType = generics.get(0).name().toString();
String idType = generics.get(1).name().toString();

Expand Down Expand Up @@ -105,11 +104,10 @@ void findRepositoryResources(CombinedIndexBuildItem indexBuildItem,
ResourceImplementor resourceImplementor = new ResourceImplementor(new EntityClassHelper(index));
ClassOutput classOutput = new GeneratedBeanGizmoAdaptor(implementationsProducer);

for (ClassInfo classInfo : index.getKnownDirectImplementors(PANACHE_REPOSITORY_RESOURCE_INTERFACE)) {
validateResource(index, classInfo);
for (ClassInfo resourceInterface : index.getKnownDirectImplementors(PANACHE_REPOSITORY_RESOURCE_INTERFACE)) {
validateResource(index, resourceInterface);

List<Type> generics = getGenericTypes(classInfo);
String resourceInterface = classInfo.name().toString();
List<Type> generics = getGenericTypes(resourceInterface);
String repositoryClassName = generics.get(0).name().toString();
String entityType = generics.get(1).name().toString();
String idType = generics.get(2).name().toString();
Expand Down
Loading

0 comments on commit e8ce818

Please sign in to comment.