Skip to content

Commit

Permalink
Fix Jackson serializers generation for interfaces and boxed primitive…
Browse files Browse the repository at this point in the history
… types
  • Loading branch information
mariofusco authored and danielsoro committed Sep 20, 2024
1 parent 973805c commit 6b8a14e
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ private void writeField(ClassInfo classInfo, FieldSpecs fieldSpecs, BytecodeCrea

if (primitiveMethodName != null) {
MethodDescriptor primitiveWriter = MethodDescriptor.ofMethod(JSON_GEN_CLASS_NAME, primitiveMethodName, "void",
typeName);
fieldSpecs.writtenType());
bytecode.invokeVirtualMethod(primitiveWriter, jsonGenerator, arg);
return;
}
Expand Down Expand Up @@ -372,7 +372,7 @@ private void registerTypeToBeGenerated(String typeName) {

private String writeMethodForPrimitiveFields(String typeName) {
return switch (typeName) {
case "java.lang.String" -> "writeString";
case "java.lang.String", "char", "java.lang.Character" -> "writeString";
case "short", "java.lang.Short", "int", "java.lang.Integer", "long", "java.lang.Long", "float",
"java.lang.Float", "double", "java.lang.Double" ->
"writeNumber";
Expand Down Expand Up @@ -590,8 +590,37 @@ boolean hasUnknownAnnotation() {
}

ResultHandle toValueReaderHandle(BytecodeCreator bytecode, ResultHandle valueHandle) {
return methodInfo != null ? bytecode.invokeVirtualMethod(MethodDescriptor.of(methodInfo), valueHandle)
: bytecode.readInstanceField(FieldDescriptor.of(fieldInfo), valueHandle);
ResultHandle handle = accessorHandle(bytecode, valueHandle);

handle = switch (fieldType.name().toString()) {
case "char", "java.lang.Character" -> bytecode.invokeStaticMethod(
MethodDescriptor.ofMethod(Character.class, "toString", String.class, char.class), handle);
default -> handle;
};

return handle;
}

private ResultHandle accessorHandle(BytecodeCreator bytecode, ResultHandle valueHandle) {
if (methodInfo != null) {
if (methodInfo.declaringClass().isInterface()) {
return bytecode.invokeInterfaceMethod(MethodDescriptor.of(methodInfo), valueHandle);
}
return bytecode.invokeVirtualMethod(MethodDescriptor.of(methodInfo), valueHandle);
}
return bytecode.readInstanceField(FieldDescriptor.of(fieldInfo), valueHandle);
}

String writtenType() {
return switch (fieldType.name().toString()) {
case "char", "java.lang.Character" -> "java.lang.String";
case "java.lang.Integer" -> "int";
case "java.lang.Short" -> "short";
case "java.lang.Long" -> "long";
case "java.lang.Double" -> "double";
case "java.lang.Float" -> "float";
default -> fieldType.name().toString();
};
}

private String[] rolesAllowed() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,8 @@ public int getPrivateAge() {
public void setPrivateAge(int privateAge) {
this.privateAge = privateAge;
}

public char getInitial() {
return getPublicName().charAt(0);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package io.quarkus.resteasy.reactive.jackson.deployment.test;

public record ContainerDTO(NestedInterface nestedInterface) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package io.quarkus.resteasy.reactive.jackson.deployment.test;

public interface NestedInterface {

NestedInterface INSTANCE = new NestedInterface() {
@Override
public String getString() {
return "response";
}

@Override
public Integer getInt() {
return 42;
}

@Override
public char getCharacter() {
return 'a';
}
};

String getString();

Integer getInt();

char getCharacter();

}
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,12 @@ public String genericInputTest(DataItem<Item> item) {
return item.getContent().getName();
}

@GET
@Path("/interface")
public ContainerDTO interfaceTest() {
return new ContainerDTO(NestedInterface.INSTANCE);
}

public static class UnquotedFieldsPersonSerialization implements BiFunction<ObjectMapper, Type, ObjectWriter> {

public static final AtomicInteger count = new AtomicInteger();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ public JavaArchive get() {
NoopReaderInterceptor.class, TestIdentityProvider.class, TestIdentityController.class,
AbstractPet.class, Dog.class, Cat.class, Veterinarian.class, AbstractNamedPet.class,
AbstractUnsecuredPet.class, UnsecuredPet.class, SecuredPersonInterface.class, Frog.class,
Pond.class, FrogBodyParts.class, FrogBodyParts.BodyPart.class)
Pond.class, FrogBodyParts.class, FrogBodyParts.BodyPart.class, ContainerDTO.class,
NestedInterface.class)
.addAsResource(new StringAsset("admin-expression=admin\n" +
"user-expression=user\n" +
"birth-date-roles=alice,bob\n"), "application.properties");
Expand Down Expand Up @@ -506,6 +507,18 @@ public void testGenericInput() {
.body(is("foo"));
}

@Test
public void testInterface() {
RestAssured
.with()
.get("/simple/interface")
.then()
.statusCode(200)
.body("nestedInterface.int", Matchers.is(42))
.body("nestedInterface.character", Matchers.is("a"))
.body("nestedInterface.string", Matchers.is("response"));
}

@Test
public void testSecureFieldOnAbstractClass() {
// implementor with / without @SecureField returned
Expand Down Expand Up @@ -602,6 +615,7 @@ private static void testSecuredFieldOnAbstractClass(String catPath, String dogPa
.then()
.statusCode(200)
.body("publicName", Matchers.is("Garfield"))
.body("initial", Matchers.is("G"))
.body("privateName", Matchers.nullValue())
.body("veterinarian.name", Matchers.is("Dolittle"))
.body("veterinarian.title", Matchers.nullValue())
Expand All @@ -625,6 +639,7 @@ private static void testSecuredFieldOnAbstractClass(String catPath, String dogPa
.then()
.statusCode(200)
.body("publicName", Matchers.is("Garfield"))
.body("initial", Matchers.is("G"))
.body("privateName", Matchers.is("Monday"))
.body("privateAge", Matchers.is(4))
.body("veterinarian.name", Matchers.is("Dolittle"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ public JavaArchive get() {
NoopReaderInterceptor.class, TestIdentityProvider.class, TestIdentityController.class,
AbstractPet.class, Dog.class, Cat.class, Veterinarian.class, AbstractNamedPet.class,
AbstractUnsecuredPet.class, UnsecuredPet.class, SecuredPersonInterface.class, Frog.class,
Pond.class, FrogBodyParts.class, FrogBodyParts.BodyPart.class)
Pond.class, FrogBodyParts.class, FrogBodyParts.BodyPart.class, ContainerDTO.class,
NestedInterface.class)
.addAsResource(new StringAsset("admin-expression=admin\n" +
"user-expression=user\n" +
"birth-date-roles=alice,bob\n" +
Expand Down

0 comments on commit 6b8a14e

Please sign in to comment.