diff --git a/extensions/jaxb/deployment/src/main/java/io/quarkus/jaxb/deployment/FilteredJaxbClassesToBeBoundBuildItem.java b/extensions/jaxb/deployment/src/main/java/io/quarkus/jaxb/deployment/FilteredJaxbClassesToBeBoundBuildItem.java index 347e3cf661c6b..10e84bd9f104d 100644 --- a/extensions/jaxb/deployment/src/main/java/io/quarkus/jaxb/deployment/FilteredJaxbClassesToBeBoundBuildItem.java +++ b/extensions/jaxb/deployment/src/main/java/io/quarkus/jaxb/deployment/FilteredJaxbClassesToBeBoundBuildItem.java @@ -5,6 +5,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Set; +import java.util.function.Predicate; import java.util.stream.Collectors; import io.quarkus.builder.item.SimpleBuildItem; @@ -33,11 +34,20 @@ public List> getClasses() { public static class Builder { private final Set classNames = new LinkedHashSet<>(); - private final Set classNameExcludes = new LinkedHashSet<>(); + private final Set> classNamePredicateExcludes = new LinkedHashSet<>(); public Builder classNameExcludes(Collection classNameExcludes) { - for (String className : classNameExcludes) { - this.classNameExcludes.add(className); + final String packMatch = ".*"; + + for (String classNameExclude : classNameExcludes) { + if (classNameExclude.endsWith(packMatch)) { + // Package ends with ".*" + final String packageName = classNameExclude.substring(0, classNameExclude.length() - packMatch.length()); + this.classNamePredicateExcludes.add((className) -> className.startsWith(packageName)); + } else { + // Standard class name + this.classNamePredicateExcludes.add(classNameExclude::equals); + } } return this; } @@ -51,7 +61,7 @@ public Builder classNames(Collection classNames) { public FilteredJaxbClassesToBeBoundBuildItem build() { final List> classes = classNames.stream() - .filter(className -> !this.classNameExcludes.contains(className)) + .filter(className -> this.classNamePredicateExcludes.stream().noneMatch(p -> p.test(className))) .map(FilteredJaxbClassesToBeBoundBuildItem::getClassByName) .filter(JaxbType::isValidType) .collect(Collectors.toList()); diff --git a/extensions/jaxb/deployment/src/test/java/io/quarkus/jaxb/deployment/AbstractJaxbContextTest.java b/extensions/jaxb/deployment/src/test/java/io/quarkus/jaxb/deployment/AbstractJaxbContextTest.java new file mode 100644 index 0000000000000..4e42f478435df --- /dev/null +++ b/extensions/jaxb/deployment/src/test/java/io/quarkus/jaxb/deployment/AbstractJaxbContextTest.java @@ -0,0 +1,58 @@ +package io.quarkus.jaxb.deployment; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.StringWriter; + +import jakarta.enterprise.context.control.ActivateRequestContext; +import jakarta.inject.Inject; +import jakarta.xml.bind.JAXBContext; +import jakarta.xml.bind.JAXBException; +import jakarta.xml.bind.Marshaller; +import jakarta.xml.bind.Unmarshaller; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; + +public abstract class AbstractJaxbContextTest { + + @Inject + JAXBContext jaxbContext; + + @Inject + Marshaller marshaller; + + @Inject + Unmarshaller unmarshaller; + + @Test + @ActivateRequestContext + public void shouldInjectJaxbBeans() { + assertThat(jaxbContext).isNotNull(); + assertThat(marshaller).isNotNull(); + assertThat(unmarshaller).isNotNull(); + } + + @Test + @ActivateRequestContext + public void marshalModelOne() throws JAXBException { + io.quarkus.jaxb.deployment.one.Model model = new io.quarkus.jaxb.deployment.one.Model(); + model.setName1("name1"); + + StringWriter sw = new StringWriter(); + marshaller.marshal(model, sw); + + assertThat(sw.toString()).isEqualTo("" + + "name1"); + } + + @Test + @ActivateRequestContext + public void marshalModelTwo() throws JAXBException { + io.quarkus.jaxb.deployment.two.Model model = new io.quarkus.jaxb.deployment.two.Model(); + model.setName2("name2"); + Assertions.assertThatExceptionOfType(JAXBException.class) + .isThrownBy(() -> marshaller.marshal(model, new StringWriter())) + .withMessage("class io.quarkus.jaxb.deployment.two.Model nor any of its super class is known to this context."); + } +} diff --git a/extensions/jaxb/deployment/src/test/java/io/quarkus/jaxb/deployment/ClassExcludeTest.java b/extensions/jaxb/deployment/src/test/java/io/quarkus/jaxb/deployment/ClassExcludeTest.java new file mode 100644 index 0000000000000..f6859cccfec74 --- /dev/null +++ b/extensions/jaxb/deployment/src/test/java/io/quarkus/jaxb/deployment/ClassExcludeTest.java @@ -0,0 +1,17 @@ +package io.quarkus.jaxb.deployment; + +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; + +public class ClassExcludeTest extends AbstractJaxbContextTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses( + io.quarkus.jaxb.deployment.one.Model.class, + io.quarkus.jaxb.deployment.two.Model.class) + .addPackage("io.quarkus.jaxb.deployment.info")) + .overrideConfigKey("quarkus.jaxb.exclude-classes", "io.quarkus.jaxb.deployment.two.Model"); +} diff --git a/extensions/jaxb/deployment/src/test/java/io/quarkus/jaxb/deployment/PackageExcludeTest.java b/extensions/jaxb/deployment/src/test/java/io/quarkus/jaxb/deployment/PackageExcludeTest.java new file mode 100644 index 0000000000000..b531ce48f6d45 --- /dev/null +++ b/extensions/jaxb/deployment/src/test/java/io/quarkus/jaxb/deployment/PackageExcludeTest.java @@ -0,0 +1,17 @@ +package io.quarkus.jaxb.deployment; + +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; + +public class PackageExcludeTest extends AbstractJaxbContextTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses( + io.quarkus.jaxb.deployment.one.Model.class, + io.quarkus.jaxb.deployment.two.Model.class) + .addPackage("io.quarkus.jaxb.deployment.info")) + .overrideConfigKey("quarkus.jaxb.exclude-classes", "io.quarkus.jaxb.deployment.two.*"); +} diff --git a/extensions/jaxb/runtime/src/main/java/io/quarkus/jaxb/runtime/JaxbConfig.java b/extensions/jaxb/runtime/src/main/java/io/quarkus/jaxb/runtime/JaxbConfig.java index 2c48016a10824..bd2a0114e49e6 100644 --- a/extensions/jaxb/runtime/src/main/java/io/quarkus/jaxb/runtime/JaxbConfig.java +++ b/extensions/jaxb/runtime/src/main/java/io/quarkus/jaxb/runtime/JaxbConfig.java @@ -18,6 +18,8 @@ public class JaxbConfig { /** * Exclude classes to automatically be bound to the default JAXB context. + * Values with suffix {@code .*}, i.e. {@code org.acme.*}, are considered packages and exclude all classes that are members + * of these packages */ @ConfigItem public Optional> excludeClasses;