Skip to content

Commit

Permalink
Merge pull request #19801 from geoand/#19771
Browse files Browse the repository at this point in the history
Port rest-data-panache to RESTEasy Reactive
  • Loading branch information
geoand authored Sep 2, 2021
2 parents ab9f978 + 149bf56 commit 006d2ec
Show file tree
Hide file tree
Showing 41 changed files with 555 additions and 107 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ public interface Capability {

String RESTEASY_MUTINY = RESTEASY + ".mutiny";
String RESTEASY_REACTIVE = RESTEASY + ".reactive";
String RESTEASY_REACTIVE_JSON = RESTEASY_REACTIVE + ".json";
String RESTEASY_REACTIVE_JSON_JACKSON = RESTEASY_REACTIVE_JSON + ".jackson";
String RESTEASY_REACTIVE_JSON_JSONB = RESTEASY_REACTIVE_JSON + ".jsonb";

String JWT = QUARKUS_PREFIX + "jwt";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
import io.quarkus.deployment.builditem.HotDeploymentWatchedFileBuildItem;
import io.quarkus.deployment.builditem.ShutdownContextBuildItem;
import io.quarkus.deployment.builditem.nativeimage.NativeImageConfigBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveFieldBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveMethodBuildItem;
import io.quarkus.deployment.logging.LogCleanupFilterBuildItem;
Expand Down Expand Up @@ -349,9 +350,13 @@ NativeImageConfigBuildItem nativeImageConfig() {
}

@BuildStep
ExceptionMapperBuildItem mapper() {
return new ExceptionMapperBuildItem(ResteasyReactiveViolationExceptionMapper.class.getName(),
ValidationException.class.getName(), Priorities.USER + 1, true);
void exceptionMapper(BuildProducer<ExceptionMapperBuildItem> exceptionMapperProducer,
BuildProducer<ReflectiveClassBuildItem> reflectiveClassProducer) {
exceptionMapperProducer.produce(new ExceptionMapperBuildItem(ResteasyReactiveViolationExceptionMapper.class.getName(),
ValidationException.class.getName(), Priorities.USER + 1, true));
reflectiveClassProducer.produce(
new ReflectiveClassBuildItem(true, true, ResteasyReactiveViolationExceptionMapper.ViolationReport.class,
ResteasyReactiveViolationExceptionMapper.ViolationReport.Violation.class));
}

private static void contributeBuiltinConstraints(Set<String> builtinConstraints,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-jsonb-deployment</artifactId>
<artifactId>quarkus-resteasy-reactive-jsonb-deployment</artifactId>
<scope>test</scope>
</dependency>
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import java.lang.reflect.Modifier;
import java.util.List;

import javax.ws.rs.Priorities;

import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;
import org.jboss.jandex.IndexView;
Expand All @@ -23,9 +25,10 @@
import io.quarkus.hibernate.orm.rest.data.panache.PanacheRepositoryResource;
import io.quarkus.hibernate.orm.rest.data.panache.runtime.RestDataPanacheExceptionMapper;
import io.quarkus.hibernate.orm.rest.data.panache.runtime.jta.TransactionalUpdateExecutor;
import io.quarkus.rest.data.panache.RestDataPanacheException;
import io.quarkus.rest.data.panache.deployment.ResourceMetadata;
import io.quarkus.rest.data.panache.deployment.RestDataResourceBuildItem;
import io.quarkus.resteasy.common.spi.ResteasyJaxrsProviderBuildItem;
import io.quarkus.resteasy.reactive.spi.ExceptionMapperBuildItem;

class HibernateOrmPanacheRestProcessor {

Expand All @@ -41,8 +44,9 @@ FeatureBuildItem feature() {
}

@BuildStep
ResteasyJaxrsProviderBuildItem registerRestDataPanacheExceptionMapper() {
return new ResteasyJaxrsProviderBuildItem(RestDataPanacheExceptionMapper.class.getName());
ExceptionMapperBuildItem registerRestDataPanacheExceptionMapper() {
return new ExceptionMapperBuildItem(RestDataPanacheExceptionMapper.class.getName(),
RestDataPanacheException.class.getName(), Priorities.USER + 100, false);
}

@BuildStep
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-orm-panache</artifactId>
</dependency>
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import java.lang.reflect.Modifier;
import java.util.List;

import javax.ws.rs.Priorities;

import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;
import org.jboss.jandex.IndexView;
Expand All @@ -27,9 +29,10 @@
import io.quarkus.mongodb.rest.data.panache.PanacheMongoRepositoryResource;
import io.quarkus.mongodb.rest.data.panache.runtime.NoopUpdateExecutor;
import io.quarkus.mongodb.rest.data.panache.runtime.RestDataPanacheExceptionMapper;
import io.quarkus.rest.data.panache.RestDataPanacheException;
import io.quarkus.rest.data.panache.deployment.ResourceMetadata;
import io.quarkus.rest.data.panache.deployment.RestDataResourceBuildItem;
import io.quarkus.resteasy.common.spi.ResteasyJaxrsProviderBuildItem;
import io.quarkus.resteasy.reactive.spi.ExceptionMapperBuildItem;

class MongoPanacheRestProcessor {

Expand All @@ -45,8 +48,9 @@ FeatureBuildItem feature() {
}

@BuildStep
ResteasyJaxrsProviderBuildItem registerRestDataPanacheExceptionMapper() {
return new ResteasyJaxrsProviderBuildItem(RestDataPanacheExceptionMapper.class.getName());
ExceptionMapperBuildItem registerRestDataPanacheExceptionMapper() {
return new ExceptionMapperBuildItem(RestDataPanacheExceptionMapper.class.getName(),
RestDataPanacheException.class.getName(), Priorities.USER + 100, false);
}

@BuildStep
Expand Down
4 changes: 2 additions & 2 deletions extensions/panache/rest-data-panache/deployment/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-deployment</artifactId>
<artifactId>quarkus-resteasy-reactive-links-deployment</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
Expand Down Expand Up @@ -66,4 +66,4 @@
</plugin>
</plugins>
</build>
</project>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,12 @@
import java.util.Arrays;
import java.util.List;

import org.jboss.resteasy.links.impl.EL;

import io.quarkus.arc.deployment.GeneratedBeanBuildItem;
import io.quarkus.arc.deployment.GeneratedBeanGizmoAdaptor;
import io.quarkus.deployment.Capabilities;
import io.quarkus.deployment.Capability;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.builditem.CombinedIndexBuildItem;
import io.quarkus.deployment.builditem.nativeimage.RuntimeInitializedClassBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
import io.quarkus.gizmo.ClassOutput;
import io.quarkus.jackson.spi.JacksonModuleBuildItem;
import io.quarkus.jsonb.spi.JsonbSerializerBuildItem;
Expand All @@ -28,14 +24,21 @@
import io.quarkus.rest.data.panache.runtime.hal.HalLink;
import io.quarkus.rest.data.panache.runtime.hal.HalLinkJacksonSerializer;
import io.quarkus.rest.data.panache.runtime.hal.HalLinkJsonbSerializer;
import io.quarkus.resteasy.reactive.server.deployment.GeneratedJaxRsResourceGizmoAdaptor;
import io.quarkus.resteasy.reactive.spi.GeneratedJaxRsResourceBuildItem;

public class RestDataProcessor {

@BuildStep
ReflectiveClassBuildItem registerReflection() {
return new ReflectiveClassBuildItem(true, true, HalLink.class);
}

@BuildStep
void implementResources(CombinedIndexBuildItem index, List<RestDataResourceBuildItem> resourceBuildItems,
List<ResourcePropertiesBuildItem> resourcePropertiesBuildItems, Capabilities capabilities,
BuildProducer<GeneratedBeanBuildItem> implementationsProducer) {
ClassOutput classOutput = new GeneratedBeanGizmoAdaptor(implementationsProducer);
BuildProducer<GeneratedJaxRsResourceBuildItem> implementationsProducer) {
ClassOutput classOutput = new GeneratedJaxRsResourceGizmoAdaptor(implementationsProducer);
JaxRsResourceImplementor jaxRsResourceImplementor = new JaxRsResourceImplementor(hasValidatorCapability(capabilities));
ResourcePropertiesProvider resourcePropertiesProvider = new ResourcePropertiesProvider(index.getIndex());

Expand Down Expand Up @@ -71,11 +74,6 @@ JsonbSerializerBuildItem registerJsonbSerializers() {
HalLinkJsonbSerializer.class.getName()));
}

@BuildStep
RuntimeInitializedClassBuildItem el() {
return new RuntimeInitializedClassBuildItem(EL.class.getCanonicalName());
}

private ResourceProperties getResourceProperties(ResourcePropertiesProvider resourcePropertiesProvider,
ResourceMetadata resourceMetadata, List<ResourcePropertiesBuildItem> resourcePropertiesBuildItems) {
for (ResourcePropertiesBuildItem resourcePropertiesBuildItem : resourcePropertiesBuildItems) {
Expand All @@ -92,7 +90,7 @@ private boolean hasValidatorCapability(Capabilities capabilities) {
}

private boolean hasHalCapability(Capabilities capabilities) {
return capabilities.isPresent(Capability.RESTEASY_JSON_JSONB)
|| capabilities.isPresent(Capability.RESTEASY_JSON_JACKSON);
return capabilities.isPresent(Capability.RESTEASY_REACTIVE_JSON_JSONB)
|| capabilities.isPresent(Capability.RESTEASY_REACTIVE_JSON_JACKSON);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;

import org.jboss.resteasy.links.LinkResource;
import org.jboss.logging.Logger;

import io.quarkus.gizmo.AnnotatedElement;
import io.quarkus.gizmo.AnnotationCreator;
Expand All @@ -25,12 +25,15 @@
import io.quarkus.rest.data.panache.deployment.ResourceMetadata;
import io.quarkus.rest.data.panache.deployment.properties.ResourceProperties;
import io.quarkus.rest.data.panache.runtime.sort.SortQueryParamValidator;
import io.quarkus.resteasy.reactive.links.RestLink;

/**
* A standard JAX-RS method implementor.
*/
public abstract class StandardMethodImplementor implements MethodImplementor {

private static final Logger LOGGER = Logger.getLogger(StandardMethodImplementor.class);

/**
* Implement exposed JAX-RS method.
*/
Expand Down Expand Up @@ -78,9 +81,15 @@ protected void addDeleteAnnotation(AnnotatedElement element) {
}

protected void addLinksAnnotation(AnnotatedElement element, String entityClassName, String rel) {
AnnotationCreator linkResource = element.addAnnotation(LinkResource.class);
linkResource.addValue("entityClassName", entityClassName);
linkResource.addValue("rel", rel);
AnnotationCreator linkResource = element.addAnnotation(RestLink.class);
Class<?> entityClass;
try {
entityClass = Thread.currentThread().getContextClassLoader().loadClass(entityClassName);
linkResource.addValue("entityType", entityClass);
linkResource.addValue("rel", rel);
} catch (ClassNotFoundException e) {
LOGGER.error("Unable to create links for entity: '" + entityClassName + "'", e);
}
}

protected void addPathAnnotation(AnnotatedElement element, String value) {
Expand Down
12 changes: 1 addition & 11 deletions extensions/panache/rest-data-panache/runtime/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,7 @@
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-links</artifactId>
<exclusions>
<exclusion>
<groupId>jakarta.activation</groupId>
<artifactId>jakarta.activation-api</artifactId>
</exclusion>
</exclusions>
<artifactId>quarkus-resteasy-reactive-links</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,22 +32,19 @@ public void serialize(HalEntityWrapper wrapper, JsonGenerator generator, Seriali
for (BeanPropertyDefinition property : getPropertyDefinitions(serializers, wrapper.getEntity().getClass())) {
AnnotatedMember accessor = property.getAccessor();
if (accessor != null) {
writeValue(property.getName(), accessor.getValue(wrapper.getEntity()), generator);
Object value = accessor.getValue(wrapper.getEntity());
generator.writeFieldName(property.getName());
if (value == null) {
generator.writeNull();
} else {
serializers.findValueSerializer(value.getClass()).serialize(value, generator, serializers);
}
}
}
writeLinks(wrapper.getEntity(), generator);
generator.writeEndObject();
}

private void writeValue(String name, Object value, JsonGenerator generator) throws IOException {
generator.writeFieldName(name);
if (value == null) {
generator.writeNull();
} else {
generator.writeObject(value);
}
}

private void writeLinks(Object entity, JsonGenerator generator) throws IOException {
Map<String, HalLink> links = linksExtractor.getLinks(entity);
generator.writeFieldName("_links");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,41 +1,51 @@
package io.quarkus.rest.data.panache.runtime.resource;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import org.jboss.resteasy.links.LinksProvider;
import org.jboss.resteasy.links.RESTServiceDiscovery;
import javax.ws.rs.core.Link;

import io.quarkus.arc.Arc;
import io.quarkus.arc.InstanceHandle;
import io.quarkus.resteasy.reactive.links.RestLinksProvider;

public final class ResourceLinksProvider {

private static final String SELF_REF = "self";

public Map<String, String> getClassLinks(Class<?> className) {
RESTServiceDiscovery links = LinksProvider
.getClassLinksProvider()
.getLinks(className, Thread.currentThread().getContextClassLoader());
return linksToMap(links);
return linksToMap(restLinksProvider().getTypeLinks(className));
}

public Map<String, String> getInstanceLinks(Object instance) {
RESTServiceDiscovery links = LinksProvider
.getObjectLinksProvider()
.getLinks(instance, Thread.currentThread().getContextClassLoader());
return linksToMap(links);
return linksToMap(restLinksProvider().getInstanceLinks(instance));
}

public String getSelfLink(Object instance) {
RESTServiceDiscovery.AtomLink link = LinksProvider.getObjectLinksProvider()
.getLinks(instance, Thread.currentThread().getContextClassLoader())
.getLinkForRel(SELF_REF);
return link == null ? null : link.getHref();
Collection<Link> links = restLinksProvider().getInstanceLinks(instance);
for (Link link : links) {
if (SELF_REF.equals(link.getRel())) {
return link.getUri().toString();
}
}
return null;
}

private RestLinksProvider restLinksProvider() {
InstanceHandle<RestLinksProvider> instance = Arc.container().instance(RestLinksProvider.class);
if (instance.isAvailable()) {
return instance.get();
}
throw new IllegalStateException("Invalid use of '" + this.getClass().getName()
+ "'. No request scope bean found for type '" + ResourceLinksProvider.class.getName() + "'");
}

private Map<String, String> linksToMap(RESTServiceDiscovery serviceDiscovery) {
Map<String, String> links = new HashMap<>(serviceDiscovery.size());
for (RESTServiceDiscovery.AtomLink atomLink : serviceDiscovery) {
links.put(atomLink.getRel(), atomLink.getHref());
private Map<String, String> linksToMap(Collection<Link> links) {
Map<String, String> result = new HashMap<>();
for (Link link : links) {
result.put(link.getRel(), link.getUri().toString());
}
return links;
return result;
}
}
Loading

0 comments on commit 006d2ec

Please sign in to comment.