diff --git a/extensions/jackson/deployment/src/main/java/io/quarkus/jackson/deployment/IgnoreJsonDeserializeClassBuildItem.java b/extensions/jackson/deployment/src/main/java/io/quarkus/jackson/deployment/IgnoreJsonDeserializeClassBuildItem.java index 170df9aca7221..9a62d5bfd17b4 100644 --- a/extensions/jackson/deployment/src/main/java/io/quarkus/jackson/deployment/IgnoreJsonDeserializeClassBuildItem.java +++ b/extensions/jackson/deployment/src/main/java/io/quarkus/jackson/deployment/IgnoreJsonDeserializeClassBuildItem.java @@ -1,5 +1,7 @@ package io.quarkus.jackson.deployment; +import java.util.List; + import org.jboss.jandex.DotName; import io.quarkus.builder.item.MultiBuildItem; @@ -10,13 +12,22 @@ */ public final class IgnoreJsonDeserializeClassBuildItem extends MultiBuildItem { - private final DotName dotName; + private final List dotNames; public IgnoreJsonDeserializeClassBuildItem(DotName dotName) { - this.dotName = dotName; + this.dotNames = List.of(dotName); + } + + public IgnoreJsonDeserializeClassBuildItem(List dotNames) { + this.dotNames = dotNames; } + @Deprecated(forRemoval = true) public DotName getDotName() { - return dotName; + return dotNames.size() > 0 ? dotNames.get(0) : null; + } + + public List getDotNames() { + return dotNames; } } diff --git a/extensions/jackson/deployment/src/main/java/io/quarkus/jackson/deployment/JacksonProcessor.java b/extensions/jackson/deployment/src/main/java/io/quarkus/jackson/deployment/JacksonProcessor.java index a89809f5ed8b1..5b3c3f5f11570 100644 --- a/extensions/jackson/deployment/src/main/java/io/quarkus/jackson/deployment/JacksonProcessor.java +++ b/extensions/jackson/deployment/src/main/java/io/quarkus/jackson/deployment/JacksonProcessor.java @@ -123,7 +123,7 @@ void register( Set ignoredDotNames = new HashSet<>(); for (IgnoreJsonDeserializeClassBuildItem ignoreJsonDeserializeClassBuildItem : ignoreJsonDeserializeClassBuildItems) { - ignoredDotNames.add(ignoreJsonDeserializeClassBuildItem.getDotName()); + ignoredDotNames.addAll(ignoreJsonDeserializeClassBuildItem.getDotNames()); } // handle the various @JsonDeserialize cases diff --git a/extensions/kubernetes-client/deployment/src/main/java/io/quarkus/kubernetes/client/deployment/KubernetesClientProcessor.java b/extensions/kubernetes-client/deployment/src/main/java/io/quarkus/kubernetes/client/deployment/KubernetesClientProcessor.java index 10bf9e433e7cc..85a765326f28f 100644 --- a/extensions/kubernetes-client/deployment/src/main/java/io/quarkus/kubernetes/client/deployment/KubernetesClientProcessor.java +++ b/extensions/kubernetes-client/deployment/src/main/java/io/quarkus/kubernetes/client/deployment/KubernetesClientProcessor.java @@ -46,6 +46,11 @@ public class KubernetesClientProcessor { .createSimple("io.fabric8.kubernetes.client.informers.ResourceEventHandler"); private static final DotName KUBERNETES_RESOURCE = DotName .createSimple("io.fabric8.kubernetes.api.model.KubernetesResource"); + private static final DotName KUBERNETES_RESOURCE_LIST = DotName + .createSimple("io.fabric8.kubernetes.api.model.KubernetesResourceList"); + + private static final DotName VISITABLE_BUILDER = DotName + .createSimple("io.fabric8.kubernetes.api.builder.VisitableBuilder"); private static final DotName CUSTOM_RESOURCE = DotName.createSimple("io.fabric8.kubernetes.client.CustomResource"); private static final Logger log = Logger.getLogger(KubernetesClientProcessor.class.getName()); @@ -117,36 +122,28 @@ public void process(ApplicationIndexBuildItem applicationIndex, CombinedIndexBui Collection kubernetesResourceImpls = combinedIndexBuildItem.getIndex() .getAllKnownImplementors(KUBERNETES_RESOURCE); + Collection kubernetesResourceListImpls = combinedIndexBuildItem.getIndex() + .getAllKnownImplementors(KUBERNETES_RESOURCE_LIST); + Collection visitableBuilderImpls = combinedIndexBuildItem.getIndex() + .getAllKnownImplementors(VISITABLE_BUILDER); + // default sizes determined experimentally - these are only set in order to prevent continuous expansion of the array list - List withoutFieldsRegistration = new ArrayList<>(kubernetesResourceImpls.size()); + List withoutFieldsRegistration = new ArrayList<>( + kubernetesResourceImpls.size() + kubernetesResourceListImpls.size()); List withFieldsRegistration = new ArrayList<>(2); - kubernetesResourceImpls - .stream() - .peek(c -> { - // we need to make sure that the Jackson extension does not try to fully register the model classes - // since we are going to register them weakly - ignoredJsonDeserializationClasses.produce(new IgnoreJsonDeserializeClassBuildItem(c.name())); - }) - .filter(c -> !watchedClasses.contains(c.name())) - .map(c -> { - boolean registerFields = false; - List jsonFormatInstances = c.annotationsMap().get(JSON_FORMAT); - if (jsonFormatInstances != null) { - for (AnnotationInstance jsonFormatInstance : jsonFormatInstances) { - if (jsonFormatInstance.target().kind() == AnnotationTarget.Kind.FIELD) { - registerFields = true; - break; - } - } - } - return new AbstractMap.SimpleEntry<>(c.name(), registerFields); - }).forEach(e -> { - if (e.getValue()) { - withFieldsRegistration.add(e.getKey().toString()); - } else { - withoutFieldsRegistration.add(e.getKey().toString()); - } - }); + List ignoreJsonDeserialization = new ArrayList<>( + kubernetesResourceImpls.size() + kubernetesResourceListImpls.size()); + + populateReflectionRegistrationLists(kubernetesResourceImpls, watchedClasses, ignoreJsonDeserialization, + withoutFieldsRegistration, + withFieldsRegistration); + populateReflectionRegistrationLists(kubernetesResourceListImpls, watchedClasses, ignoreJsonDeserialization, + withoutFieldsRegistration, + withFieldsRegistration); + populateReflectionRegistrationLists(visitableBuilderImpls, watchedClasses, ignoreJsonDeserialization, + withoutFieldsRegistration, + withFieldsRegistration); + if (!withFieldsRegistration.isEmpty()) { reflectiveClasses.produce(ReflectiveClassBuildItem .builder(withFieldsRegistration.toArray(EMPTY_STRINGS_ARRAY)).weak(true).methods(true).fields(true) @@ -158,6 +155,8 @@ public void process(ApplicationIndexBuildItem applicationIndex, CombinedIndexBui .build()); } + ignoredJsonDeserializationClasses.produce(new IgnoreJsonDeserializeClassBuildItem(ignoreJsonDeserialization)); + // we also ignore some classes that are annotated with @JsonDeserialize that would force the registration of the entire model ignoredJsonDeserializationClasses.produce( new IgnoreJsonDeserializeClassBuildItem(DotName.createSimple("io.fabric8.kubernetes.api.model.KubeSchema"))); @@ -206,6 +205,40 @@ public void process(ApplicationIndexBuildItem applicationIndex, CombinedIndexBui sslNativeSupport.produce(new ExtensionSslNativeSupportBuildItem(Feature.KUBERNETES_CLIENT)); } + private static void populateReflectionRegistrationLists(Collection kubernetesResourceImpls, + Set watchedClasses, + List ignoredJsonDeserializationClasses, + List withoutFieldsRegistration, + List withFieldsRegistration) { + kubernetesResourceImpls + .stream() + .peek(c -> { + // we need to make sure that the Jackson extension does not try to fully register the model classes + // since we are going to register them weakly + ignoredJsonDeserializationClasses.add(c.name()); + }) + .filter(c -> !watchedClasses.contains(c.name())) + .map(c -> { + boolean registerFields = false; + List jsonFormatInstances = c.annotationsMap().get(JSON_FORMAT); + if (jsonFormatInstances != null) { + for (AnnotationInstance jsonFormatInstance : jsonFormatInstances) { + if (jsonFormatInstance.target().kind() == AnnotationTarget.Kind.FIELD) { + registerFields = true; + break; + } + } + } + return new AbstractMap.SimpleEntry<>(c.name(), registerFields); + }).forEach(e -> { + if (e.getValue()) { + withFieldsRegistration.add(e.getKey().toString()); + } else { + withoutFieldsRegistration.add(e.getKey().toString()); + } + }); + } + private void findWatchedClasses(final DotName implementedOrExtendedClass, final ApplicationIndexBuildItem applicationIndex, final CombinedIndexBuildItem combinedIndexBuildItem, final Set watchedClasses, final int expectedGenericTypeCardinality, boolean isTargetClassAnInterface) {