forked from quarkusio/quarkus
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Resteasy Reactive - Avoid NPE when using runtime converters
The NPE happens here: https://github.com/quarkusio/quarkus/blob/e6ffbe43243f9c852c61aafc307515be0915c6c8/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/ClassInjectorTransformer.java#L222. However, it's expected that the delegated converter is null when there are runtime converts. See related lines: https://github.com/quarkusio/quarkus/blob/bd87966540990fa68ec3769e22e67df1854b08a5/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/QuarkusServerEndpointIndexer.java#L169 and https://github.com/quarkusio/quarkus/blob/bd87966540990fa68ec3769e22e67df1854b08a5/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/QuarkusServerEndpointIndexer.java#L173. Therefore, as It's possible that the delegate is null when there are runtime converters, we check whether the delegate is null and if it is, we don't use it to avoid the NPE. The rest works as expected as proven in the test. Fixes quarkusio#21664
- Loading branch information
Showing
2 changed files
with
102 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
98 changes: 98 additions & 0 deletions
98
...va/io/quarkus/resteasy/reactive/server/test/beanparam/CustomConverterInBeanParamTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
package io.quarkus.resteasy.reactive.server.test.beanparam; | ||
|
||
import static org.hamcrest.CoreMatchers.equalTo; | ||
|
||
import java.lang.annotation.Annotation; | ||
import java.lang.reflect.Type; | ||
import java.time.LocalDateTime; | ||
import java.time.format.DateTimeFormatter; | ||
|
||
import javax.ws.rs.BeanParam; | ||
import javax.ws.rs.GET; | ||
import javax.ws.rs.Path; | ||
import javax.ws.rs.Produces; | ||
import javax.ws.rs.QueryParam; | ||
import javax.ws.rs.core.MediaType; | ||
import javax.ws.rs.ext.ParamConverter; | ||
import javax.ws.rs.ext.ParamConverterProvider; | ||
import javax.ws.rs.ext.Provider; | ||
|
||
import org.jboss.shrinkwrap.api.ShrinkWrap; | ||
import org.jboss.shrinkwrap.api.spec.JavaArchive; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.api.extension.RegisterExtension; | ||
|
||
import io.quarkus.test.QuarkusUnitTest; | ||
import io.restassured.RestAssured; | ||
|
||
public class CustomConverterInBeanParamTest { | ||
|
||
@RegisterExtension | ||
static QuarkusUnitTest test = new QuarkusUnitTest() | ||
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) | ||
.addClasses(SearchResource.class, FilterData.class, | ||
JavaTimeParamConverterProvider.class, LocalDateTimeParamConverter.class)); | ||
|
||
@Test | ||
void shouldCustomConvertBeUsedForLocalDateTimeInFilterData() { | ||
LocalDateTime since = LocalDateTime.now(); | ||
String request = since.format(DateTimeFormatter.ISO_DATE_TIME); | ||
String expected = since.plusYears(1).format(DateTimeFormatter.ISO_DATE_TIME); | ||
|
||
RestAssured.get("/search?since=" + request) | ||
.then() | ||
.statusCode(200) | ||
.body(equalTo("Got: " + expected)); | ||
} | ||
|
||
@Path("/search") | ||
public static class SearchResource { | ||
|
||
@GET | ||
@Produces(MediaType.TEXT_PLAIN) | ||
public String search(@BeanParam FilterData filter) { | ||
return "Got: " + filter.getSince().plusYears(1).format(DateTimeFormatter.ISO_DATE_TIME); | ||
} | ||
} | ||
|
||
public static class FilterData { | ||
|
||
@QueryParam("since") | ||
private LocalDateTime since; | ||
|
||
public LocalDateTime getSince() { | ||
return since; | ||
} | ||
|
||
public void setSince(LocalDateTime since) { | ||
this.since = since; | ||
} | ||
} | ||
|
||
public static class LocalDateTimeParamConverter implements ParamConverter<LocalDateTime> { | ||
|
||
@Override | ||
public LocalDateTime fromString(String value) { | ||
return LocalDateTime.parse(value, DateTimeFormatter.ISO_DATE_TIME); | ||
} | ||
|
||
@Override | ||
public String toString(LocalDateTime value) { | ||
return value.format(DateTimeFormatter.ISO_DATE_TIME); | ||
} | ||
} | ||
|
||
@Provider | ||
public static class JavaTimeParamConverterProvider implements ParamConverterProvider { | ||
|
||
@Override | ||
public <T> ParamConverter<T> getConverter(Class<T> rawType, Type genericType, Annotation[] annotations) { | ||
if (rawType == LocalDateTime.class) { | ||
return (ParamConverter<T>) new LocalDateTimeParamConverter(); | ||
} | ||
|
||
return null; | ||
} | ||
|
||
} | ||
} |