Skip to content

Commit 945c730

Browse files
authored
Merge pull request #49046 from geoand/gizmo2-jackson
Port Jackson extension to Gizmo2
2 parents 7c5392f + 2c52cd9 commit 945c730

File tree

2 files changed

+128
-72
lines changed

2 files changed

+128
-72
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package io.quarkus.arc.deployment;
2+
3+
import java.util.function.Predicate;
4+
5+
import io.quarkus.deployment.annotations.BuildProducer;
6+
import io.quarkus.gizmo2.ClassOutput;
7+
import io.smallrye.common.annotation.Experimental;
8+
9+
@Experimental("Interim adapter class, to be replaced by an injection-based mechanism")
10+
public class GeneratedBeanGizmo2Adaptor implements ClassOutput {
11+
12+
private final BuildProducer<GeneratedBeanBuildItem> classOutput;
13+
private final Predicate<String> applicationClassPredicate;
14+
15+
public GeneratedBeanGizmo2Adaptor(BuildProducer<GeneratedBeanBuildItem> classOutput) {
16+
this(classOutput, new Predicate<>() {
17+
18+
@Override
19+
public boolean test(String t) {
20+
return true;
21+
}
22+
});
23+
}
24+
25+
public GeneratedBeanGizmo2Adaptor(BuildProducer<GeneratedBeanBuildItem> classOutput,
26+
Predicate<String> applicationClassPredicate) {
27+
this.classOutput = classOutput;
28+
this.applicationClassPredicate = applicationClassPredicate;
29+
}
30+
31+
@Override
32+
public void write(String className, byte[] bytes) {
33+
String classNameWithoutSuffix = className.substring(0, className.length() - 6);
34+
classOutput.produce(new GeneratedBeanBuildItem(classNameWithoutSuffix, bytes, null,
35+
applicationClassPredicate.test(classNameWithoutSuffix)));
36+
}
37+
38+
}

extensions/jackson/deployment/src/main/java/io/quarkus/jackson/deployment/JacksonProcessor.java

Lines changed: 90 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
import static org.jboss.jandex.AnnotationTarget.Kind.CLASS;
44
import static org.jboss.jandex.AnnotationTarget.Kind.METHOD;
55

6+
import java.lang.constant.ClassDesc;
7+
import java.lang.constant.ConstantDescs;
8+
import java.lang.constant.MethodTypeDesc;
69
import java.lang.reflect.Field;
710
import java.util.Arrays;
811
import java.util.Collection;
@@ -41,7 +44,7 @@
4144

4245
import io.quarkus.arc.deployment.AdditionalBeanBuildItem;
4346
import io.quarkus.arc.deployment.GeneratedBeanBuildItem;
44-
import io.quarkus.arc.deployment.GeneratedBeanGizmoAdaptor;
47+
import io.quarkus.arc.deployment.GeneratedBeanGizmo2Adaptor;
4548
import io.quarkus.arc.deployment.SyntheticBeanBuildItem;
4649
import io.quarkus.arc.deployment.UnremovableBeanBuildItem;
4750
import io.quarkus.arc.impl.Reflections;
@@ -57,11 +60,15 @@
5760
import io.quarkus.deployment.builditem.nativeimage.ReflectiveHierarchyBuildItem;
5861
import io.quarkus.deployment.builditem.nativeimage.ReflectiveMethodBuildItem;
5962
import io.quarkus.deployment.pkg.builditem.CurateOutcomeBuildItem;
60-
import io.quarkus.gizmo.ClassCreator;
61-
import io.quarkus.gizmo.ClassOutput;
62-
import io.quarkus.gizmo.MethodCreator;
63-
import io.quarkus.gizmo.MethodDescriptor;
64-
import io.quarkus.gizmo.ResultHandle;
63+
import io.quarkus.gizmo2.ClassOutput;
64+
import io.quarkus.gizmo2.Const;
65+
import io.quarkus.gizmo2.Expr;
66+
import io.quarkus.gizmo2.Gizmo;
67+
import io.quarkus.gizmo2.LocalVar;
68+
import io.quarkus.gizmo2.ParamVar;
69+
import io.quarkus.gizmo2.Reflection2Gizmo;
70+
import io.quarkus.gizmo2.desc.ClassMethodDesc;
71+
import io.quarkus.gizmo2.desc.MethodDesc;
6572
import io.quarkus.jackson.JacksonMixin;
6673
import io.quarkus.jackson.ObjectMapperCustomizer;
6774
import io.quarkus.jackson.runtime.ConfigurationCustomizer;
@@ -100,6 +107,9 @@ public class JacksonProcessor {
100107
private static final String PARAMETER_NAMES_MODULE = "com.fasterxml.jackson.module.paramnames.ParameterNamesModule";
101108
private static final DotName JACKSON_MIXIN = DotName.createSimple(JacksonMixin.class.getName());
102109

110+
private static final MethodDesc OBJECT_MAPPER_REGISTER_MODULE_METHOD_DESC = MethodDesc.of(ObjectMapper.class,
111+
"registerModule", ObjectMapper.class, Module.class);
112+
103113
// this list can probably be enriched with more modules
104114
private static final List<String> MODULES_NAMES_TO_AUTO_REGISTER = Arrays.asList(TIME_MODULE, JDK8_MODULE,
105115
PARAMETER_NAMES_MODULE);
@@ -377,79 +387,87 @@ void generateCustomizer(BuildProducer<GeneratedBeanBuildItem> generatedBeans,
377387
return;
378388
}
379389

380-
ClassOutput classOutput = new GeneratedBeanGizmoAdaptor(generatedBeans);
381-
382-
try (ClassCreator classCreator = ClassCreator.builder().classOutput(classOutput)
383-
.className("io.quarkus.jackson.customizer.RegisterSerializersAndDeserializersCustomizer")
384-
.interfaces(ObjectMapperCustomizer.class.getName())
385-
.build()) {
386-
classCreator.addAnnotation(Singleton.class);
387-
388-
try (MethodCreator customize = classCreator.getMethodCreator("customize", void.class, ObjectMapper.class)) {
389-
ResultHandle objectMapper = customize.getMethodParam(0);
390-
391-
for (JacksonModuleBuildItem jacksonModule : jacksonModules) {
392-
if (jacksonModule.getItems().isEmpty()) {
393-
continue;
394-
}
395-
396-
/*
397-
* Create code similar to the following:
398-
*
399-
* SimpleModule module = new SimpleModule("somename");
400-
* module.addSerializer(Foo.class, new FooSerializer());
401-
* module.addDeserializer(Foo.class, new FooDeserializer());
402-
* objectMapper.registerModule(module);
403-
*/
404-
ResultHandle module = customize.newInstance(
405-
MethodDescriptor.ofConstructor(SimpleModule.class, String.class),
406-
customize.load(jacksonModule.getName()));
407-
408-
for (JacksonModuleBuildItem.Item item : jacksonModule.getItems()) {
409-
ResultHandle targetClass = customize.loadClassFromTCCL(item.getTargetClassName());
410-
411-
String serializerClassName = item.getSerializerClassName();
412-
if (serializerClassName != null && !serializerClassName.isEmpty()) {
413-
ResultHandle serializer = customize.newInstance(
414-
MethodDescriptor.ofConstructor(serializerClassName));
415-
customize.invokeVirtualMethod(
416-
MethodDescriptor.ofMethod(SimpleModule.class, "addSerializer", SimpleModule.class,
417-
Class.class, JsonSerializer.class),
418-
module, targetClass, serializer);
390+
ClassOutput classOutput = new GeneratedBeanGizmo2Adaptor(generatedBeans);
391+
Gizmo g = Gizmo.create(classOutput);
392+
g.class_("io.quarkus.jackson.customizer.RegisterSerializersAndDeserializersCustomizer", cc -> {
393+
cc.implements_(ObjectMapperCustomizer.class);
394+
cc.defaultConstructor();
395+
cc.addAnnotation(Singleton.class);
396+
cc.method("customize", mc -> {
397+
ParamVar objectMapperParam = mc.parameter("objectMapper", ObjectMapper.class);
398+
mc.returning(void.class);
399+
mc.body(bc -> {
400+
ClassDesc simpleModuleClassDesc = Reflection2Gizmo.classDescOf(SimpleModule.class);
401+
for (JacksonModuleBuildItem jacksonModule : jacksonModules) {
402+
if (jacksonModule.getItems().isEmpty()) {
403+
continue;
419404
}
420405

421-
String deserializerClassName = item.getDeserializerClassName();
422-
if (deserializerClassName != null && !deserializerClassName.isEmpty()) {
423-
ResultHandle deserializer = customize.newInstance(
424-
MethodDescriptor.ofConstructor(deserializerClassName));
425-
customize.invokeVirtualMethod(
426-
MethodDescriptor.ofMethod(SimpleModule.class, "addDeserializer", SimpleModule.class,
427-
Class.class, JsonDeserializer.class),
428-
module, targetClass, deserializer);
406+
/*
407+
* Create code similar to the following:
408+
*
409+
* SimpleModule module = new SimpleModule("somename");
410+
* module.addSerializer(Foo.class, new FooSerializer());
411+
* module.addDeserializer(Foo.class, new FooDeserializer());
412+
* objectMapper.registerModule(module);
413+
*/
414+
415+
LocalVar simpleModuleInstance = bc.localVar("simpleModule",
416+
bc.new_(SimpleModule.class, Const.of(jacksonModule.getName())));
417+
418+
for (JacksonModuleBuildItem.Item item : jacksonModule.getItems()) {
419+
420+
LocalVar targetClass = bc.localVar("targetClass",
421+
Const.of(ClassDesc.of(item.getTargetClassName())));
422+
String serializerClassName = item.getSerializerClassName();
423+
if ((serializerClassName != null) && !serializerClassName.isEmpty()) {
424+
ClassDesc serializerClassDesc = ClassDesc.of(serializerClassName);
425+
Expr serializerInstance = bc.new_(serializerClassDesc);
426+
427+
bc.invokeVirtual(
428+
ClassMethodDesc.of(simpleModuleClassDesc, "addSerializer",
429+
MethodTypeDesc.of(simpleModuleClassDesc,
430+
ConstantDescs.CD_Class, Reflection2Gizmo.classDescOf(
431+
JsonSerializer.class))),
432+
simpleModuleInstance, targetClass, serializerInstance);
433+
434+
}
435+
436+
String deserializerClassName = item.getDeserializerClassName();
437+
if ((deserializerClassName != null) && !deserializerClassName.isEmpty()) {
438+
ClassDesc deserializerClassDesc = ClassDesc.of(deserializerClassName);
439+
Expr deserializerInstance = bc.new_(deserializerClassDesc);
440+
441+
bc.invokeVirtual(
442+
ClassMethodDesc.of(simpleModuleClassDesc, "addDeserializer",
443+
MethodTypeDesc.of(simpleModuleClassDesc,
444+
ConstantDescs.CD_Class, Reflection2Gizmo.classDescOf(
445+
JsonDeserializer.class))),
446+
simpleModuleInstance, targetClass, deserializerInstance);
447+
448+
}
429449
}
430-
}
431450

432-
customize.invokeVirtualMethod(
433-
MethodDescriptor.ofMethod(ObjectMapper.class, "registerModule", ObjectMapper.class, Module.class),
434-
objectMapper, module);
435-
}
451+
bc.invokeVirtual(
452+
OBJECT_MAPPER_REGISTER_MODULE_METHOD_DESC,
453+
objectMapperParam, simpleModuleInstance);
436454

437-
for (ClassPathJacksonModuleBuildItem classPathJacksonModule : classPathJacksonModules) {
438-
ResultHandle module = customize
439-
.newInstance(MethodDescriptor.ofConstructor(classPathJacksonModule.getModuleClassName()));
440-
customize.invokeVirtualMethod(
441-
MethodDescriptor.ofMethod(ObjectMapper.class, "registerModule", ObjectMapper.class, Module.class),
442-
objectMapper, module);
443-
}
455+
}
444456

445-
customize.returnValue(null);
446-
}
457+
for (ClassPathJacksonModuleBuildItem classPathJacksonModule : classPathJacksonModules) {
458+
bc.invokeVirtual(
459+
OBJECT_MAPPER_REGISTER_MODULE_METHOD_DESC,
460+
objectMapperParam, bc.new_(ClassDesc.of(classPathJacksonModule.getModuleClassName())));
461+
}
447462

448-
// ensure that the things we auto-register have the lower priority - this ensures that user registered modules take priority
449-
try (MethodCreator priority = classCreator.getMethodCreator("priority", int.class)) {
450-
priority.returnValue(priority.load(ObjectMapperCustomizer.QUARKUS_CUSTOMIZER_PRIORITY));
451-
}
452-
}
463+
bc.return_();
464+
});
465+
});
466+
cc.method("priority", mc -> {
467+
mc.returning(int.class);
468+
mc.body(bc -> bc.return_(ObjectMapperCustomizer.QUARKUS_CUSTOMIZER_PRIORITY));
469+
});
470+
});
453471
}
454472

455473
@Record(ExecutionTime.STATIC_INIT)

0 commit comments

Comments
 (0)