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

Apply some housekeeping to RESTEasy Reactive #32224

Merged
merged 2 commits into from
Mar 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -645,10 +645,10 @@ private org.jboss.resteasy.reactive.common.ResteasyReactiveConfig createRestReac
Config mpConfig = ConfigProvider.getConfig();

return new org.jboss.resteasy.reactive.common.ResteasyReactiveConfig(
getEffectivePropertyValue("input-buffer-size", config.inputBufferSize.asLongValue(), Long.class, mpConfig),
getEffectivePropertyValue("output-buffer-size", config.outputBufferSize, Integer.class, mpConfig),
getEffectivePropertyValue("single-default-produces", config.singleDefaultProduces, Boolean.class, mpConfig),
getEffectivePropertyValue("default-produces", config.defaultProduces, Boolean.class, mpConfig));
getEffectivePropertyValue("input-buffer-size", config.inputBufferSize().asLongValue(), Long.class, mpConfig),
getEffectivePropertyValue("output-buffer-size", config.outputBufferSize(), Integer.class, mpConfig),
getEffectivePropertyValue("single-default-produces", config.singleDefaultProduces(), Boolean.class, mpConfig),
getEffectivePropertyValue("default-produces", config.defaultProduces(), Boolean.class, mpConfig));
}

private <T> T getEffectivePropertyValue(String legacyPropertyName, T newPropertyValue, Class<T> propertyType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ ApplicationResultBuildItem handleApplication(CombinedIndexBuildItem combinedInde
ResteasyReactiveConfig config) {
ApplicationScanningResult result = ResteasyReactiveScanner
.scanForApplicationClass(combinedIndexBuildItem.getComputingIndex(),
config.buildTimeConditionAware ? getExcludedClasses(buildTimeConditions) : Collections.emptySet());
config.buildTimeConditionAware() ? getExcludedClasses(buildTimeConditions) : Collections.emptySet());
if (result.getSelectedAppClass() != null) {
reflectiveClass.produce(ReflectiveClassBuildItem.builder(result.getSelectedAppClass().name().toString())
.build());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,59 +1,61 @@
package io.quarkus.resteasy.reactive.common.runtime;

import io.quarkus.runtime.annotations.ConfigItem;
import io.quarkus.runtime.annotations.ConfigPhase;
import io.quarkus.runtime.annotations.ConfigRoot;
import io.quarkus.runtime.configuration.MemorySize;
import io.smallrye.common.annotation.Experimental;
import io.smallrye.config.ConfigMapping;
import io.smallrye.config.WithDefault;

@ConfigRoot(phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED, name = "resteasy-reactive")
public class ResteasyReactiveConfig {
@ConfigMapping(prefix = "quarkus.resteasy-reactive")
@ConfigRoot(phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED)
public interface ResteasyReactiveConfig {

/**
* The amount of memory that can be used to buffer input before switching to
* blocking IO.
*/
@ConfigItem(defaultValue = "10k")
public MemorySize inputBufferSize;
@WithDefault("10k")
MemorySize inputBufferSize();

/**
* The size of the output stream response buffer. If a response is larger than this and no content-length
* is provided then the request will be chunked.
*
* Larger values may give slight performance increases for large responses, at the expense of more memory usage.
*/
@ConfigItem(defaultValue = "8191")
public int outputBufferSize;
@WithDefault("8191")
int outputBufferSize();

/**
* By default, we assume a default produced media type of "text/plain"
* for String endpoint return types. If this is disabled, the default
* produced media type will be "[text/plain, *&sol;*]" which is more
* expensive due to negotiation.
*/
@ConfigItem(defaultValue = "true")
public boolean singleDefaultProduces;
@WithDefault("true")
boolean singleDefaultProduces();

/**
* When one of the quarkus-resteasy-reactive-jackson or quarkus-resteasy-reactive-jsonb extension are active
* and the result type of an endpoint is an application class or one of {@code Collection}, {@code List}, {@code Set} or
* {@code Map},
* we assume the default return type is "application/json" if this configuration is enabled.
*/
@ConfigItem(defaultValue = "true")
@WithDefault("true")
@Experimental("This flag has a high probability of going away in the future")
public boolean defaultProduces;
boolean defaultProduces();

/**
* Whether annotations such `@IfBuildTimeProfile`, `@IfBuildTimeProperty` and friends will be taken
* into account when used on JAX-RS classes.
*/
@ConfigItem(defaultValue = "true")
public boolean buildTimeConditionAware;
@WithDefault("true")
boolean buildTimeConditionAware();

/**
* Whether duplicate endpoints should trigger error at startup
*/
@ConfigItem(defaultValue = "true")
public boolean failOnDuplicate;
@WithDefault("true")
boolean failOnDuplicate();
}
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,6 @@
import io.quarkus.arc.deployment.GeneratedBeanBuildItem;
import io.quarkus.arc.deployment.UnremovableBeanBuildItem;
import io.quarkus.arc.runtime.BeanContainer;
import io.quarkus.arc.runtime.ClientProxyUnwrapper;
import io.quarkus.deployment.Capabilities;
import io.quarkus.deployment.Capability;
import io.quarkus.deployment.Feature;
Expand Down Expand Up @@ -1177,7 +1176,7 @@ public void setupDeployment(BeanContainerBuildItem beanContainerBuildItem,
BeanFactory<ResteasyReactiveInitialiser> initClassFactory = recorder.factory(QUARKUS_INIT_CLASS,
beanContainerBuildItem.getValue());

String applicationPath = determineApplicationPath(appResult, getAppPath(serverConfig.path));
String applicationPath = determineApplicationPath(appResult, getAppPath(serverConfig.path()));
// spec allows the path contain encoded characters
if ((applicationPath != null) && applicationPath.contains("%")) {
applicationPath = Encode.decodePath(applicationPath);
Expand All @@ -1194,7 +1193,7 @@ public void setupDeployment(BeanContainerBuildItem beanContainerBuildItem,
.setExceptionMapping(exceptionMapping)
.setCtxResolvers(contextResolvers)
.setFeatures(feats)
.setClientProxyUnwrapper(new ClientProxyUnwrapper())
.setClientProxyUnwrapper(recorder.clientProxyUnwrapper())
.setApplicationSupplier(recorder.handleApplication(applicationClass, singletonClasses.isEmpty()))
.setFactoryCreator(recorder.factoryCreator(beanContainerBuildItem.getValue()))
.setDynamicFeatures(dynamicFeats)
Expand Down Expand Up @@ -1302,7 +1301,7 @@ private void checkForDuplicateEndpoint(ResteasyReactiveConfig config, Map<String
.filter(Objects::nonNull)
.collect(Collectors.joining());
if (message.length() > 0) {
if (config.failOnDuplicate) {
if (config.failOnDuplicate()) {
throw new ConfigurationError(message);
}
log.warn(message);
Expand Down Expand Up @@ -1369,10 +1368,10 @@ private org.jboss.resteasy.reactive.common.ResteasyReactiveConfig createRestReac
Config mpConfig = ConfigProvider.getConfig();

return new org.jboss.resteasy.reactive.common.ResteasyReactiveConfig(
getEffectivePropertyValue("input-buffer-size", config.inputBufferSize.asLongValue(), Long.class, mpConfig),
getEffectivePropertyValue("output-buffer-size", config.outputBufferSize, Integer.class, mpConfig),
getEffectivePropertyValue("single-default-produces", config.singleDefaultProduces, Boolean.class, mpConfig),
getEffectivePropertyValue("default-produces", config.defaultProduces, Boolean.class, mpConfig));
getEffectivePropertyValue("input-buffer-size", config.inputBufferSize().asLongValue(), Long.class, mpConfig),
getEffectivePropertyValue("output-buffer-size", config.outputBufferSize(), Integer.class, mpConfig),
getEffectivePropertyValue("single-default-produces", config.singleDefaultProduces(), Boolean.class, mpConfig),
getEffectivePropertyValue("default-produces", config.defaultProduces(), Boolean.class, mpConfig));
}

private <T> T getEffectivePropertyValue(String legacyPropertyName, T newPropertyValue, Class<T> propertyType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

import java.util.Optional;

import io.quarkus.runtime.annotations.ConfigItem;
import io.quarkus.runtime.annotations.ConfigPhase;
import io.quarkus.runtime.annotations.ConfigRoot;
import io.smallrye.config.ConfigMapping;

@ConfigRoot(name = "resteasy-reactive")
public class ResteasyReactiveServerConfig {
@ConfigMapping(prefix = "quarkus.resteasy-reactive")
@ConfigRoot(phase = ConfigPhase.BUILD_TIME)
public interface ResteasyReactiveServerConfig {

/**
* Set this to define the application path that serves as the base URI for all
Expand All @@ -15,6 +17,5 @@ public class ResteasyReactiveServerConfig {
* <p>
* This value is always resolved relative to {@code quarkus.http.root-path}.
*/
@ConfigItem
Optional<String> path;
Optional<String> path();
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import org.jboss.resteasy.reactive.spi.ThreadSetupAction;

import io.quarkus.arc.Arc;
import io.quarkus.arc.ClientProxy;
import io.quarkus.arc.runtime.BeanContainer;
import io.quarkus.resteasy.reactive.common.runtime.ArcBeanFactory;
import io.quarkus.resteasy.reactive.common.runtime.ArcThreadSetupAction;
Expand Down Expand Up @@ -346,6 +347,10 @@ public BeanFactory<?> apply(Class<?> aClass) {
};
}

public Function<Object, Object> clientProxyUnwrapper() {
return ClientProxy::unwrap;
}

public Supplier<Boolean> disableIfPropertyMatches(String propertyName, String propertyValue, boolean disableIfMissing) {
return new Supplier<>() {
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public Supplier<RuntimeConfiguration> runtimeConfiguration(RuntimeValue<Deployme
RuntimeConfiguration runtimeConfiguration = new DefaultRuntimeConfiguration(httpConf.readTimeout,
httpConf.body.deleteUploadedFilesOnEnd, httpConf.body.uploadsDirectory,
httpConf.body.multipart.fileContentTypes.orElse(null),
runtimeConf.multipart.inputPart.defaultCharset, maxBodySize,
runtimeConf.multipart().inputPart().defaultCharset(), maxBodySize,
httpConf.limits.maxFormAttributeSize.asLongValue());

deployment.getValue().setRuntimeConfiguration(runtimeConfiguration);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,34 @@

import java.nio.charset.Charset;

import io.quarkus.runtime.annotations.ConfigGroup;
import io.quarkus.runtime.annotations.ConfigItem;
import io.quarkus.runtime.annotations.ConfigPhase;
import io.quarkus.runtime.annotations.ConfigRoot;
import io.smallrye.config.ConfigMapping;
import io.smallrye.config.WithDefault;

@ConfigRoot(name = "resteasy-reactive", phase = ConfigPhase.RUN_TIME)
public class ResteasyReactiveServerRuntimeConfig {
@ConfigMapping(prefix = "quarkus.resteasy-reactive")
@ConfigRoot(phase = ConfigPhase.RUN_TIME)
public interface ResteasyReactiveServerRuntimeConfig {

/**
* Input part configuration.
*/
@ConfigItem
public MultipartConfigGroup multipart;
MultipartConfigGroup multipart();

@ConfigGroup
public static class MultipartConfigGroup {
interface MultipartConfigGroup {

/**
* Input part configuration.
*/
@ConfigItem
public InputPartConfigGroup inputPart;
InputPartConfigGroup inputPart();
}

@ConfigGroup
public static class InputPartConfigGroup {
interface InputPartConfigGroup {

/**
* Default charset.
*/
@ConfigItem(defaultValue = "UTF-8")
public Charset defaultCharset;
@WithDefault("UTF-8")
Charset defaultCharset();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@radcortez in a lot of config groups, we have methods like boolean isAnyPropertySet(). By making the @ConfigItem element not mandatory (or even not desirable), my understanding is that we will need a way to mark these methods as ignored from the config (and the doc)?

Moving these methods outside of the interface will be counter productive as I'm pretty sure they will end up not being updated when we add new properties.

And I suppose we will have to make them default methods.

Copy link
Contributor Author

@geoand geoand Mar 29, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't simply making the method default be enough for Smallry Config to ignore them?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no idea thus why I'm asking. But they also need to be ignored in the doc. Not sure if @radcortez already took that into account.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, default methods are ignored :)

I fixed that recently here: #31384

}
}