Skip to content

Commit

Permalink
Fix Resource Class reflection registration when custom Writer is used
Browse files Browse the repository at this point in the history
  • Loading branch information
geoand committed May 10, 2023
1 parent 5611919 commit 158d4c6
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 12 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.quarkus.resteasy.reactive.server.deployment;

import static org.jboss.resteasy.reactive.server.processor.util.ResteasyReactiveServerDotNames.SERVER_MESSAGE_BODY_READER;
import static org.jboss.resteasy.reactive.server.processor.util.ResteasyReactiveServerDotNames.SERVER_MESSAGE_BODY_WRITER;

import java.lang.annotation.Annotation;
import java.util.List;
Expand Down Expand Up @@ -156,7 +157,7 @@ protected void handleAdditionalMethodProcessing(ServerResourceMethod method, Cla

@Override
public boolean additionalRegisterClassForReflectionCheck(ResourceMethodCallbackEntry entry) {
return checkBodyParameterMessageBodyReader(entry);
return checkBodyParameterMessageBodyReader(entry) || checkReturnTypeMessageBodyWriter(entry);
}

/**
Expand Down Expand Up @@ -194,12 +195,48 @@ private boolean checkBodyParameterMessageBodyReader(ResourceMethodCallbackEntry
return false;
}

/**
* Check whether the Resource Method has a return type for which there exists a matching
* {@link jakarta.ws.rs.ext.MessageBodyWriter}
* that is not a {@link org.jboss.resteasy.reactive.server.spi.ServerMessageBodyWriter}.
* In this case the Resource Class needs to be registered for reflection because the
* {@link jakarta.ws.rs.ext.MessageBodyWriter#isWriteable(Class, java.lang.reflect.Type, Annotation[], MediaType)}
* method expects to be passed the method annotations.
*/
private boolean checkReturnTypeMessageBodyWriter(ResourceMethodCallbackEntry entry) {
Type returnType = entry.getMethodInfo().returnType();
String returnTypeName;
switch (returnType.kind()) {
case CLASS:
returnTypeName = returnType.asClassType().name().toString();
break;
case PARAMETERIZED_TYPE:
returnTypeName = returnType.asParameterizedType().name().toString();
break;
default:
returnTypeName = null;
}
if (returnTypeName == null) {
return false;
}

List<ScannedSerializer> writers = getSerializerScanningResult().getWriters();

for (ScannedSerializer writer : writers) {
if (isSubclassOf(returnTypeName, writer.getHandledClassName())
&& !isServerMessageBodyWriter(writer.getClassInfo())) {
return true;
}
}
return false;
}

private boolean isSubclassOf(String className, String parentName) {
if (className.equals(parentName)) {
return true;
}
ClassInfo classByName = index.getClassByName(className);
if (classByName == null) {
if ((classByName == null) || (classByName.superName() == null)) {
return false;
}
try {
Expand All @@ -210,8 +247,12 @@ private boolean isSubclassOf(String className, String parentName) {
}
}

private boolean isServerMessageBodyReader(ClassInfo readerClassInfo) {
return index.getAllKnownImplementors(SERVER_MESSAGE_BODY_READER).contains(readerClassInfo);
private boolean isServerMessageBodyReader(ClassInfo classInfo) {
return index.getAllKnownImplementors(SERVER_MESSAGE_BODY_READER).contains(classInfo);
}

private boolean isServerMessageBodyWriter(ClassInfo classInfo) {
return index.getAllKnownImplementors(SERVER_MESSAGE_BODY_WRITER).contains(classInfo);
}

private void warnAboutMissingJsonProviderIfNeeded(ServerResourceMethod method, MethodInfo info) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package io.quarkus.it.envers;

public class Message2 {

private String data;

public Message2() {
}

public Message2(String data) {
this.data = data;
}

public String getData() {
return data;
}

public void setData(String data) {
this.data = data;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package io.quarkus.it.envers;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;

import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.MultivaluedMap;
import jakarta.ws.rs.ext.MessageBodyReader;
import jakarta.ws.rs.ext.MessageBodyWriter;
import jakarta.ws.rs.ext.Provider;

@Provider
@Consumes(MediaType.WILDCARD)
@Produces(MediaType.WILDCARD)
public class Message2Provider implements MessageBodyReader<Message2>, MessageBodyWriter<Message2> {

@Override
public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return Message2.class.isAssignableFrom(type);
}

@Override
public Message2 readFrom(Class<Message2> type, Type genericType, Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, String> httpHeaders, InputStream entityStream) throws IOException, WebApplicationException {
return new Message2("in");
}

@Override
public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return Message2.class.isAssignableFrom(type);
}

@Override
public void writeTo(Message2 event, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException {
String data = "out";
if (annotations != null) {
for (Annotation annotation : annotations) {
if (annotation.annotationType().equals(CustomOutput.class)) {
data = ((CustomOutput) annotation).value();
break;
}
}
}
entityStream.write(String.format("{\"data\": \"%s\"}", data).getBytes(StandardCharsets.UTF_8));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package io.quarkus.it.envers;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

@Path("output2")
public class Output2Resource {

@GET
@Produces(MediaType.APPLICATION_JSON)
public Message2 out() {
return new Message2("test");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

import org.jboss.resteasy.reactive.RestStreamElementType;
Expand All @@ -14,12 +13,6 @@
@Path("output")
public class OutputResource {

@GET
@Produces(MediaType.APPLICATION_JSON)
public Message out() {
return new Message("test");
}

@GET
@RestStreamElementType(MediaType.APPLICATION_JSON)
@CustomOutput("dummy")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class OutputResourceTest {
void test() {
given().accept(ContentType.JSON)
.when()
.get(RESOURCE_PATH)
.get(RESOURCE_PATH + "2")
.then()
.statusCode(200)
.body("data", equalTo("out"));
Expand Down

0 comments on commit 158d4c6

Please sign in to comment.