-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fail at build time when there are model conflicts in the JAXBContext.
When having these two classes: ```java package io.quarkus.resteasy.reactive.jaxb.deployment.test.one; import jakarta.xml.bind.annotation.XmlRootElement; @XmlRootElement public class Model { private String name; // ... } ``` And: ```java package io.quarkus.resteasy.reactive.jaxb.deployment.test.two; import jakarta.xml.bind.annotation.XmlRootElement; @XmlRootElement public class Model { private String name; // ... } ``` If users use the `quarkus-jaxb` extension and they inject the JAXBContext, for example: ```java @Inject JAXBContext context; ``` This will fail at runtime because JAXB sees the Model classes as one because of the name. These changes address this issue by failing at build time, so users can properly address it by fixing the JAXB model. Moreover, users can now exclude any of these classes by using the new property `quarkus.jaxb.exclude-classes`, for example: ``` quarkus.jaxb.exclude-classes=io.quarkus.jaxb.deployment.two.Model ``` Plus, in resteasy reactive, if users exclude a class that is required to serialize/deserialize using JAXB, it will not cause any harm because internally it will recreate a cached JAXBContext including the excluded cache.
- Loading branch information
Showing
21 changed files
with
4,230 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
68 changes: 68 additions & 0 deletions
68
extensions/jaxb/deployment/src/main/java/io/quarkus/jaxb/deployment/utils/JaxbType.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
package io.quarkus.jaxb.deployment.utils; | ||
|
||
import java.util.Locale; | ||
import java.util.Set; | ||
|
||
import jakarta.xml.bind.annotation.XmlRootElement; | ||
import jakarta.xml.bind.annotation.XmlType; | ||
|
||
public class JaxbType { | ||
|
||
private static final String DEFAULT_JAXB_ANNOTATION_VALUE = "##default"; | ||
|
||
private final String modelName; | ||
private final Class<?> clazz; | ||
|
||
public JaxbType(Class<?> clazz) { | ||
this.modelName = findModelNameFromType(clazz); | ||
this.clazz = clazz; | ||
} | ||
|
||
public String getModelName() { | ||
return modelName; | ||
} | ||
|
||
public Class<?> getType() { | ||
return clazz; | ||
} | ||
|
||
private String findModelNameFromType(Class<?> clazz) { | ||
String nameFromAnnotation = DEFAULT_JAXB_ANNOTATION_VALUE; | ||
String namespaceFromAnnotation = DEFAULT_JAXB_ANNOTATION_VALUE; | ||
XmlType xmlType = clazz.getAnnotation(XmlType.class); | ||
if (xmlType != null) { | ||
nameFromAnnotation = xmlType.name(); | ||
namespaceFromAnnotation = xmlType.namespace(); | ||
} else { | ||
XmlRootElement rootElement = clazz.getAnnotation(XmlRootElement.class); | ||
if (rootElement != null) { | ||
nameFromAnnotation = rootElement.name(); | ||
namespaceFromAnnotation = rootElement.namespace(); | ||
} | ||
} | ||
|
||
String modelName = nameFromAnnotation; | ||
if (DEFAULT_JAXB_ANNOTATION_VALUE.equals(nameFromAnnotation)) { | ||
modelName = clazz.getSimpleName().toLowerCase(Locale.ROOT); | ||
} | ||
|
||
if (!DEFAULT_JAXB_ANNOTATION_VALUE.equals(namespaceFromAnnotation)) { | ||
modelName += "." + namespaceFromAnnotation; | ||
} | ||
|
||
return modelName; | ||
} | ||
|
||
public static boolean isValidType(Class<?> clazz) { | ||
return clazz != null && !clazz.isPrimitive() && !clazz.isArray(); | ||
} | ||
|
||
public static JaxbType findExistingType(Set<JaxbType> dictionary, JaxbType jaxbType) { | ||
for (JaxbType existing : dictionary) { | ||
if (existing.modelName.equals(jaxbType.modelName)) { | ||
return existing; | ||
} | ||
} | ||
return null; | ||
} | ||
} |
16 changes: 16 additions & 0 deletions
16
extensions/jaxb/deployment/src/test/java/io/quarkus/jaxb/deployment/one/Model.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package io.quarkus.jaxb.deployment.one; | ||
|
||
import jakarta.xml.bind.annotation.XmlRootElement; | ||
|
||
@XmlRootElement | ||
public class Model { | ||
private String name1; | ||
|
||
public String getName1() { | ||
return name1; | ||
} | ||
|
||
public void setName1(String name1) { | ||
this.name1 = name1; | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
extensions/jaxb/deployment/src/test/java/io/quarkus/jaxb/deployment/two/Model.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package io.quarkus.jaxb.deployment.two; | ||
|
||
import jakarta.xml.bind.annotation.XmlRootElement; | ||
|
||
/** | ||
* This class would make the JAXBContext to fail because there is an existing class with same name and model in the | ||
* package `one`. | ||
* To address this failure, we are excluding this class using the property `quarkus.jaxb.exclude-classes` in the | ||
* `application.properties` file. | ||
*/ | ||
@XmlRootElement | ||
public class Model { | ||
private String name2; | ||
|
||
public String getName2() { | ||
return name2; | ||
} | ||
|
||
public void setName2(String name2) { | ||
this.name2 = name2; | ||
} | ||
} |
1 change: 1 addition & 0 deletions
1
extensions/jaxb/deployment/src/test/resources/application.properties
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
quarkus.jaxb.exclude-classes=io.quarkus.jaxb.deployment.two.Model |
17 changes: 17 additions & 0 deletions
17
extensions/jaxb/runtime/src/main/java/io/quarkus/jaxb/runtime/JaxbConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package io.quarkus.jaxb.runtime; | ||
|
||
import java.util.List; | ||
import java.util.Optional; | ||
|
||
import io.quarkus.runtime.annotations.ConfigItem; | ||
import io.quarkus.runtime.annotations.ConfigPhase; | ||
import io.quarkus.runtime.annotations.ConfigRoot; | ||
|
||
@ConfigRoot(phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED, name = "jaxb") | ||
public class JaxbConfig { | ||
/** | ||
* Exclude classes to automatically be bound to the default JAXB context. | ||
*/ | ||
@ConfigItem | ||
public Optional<List<String>> excludeClasses; | ||
} |
15 changes: 10 additions & 5 deletions
15
extensions/jaxb/runtime/src/main/java/io/quarkus/jaxb/runtime/JaxbContextConfigRecorder.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,25 @@ | ||
package io.quarkus.jaxb.runtime; | ||
|
||
import java.util.Collection; | ||
import java.util.Collections; | ||
import java.util.HashSet; | ||
import java.util.Set; | ||
|
||
import io.quarkus.runtime.annotations.Recorder; | ||
|
||
@Recorder | ||
public class JaxbContextConfigRecorder { | ||
private volatile static Set<String> classesToBeBound = new HashSet<>(); | ||
private volatile static Set<Class<?>> classesToBeBound = new HashSet<>(); | ||
|
||
public void addClassesToBeBound(Collection<String> additionalClassesToBeBound) { | ||
this.classesToBeBound.addAll(additionalClassesToBeBound); | ||
public void addClassesToBeBound(Collection<Class<?>> classes) { | ||
this.classesToBeBound.addAll(classes); | ||
} | ||
|
||
public static String[] getClassesToBeBound() { | ||
return classesToBeBound.toArray(new String[0]); | ||
public static Set<Class<?>> getClassesToBeBound() { | ||
return Collections.unmodifiableSet(classesToBeBound); | ||
} | ||
|
||
public static boolean isClassBound(Class<?> clazz) { | ||
return classesToBeBound.contains(clazz.getName()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.