This is an automated email from the ASF dual-hosted git repository.
veithen pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ws-axiom.git
The following commit(s) were added to refs/heads/master by this push:
new e1a129801 Generalize @StringOrCharacterData into a parameterized
@Union checker
e1a129801 is described below
commit e1a129801b56732bf26402a2e53c2d6fb1aa50be
Author: Andreas Veithen-Knowles <[email protected]>
AuthorDate: Sun Jun 14 22:01:31 2026 +0000
Generalize @StringOrCharacterData into a parameterized @Union checker
Replaces the hardcoded String|CharacterData union checker
(components/checker-annotations, buildutils/stringorcharacterdata-checker)
with a general-purpose @Union(types = {...}) type-use annotation and
Checker Framework checker (buildutils/union-annotations,
buildutils/union-checker). @StringOrCharacterData becomes
@Union(types = {String.class, CharacterData.class}) throughout
core-streams, core-mixins and om-mixins.
Also adds a TreeAnnotator that improves the type computed for
conditional expressions such as `data == null ? "" : data`, so that
they type-check against a @Union(...) target without an explicit cast.
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
---
buildutils/pom.xml | 3 +-
.../StringOrCharacterDataAnnotatedTypeFactory.java | 161 ---------------------
.../union-annotations}/pom.xml | 4 +-
.../java/org/apache/axiom/checker/union/Union.java | 26 ++--
.../apache/axiom/checker/union/UnionBottom.java | 20 +--
.../apache/axiom/checker/union/UnknownUnion.java | 10 +-
.../pom.xml | 4 +-
.../checker/union/UnionAnnotatedTypeFactory.java | 136 +++++++++++++++++
.../apache/axiom/checker/union/UnionChecker.java} | 10 +-
.../checker/union/UnionQualifierHierarchy.java | 155 ++++++++++++++++++++
.../apache/axiom/checker/union/UnionTransfer.java | 70 +++++++++
.../axiom/checker/union/UnionTreeAnnotator.java | 82 +++++++++++
.../axiom/checker/union/UnionTypeHierarchy.java | 64 ++++++++
components/core-streams/pom.xml | 4 +-
.../axiom/core/stream/CharArrayCharacterData.java | 7 +-
.../apache/axiom/core/stream/CharacterData.java | 7 +-
.../DocumentElementExtractingFilterHandler.java | 5 +-
.../org/apache/axiom/core/stream/XmlHandler.java | 5 +-
.../axiom/core/stream/XmlHandlerWrapper.java | 5 +-
.../stax/push/input/InternalXMLStreamWriter.java | 5 +-
.../stax/push/input/XmlHandlerStreamWriter.java | 6 +-
.../xop/AbstractXOPDecodingFilterHandler.java | 9 +-
.../xop/AbstractXOPEncodingFilterHandler.java | 9 +-
components/pom.xml | 1 -
mixins/core-mixins/pom.xml | 2 +-
.../apache/axiom/core/CoreCharacterDataNode.java | 7 +-
.../axiom/core/CoreCharacterDataSinkNode.java | 6 +-
.../axiom/core/CoreCharacterDataSourceNode.java | 5 +-
.../axiom/core/CoreMixedContentContainer.java | 5 +-
.../java/org/apache/axiom/core/CoreParentNode.java | 8 +-
.../axiom/core/impl/AbstractNodeIterator.java | 2 +-
.../org/apache/axiom/core/impl/TreeWalkerImpl.java | 10 +-
.../axiom/core/impl/builder/BuildableContext.java | 7 +-
.../axiom/core/impl/builder/BuilderHandler.java | 6 +-
.../apache/axiom/core/impl/builder/Context.java | 6 +-
.../axiom/core/impl/builder/UnwrappingContext.java | 6 +-
...CoreCharacterDataContainingParentNodeMixin.java | 9 +-
.../impl/mixin/CoreCharacterDataNodeMixin.java | 14 +-
.../impl/mixin/CoreMixedContentContainerMixin.java | 7 +-
.../axiom/core/impl/mixin/CoreParentNodeMixin.java | 29 ++--
mixins/dom-mixins/pom.xml | 2 +-
mixins/om-mixins/pom.xml | 2 +-
.../om/impl/common/factory/OMFactoryImpl.java | 11 +-
.../org/apache/axiom/om/impl/intf/TextContent.java | 8 +-
.../impl/stream/ds/PushOMDataSourceXOPHandler.java | 6 +-
.../impl/stream/xop/XOPDecodingFilterHandler.java | 5 +-
mixins/pom.xml | 2 +-
47 files changed, 677 insertions(+), 296 deletions(-)
diff --git a/buildutils/pom.xml b/buildutils/pom.xml
index 7bf8a2081..7884a4fe1 100644
--- a/buildutils/pom.xml
+++ b/buildutils/pom.xml
@@ -36,7 +36,8 @@
<module>axiom-weaver-maven-plugin</module>
<module>buildutils-maven-plugin</module>
<module>shade-axiom-xml</module>
- <module>stringorcharacterdata-checker</module>
+ <module>union-annotations</module>
+ <module>union-checker</module>
</modules>
<properties>
diff --git
a/buildutils/stringorcharacterdata-checker/src/main/java/org/apache/axiom/checker/StringOrCharacterDataAnnotatedTypeFactory.java
b/buildutils/stringorcharacterdata-checker/src/main/java/org/apache/axiom/checker/StringOrCharacterDataAnnotatedTypeFactory.java
deleted file mode 100644
index dc04f06fe..000000000
---
a/buildutils/stringorcharacterdata-checker/src/main/java/org/apache/axiom/checker/StringOrCharacterDataAnnotatedTypeFactory.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.axiom.checker;
-
-import com.sun.source.tree.BinaryTree;
-import com.sun.source.tree.TypeCastTree;
-import java.lang.annotation.Annotation;
-import java.util.LinkedHashSet;
-import java.util.Set;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeMirror;
-import org.apache.axiom.core.stream.annotations.StringOrCharacterData;
-import org.apache.axiom.core.stream.annotations.UnknownCharacterDataType;
-import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory;
-import org.checkerframework.common.basetype.BaseTypeChecker;
-import org.checkerframework.framework.type.AnnotatedTypeMirror;
-import org.checkerframework.framework.type.QualifierHierarchy;
-import org.checkerframework.framework.type.treeannotator.ListTreeAnnotator;
-import org.checkerframework.framework.type.treeannotator.TreeAnnotator;
-import org.checkerframework.framework.type.typeannotator.ListTypeAnnotator;
-import org.checkerframework.framework.type.typeannotator.TypeAnnotator;
-import org.checkerframework.javacutil.AnnotationBuilder;
-import org.checkerframework.javacutil.TypesUtils;
-
-/**
- * The annotated type factory for the {@link StringOrCharacterDataChecker}.
This factory
- * automatically adds {@code @StringOrCharacterData} to {@link String} types
and to types that
- * implement {@link org.apache.axiom.core.stream.CharacterData}.
- */
-public class StringOrCharacterDataAnnotatedTypeFactory extends
BaseAnnotatedTypeFactory {
-
- private static final String CHARACTER_DATA_NAME =
"org.apache.axiom.core.stream.CharacterData";
-
- private final AnnotationMirror STRING_OR_CHARACTER_DATA;
-
- public StringOrCharacterDataAnnotatedTypeFactory(BaseTypeChecker checker) {
- super(checker);
- STRING_OR_CHARACTER_DATA = AnnotationBuilder.fromClass(elements,
StringOrCharacterData.class);
- postInit();
- }
-
- @Override
- protected Set<Class<? extends Annotation>> createSupportedTypeQualifiers()
{
- LinkedHashSet<Class<? extends Annotation>> qualifiers = new
LinkedHashSet<>();
- qualifiers.add(StringOrCharacterData.class);
- qualifiers.add(UnknownCharacterDataType.class);
- return qualifiers;
- }
-
- @Override
- protected TreeAnnotator createTreeAnnotator() {
- return new ListTreeAnnotator(super.createTreeAnnotator(), new
StringOrCharacterDataTreeAnnotator(this));
- }
-
- /**
- * Runs after {@link
org.checkerframework.framework.type.treeannotator.PropagationTreeAnnotator}
- * and re-applies {@code @StringOrCharacterData} to:
- *
- * <ul>
- * <li>Binary expressions whose result type is {@link String}. This is
necessary because
- * {@code PropagationTreeAnnotator} computes the LUB of the operand
qualifiers for binary
- * {@code +}, so a string concatenation such as {@code "literal " +
intValue} would
- * otherwise produce {@code @UnknownCharacterDataType String}.
- * <li>Type cast expressions whose target type is {@link String} or
implements {@link
- * org.apache.axiom.core.stream.CharacterData}.
- * </ul>
- */
- private class StringOrCharacterDataTreeAnnotator extends TreeAnnotator {
-
-
StringOrCharacterDataTreeAnnotator(StringOrCharacterDataAnnotatedTypeFactory
factory) {
- super(factory);
- }
-
- @Override
- public Void visitBinary(BinaryTree node, AnnotatedTypeMirror type) {
- if (TypesUtils.isString(type.getUnderlyingType())) {
- type.replaceAnnotation(STRING_OR_CHARACTER_DATA);
- }
- return null;
- }
-
- @Override
- public Void visitTypeCast(TypeCastTree node, AnnotatedTypeMirror type)
{
- TypeMirror underlyingType = type.getUnderlyingType();
- if (TypesUtils.isString(underlyingType) ||
isCharacterData(underlyingType)) {
- type.replaceAnnotation(STRING_OR_CHARACTER_DATA);
- }
- return null;
- }
- }
-
- @Override
- protected TypeAnnotator createTypeAnnotator() {
- return new ListTypeAnnotator(new
StringOrCharacterDataTypeAnnotator(this), super.createTypeAnnotator());
- }
-
- private class StringOrCharacterDataTypeAnnotator extends TypeAnnotator {
-
-
StringOrCharacterDataTypeAnnotator(StringOrCharacterDataAnnotatedTypeFactory
factory) {
- super(factory);
- }
-
- @Override
- public Void visitDeclared(AnnotatedTypeMirror.AnnotatedDeclaredType
type, Void p) {
- if (shouldAnnotate(type)) {
- type.addAnnotation(STRING_OR_CHARACTER_DATA);
- }
- return super.visitDeclared(type, null);
- }
- }
-
- private boolean shouldAnnotate(AnnotatedTypeMirror.AnnotatedDeclaredType
type) {
- QualifierHierarchy hierarchy = getQualifierHierarchy();
- Set<AnnotationMirror> annotations = type.getAnnotations();
- // Don't override existing annotations
- for (AnnotationMirror anno : annotations) {
- if (hierarchy.isSubtypeQualifiersOnly(anno,
STRING_OR_CHARACTER_DATA)
- ||
hierarchy.isSubtypeQualifiersOnly(STRING_OR_CHARACTER_DATA, anno)) {
- return false;
- }
- }
- TypeMirror underlyingType = type.getUnderlyingType();
- if (TypesUtils.isString(underlyingType)) {
- return true;
- }
- return isCharacterData(underlyingType);
- }
-
- private boolean isCharacterData(TypeMirror type) {
- if (type instanceof DeclaredType declaredType) {
- String qualifiedName =
TypesUtils.getQualifiedName(declaredType).toString();
- if (qualifiedName.equals(CHARACTER_DATA_NAME)) {
- return true;
- }
- // Check supertypes
- for (TypeMirror superType : types.directSupertypes(type)) {
- if (isCharacterData(superType)) {
- return true;
- }
- }
- }
- return false;
- }
-}
diff --git a/components/checker-annotations/pom.xml
b/buildutils/union-annotations/pom.xml
similarity index 94%
rename from components/checker-annotations/pom.xml
rename to buildutils/union-annotations/pom.xml
index c4ac604b4..3fbad830f 100644
--- a/components/checker-annotations/pom.xml
+++ b/buildutils/union-annotations/pom.xml
@@ -22,11 +22,11 @@
<parent>
<groupId>org.apache.ws.commons.axiom</groupId>
- <artifactId>components</artifactId>
+ <artifactId>buildutils</artifactId>
<version>2.1.0-SNAPSHOT</version>
</parent>
- <artifactId>checker-annotations</artifactId>
+ <artifactId>union-annotations</artifactId>
<url>http://ws.apache.org/axiom/</url>
diff --git
a/components/checker-annotations/src/main/java/org/apache/axiom/core/stream/annotations/StringOrCharacterData.java
b/buildutils/union-annotations/src/main/java/org/apache/axiom/checker/union/Union.java
similarity index 54%
copy from
components/checker-annotations/src/main/java/org/apache/axiom/core/stream/annotations/StringOrCharacterData.java
copy to
buildutils/union-annotations/src/main/java/org/apache/axiom/checker/union/Union.java
index a2a34fd95..7a0e9e99f 100644
---
a/components/checker-annotations/src/main/java/org/apache/axiom/core/stream/annotations/StringOrCharacterData.java
+++
b/buildutils/union-annotations/src/main/java/org/apache/axiom/checker/union/Union.java
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.axiom.core.stream.annotations;
+package org.apache.axiom.checker.union;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
@@ -25,14 +25,22 @@ import java.lang.annotation.Target;
import org.checkerframework.framework.qual.SubtypeOf;
/**
- * Indicates that the annotated {@link Object} type use holds a value that is
either a {@link
- * String} or a {@link org.apache.axiom.core.stream.CharacterData} instance.
+ * Indicates that the annotated type use holds a value whose runtime type is a
subtype of one of
+ * the {@link #types()}.
*
- * <p>This annotation is enforced by the {@code StringOrCharacterDataChecker}
which ensures that
- * only {@link String}, {@link org.apache.axiom.core.stream.CharacterData}, or
another {@code
- * @StringOrCharacterData Object} can be assigned to a position annotated with
this qualifier.
+ * <p>This annotation is enforced by the {@code UnionChecker}, which ensures
that only values whose
+ * (static) type is a subtype of one of {@link #types()}, or another {@code
@Union} type that is a
+ * subtype of this one, can be assigned to a position annotated with this
qualifier. {@code
+ * instanceof} checks against one of {@link #types()} (including combinations
using {@code ||} and
+ * {@code else if}) narrow a value of unknown type to {@code @Union}.
*/
@Retention(RetentionPolicy.CLASS)
-@Target({ElementType.TYPE_USE})
-@SubtypeOf(UnknownCharacterDataType.class)
-public @interface StringOrCharacterData {}
+@Target(ElementType.TYPE_USE)
+@SubtypeOf(UnknownUnion.class)
+public @interface Union {
+ /**
+ * The types that make up the union. The annotated value's runtime type
must be a subtype of at
+ * least one of these types.
+ */
+ Class<?>[] types();
+}
diff --git
a/components/checker-annotations/src/main/java/org/apache/axiom/core/stream/annotations/StringOrCharacterData.java
b/buildutils/union-annotations/src/main/java/org/apache/axiom/checker/union/UnionBottom.java
similarity index 62%
rename from
components/checker-annotations/src/main/java/org/apache/axiom/core/stream/annotations/StringOrCharacterData.java
rename to
buildutils/union-annotations/src/main/java/org/apache/axiom/checker/union/UnionBottom.java
index a2a34fd95..e68052eb7 100644
---
a/components/checker-annotations/src/main/java/org/apache/axiom/core/stream/annotations/StringOrCharacterData.java
+++
b/buildutils/union-annotations/src/main/java/org/apache/axiom/checker/union/UnionBottom.java
@@ -16,23 +16,19 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.axiom.core.stream.annotations;
+package org.apache.axiom.checker.union;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.LiteralKind;
+import org.checkerframework.framework.qual.QualifierForLiterals;
import org.checkerframework.framework.qual.SubtypeOf;
-/**
- * Indicates that the annotated {@link Object} type use holds a value that is
either a {@link
- * String} or a {@link org.apache.axiom.core.stream.CharacterData} instance.
- *
- * <p>This annotation is enforced by the {@code StringOrCharacterDataChecker}
which ensures that
- * only {@link String}, {@link org.apache.axiom.core.stream.CharacterData}, or
another {@code
- * @StringOrCharacterData Object} can be assigned to a position annotated with
this qualifier.
- */
+/** The bottom type in the {@link Union} type hierarchy. This is the qualifier
for {@code null}. */
@Retention(RetentionPolicy.CLASS)
-@Target({ElementType.TYPE_USE})
-@SubtypeOf(UnknownCharacterDataType.class)
-public @interface StringOrCharacterData {}
+@Target(ElementType.TYPE_USE)
+@SubtypeOf(Union.class)
+@QualifierForLiterals(LiteralKind.NULL)
+public @interface UnionBottom {}
diff --git
a/components/checker-annotations/src/main/java/org/apache/axiom/core/stream/annotations/UnknownCharacterDataType.java
b/buildutils/union-annotations/src/main/java/org/apache/axiom/checker/union/UnknownUnion.java
similarity index 80%
rename from
components/checker-annotations/src/main/java/org/apache/axiom/core/stream/annotations/UnknownCharacterDataType.java
rename to
buildutils/union-annotations/src/main/java/org/apache/axiom/checker/union/UnknownUnion.java
index 33ba01ab0..de3ea7b3d 100644
---
a/components/checker-annotations/src/main/java/org/apache/axiom/core/stream/annotations/UnknownCharacterDataType.java
+++
b/buildutils/union-annotations/src/main/java/org/apache/axiom/checker/union/UnknownUnion.java
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.axiom.core.stream.annotations;
+package org.apache.axiom.checker.union;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
@@ -26,11 +26,11 @@ import
org.checkerframework.framework.qual.DefaultQualifierInHierarchy;
import org.checkerframework.framework.qual.SubtypeOf;
/**
- * The top type in the StringOrCharacterData type hierarchy. This is the
default qualifier for
- * unannotated types and represents an unknown character data type.
+ * The top type in the {@link Union} type hierarchy. This is the default
qualifier for unannotated
+ * types and represents a value of unknown (unconstrained) type.
*/
@Retention(RetentionPolicy.CLASS)
-@Target({ElementType.TYPE_USE})
+@Target(ElementType.TYPE_USE)
@SubtypeOf({})
@DefaultQualifierInHierarchy
-public @interface UnknownCharacterDataType {}
+public @interface UnknownUnion {}
diff --git a/buildutils/stringorcharacterdata-checker/pom.xml
b/buildutils/union-checker/pom.xml
similarity index 93%
rename from buildutils/stringorcharacterdata-checker/pom.xml
rename to buildutils/union-checker/pom.xml
index cac55858b..51ad2dd6e 100644
--- a/buildutils/stringorcharacterdata-checker/pom.xml
+++ b/buildutils/union-checker/pom.xml
@@ -26,7 +26,7 @@
<version>2.1.0-SNAPSHOT</version>
</parent>
- <artifactId>stringorcharacterdata-checker</artifactId>
+ <artifactId>union-checker</artifactId>
<url>http://ws.apache.org/axiom/</url>
@@ -37,7 +37,7 @@
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
- <artifactId>checker-annotations</artifactId>
+ <artifactId>union-annotations</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
diff --git
a/buildutils/union-checker/src/main/java/org/apache/axiom/checker/union/UnionAnnotatedTypeFactory.java
b/buildutils/union-checker/src/main/java/org/apache/axiom/checker/union/UnionAnnotatedTypeFactory.java
new file mode 100644
index 000000000..1eefb54e6
--- /dev/null
+++
b/buildutils/union-checker/src/main/java/org/apache/axiom/checker/union/UnionAnnotatedTypeFactory.java
@@ -0,0 +1,136 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.axiom.checker.union;
+
+import java.lang.annotation.Annotation;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Types;
+import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory;
+import org.checkerframework.common.basetype.BaseTypeChecker;
+import org.checkerframework.framework.flow.CFAbstractAnalysis;
+import org.checkerframework.framework.flow.CFStore;
+import org.checkerframework.framework.flow.CFTransfer;
+import org.checkerframework.framework.flow.CFValue;
+import org.checkerframework.framework.type.QualifierHierarchy;
+import org.checkerframework.framework.type.TypeHierarchy;
+import org.checkerframework.framework.type.treeannotator.ListTreeAnnotator;
+import org.checkerframework.framework.type.treeannotator.TreeAnnotator;
+import org.checkerframework.javacutil.AnnotationBuilder;
+import org.checkerframework.javacutil.AnnotationUtils;
+import org.checkerframework.javacutil.TreeUtils;
+
+/** The annotated type factory for the {@link UnionChecker}. */
+public class UnionAnnotatedTypeFactory extends BaseAnnotatedTypeFactory {
+
+ final AnnotationMirror UNKNOWN_UNION;
+
+ private final ExecutableElement typesElement;
+ private final Types types;
+
+ public UnionAnnotatedTypeFactory(BaseTypeChecker checker) {
+ super(checker);
+ UNKNOWN_UNION = AnnotationBuilder.fromClass(elements,
UnknownUnion.class);
+ typesElement = TreeUtils.getMethod(Union.class, "types", 0,
getProcessingEnv());
+ types = checker.getTypeUtils();
+ postInit();
+ }
+
+ @Override
+ protected Set<Class<? extends Annotation>> createSupportedTypeQualifiers()
{
+ LinkedHashSet<Class<? extends Annotation>> qualifiers = new
LinkedHashSet<>();
+ qualifiers.add(Union.class);
+ qualifiers.add(UnknownUnion.class);
+ qualifiers.add(UnionBottom.class);
+ return qualifiers;
+ }
+
+ @Override
+ protected QualifierHierarchy createQualifierHierarchy() {
+ return new UnionQualifierHierarchy(getSupportedTypeQualifiers(),
elements, this);
+ }
+
+ @Override
+ protected TypeHierarchy createTypeHierarchy() {
+ return new UnionTypeHierarchy(
+ checker, getQualifierHierarchy(), ignoreRawTypeArguments,
checker.hasOption("invariantArrays"), this);
+ }
+
+ @Override
+ public CFTransfer createFlowTransferFunction(CFAbstractAnalysis<CFValue,
CFStore, CFTransfer> analysis) {
+ return new UnionTransfer(analysis);
+ }
+
+ @Override
+ protected TreeAnnotator createTreeAnnotator() {
+ return new ListTreeAnnotator(super.createTreeAnnotator(), new
UnionTreeAnnotator(this));
+ }
+
+ /**
+ * Returns whether {@code underlyingType} (erased) is a subtype of one of
the types listed in
+ * {@code unionAnno}'s {@link Union#types()}. This is the same escape rule
that {@link
+ * UnionTypeHierarchy} applies to allow an {@code @UnknownUnion}-typed
expression to be used
+ * where {@code @Union(types = {...})} is expected.
+ */
+ boolean isSubtypeOfUnionMember(TypeMirror underlyingType, AnnotationMirror
unionAnno) {
+ TypeMirror erased = types.erasure(underlyingType);
+ for (TypeMirror memberType : getUnionTypes(unionAnno)) {
+ if (types.isSubtype(erased, memberType)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns the {@link Union#types()} element of the given {@code @Union}
annotation.
+ *
+ * @param unionAnno a {@code @Union(types = {...})} annotation
+ * @return the types listed in {@link Union#types()}
+ */
+ List<TypeMirror> getUnionTypes(AnnotationMirror unionAnno) {
+ return AnnotationUtils.getElementValueArray(unionAnno, typesElement,
TypeMirror.class);
+ }
+
+ /**
+ * Creates a {@code @Union(types = {...})} annotation for the given member
types.
+ *
+ * @param memberTypes the types to use for {@link Union#types()}
+ * @return the resulting annotation
+ */
+ AnnotationMirror createUnion(List<TypeMirror> memberTypes) {
+ return new AnnotationBuilder(getProcessingEnv(), Union.class)
+ .setValue("types", memberTypes)
+ .build();
+ }
+
+ /**
+ * Creates a {@code @Union(types = {memberType})} annotation for a single
member type.
+ *
+ * @param memberType the type to use for {@link Union#types()}
+ * @return the resulting annotation
+ */
+ AnnotationMirror createUnion(TypeMirror memberType) {
+ return createUnion(List.of(memberType));
+ }
+}
diff --git
a/buildutils/stringorcharacterdata-checker/src/main/java/org/apache/axiom/checker/StringOrCharacterDataChecker.java
b/buildutils/union-checker/src/main/java/org/apache/axiom/checker/union/UnionChecker.java
similarity index 74%
rename from
buildutils/stringorcharacterdata-checker/src/main/java/org/apache/axiom/checker/StringOrCharacterDataChecker.java
rename to
buildutils/union-checker/src/main/java/org/apache/axiom/checker/union/UnionChecker.java
index e51466c7c..0da20cc42 100644
---
a/buildutils/stringorcharacterdata-checker/src/main/java/org/apache/axiom/checker/StringOrCharacterDataChecker.java
+++
b/buildutils/union-checker/src/main/java/org/apache/axiom/checker/union/UnionChecker.java
@@ -16,16 +16,16 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.axiom.checker;
+package org.apache.axiom.checker.union;
import com.google.auto.service.AutoService;
import javax.annotation.processing.Processor;
import org.checkerframework.common.basetype.BaseTypeChecker;
/**
- * A Checker Framework checker that enforces that {@code
@StringOrCharacterData Object} can only be
- * assigned from {@link String}, {@link
org.apache.axiom.core.stream.CharacterData}, or another
- * {@code @StringOrCharacterData Object}.
+ * A Checker Framework checker that enforces that a {@code @Union(types =
{A.class, B.class, ...})}
+ * type use can only hold values whose type is a subtype of one of {@code A},
{@code B}, etc., or
+ * another {@code @Union} type that is a subtype of it.
*/
@AutoService(Processor.class)
-public class StringOrCharacterDataChecker extends BaseTypeChecker {}
+public class UnionChecker extends BaseTypeChecker {}
diff --git
a/buildutils/union-checker/src/main/java/org/apache/axiom/checker/union/UnionQualifierHierarchy.java
b/buildutils/union-checker/src/main/java/org/apache/axiom/checker/union/UnionQualifierHierarchy.java
new file mode 100644
index 000000000..b6eb7b47b
--- /dev/null
+++
b/buildutils/union-checker/src/main/java/org/apache/axiom/checker/union/UnionQualifierHierarchy.java
@@ -0,0 +1,155 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.axiom.checker.union;
+
+import java.lang.annotation.Annotation;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+import org.checkerframework.framework.type.MostlyNoElementQualifierHierarchy;
+import org.checkerframework.framework.util.QualifierKind;
+
+/**
+ * The qualifier hierarchy for {@link Union}, {@link UnknownUnion} and {@link
UnionBottom}.
+ *
+ * <p>Subtyping between two {@link Union} annotations is subset based: {@code
@Union(S1)} is a
+ * subtype of {@code @Union(S2)} if every type in {@code S1} is a subtype of
some type in {@code
+ * S2}. The least upper bound of two {@link Union} annotations is the
(deduplicated) union of their
+ * {@link Union#types()}. The greatest lower bound is approximated as {@code
@Union(types = {})}
+ * (a qualifier that is a subtype of every {@code @Union} qualifier) unless
the two sets of types
+ * are equal.
+ */
+final class UnionQualifierHierarchy extends MostlyNoElementQualifierHierarchy {
+
+ private final UnionAnnotatedTypeFactory atypeFactory;
+ private final Types types;
+ private final QualifierKind unionKind;
+
+ UnionQualifierHierarchy(
+ Collection<Class<? extends Annotation>> qualifierClasses,
+ Elements elements,
+ UnionAnnotatedTypeFactory atypeFactory) {
+ super(qualifierClasses, elements, atypeFactory);
+ this.atypeFactory = atypeFactory;
+ this.types = atypeFactory.getChecker().getTypeUtils();
+ this.unionKind = getQualifierKind(Union.class.getCanonicalName());
+ }
+
+ @Override
+ protected boolean isSubtypeWithElements(
+ AnnotationMirror subAnno, QualifierKind subKind, AnnotationMirror
superAnno, QualifierKind superKind) {
+ // Both subKind and superKind are the Union kind: @Union(S1) <:
@Union(S2) iff every type
+ // in S1 is a subtype of some type in S2.
+ List<TypeMirror> superTypes = atypeFactory.getUnionTypes(superAnno);
+ for (TypeMirror subType : atypeFactory.getUnionTypes(subAnno)) {
+ if (!isSubtypeOfAny(subType, superTypes)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean isSubtypeOfAny(TypeMirror subType, List<TypeMirror>
superTypes) {
+ for (TypeMirror superType : superTypes) {
+ if (types.isSubtype(subType, superType)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ protected AnnotationMirror leastUpperBoundWithElements(
+ AnnotationMirror a1,
+ QualifierKind qualifierKind1,
+ AnnotationMirror a2,
+ QualifierKind qualifierKind2,
+ QualifierKind lubKind) {
+ // The lub kind has elements, i.e. is the Union kind. Since
UnionBottom is the only other
+ // kind without elements that can occur here (the lub of @Union and
@UnknownUnion is
+ // @UnknownUnion, which has no elements and is therefore handled
before this method is
+ // called), the lub of @Union(S) and @UnionBottom is @Union(S).
+ if (qualifierKind1 != unionKind) {
+ return a2;
+ }
+ if (qualifierKind2 != unionKind) {
+ return a1;
+ }
+ List<TypeMirror> types1 = atypeFactory.getUnionTypes(a1);
+ List<TypeMirror> union = new ArrayList<>(types1);
+ boolean changed = false;
+ for (TypeMirror type2 : atypeFactory.getUnionTypes(a2)) {
+ if (!containsSameType(union, type2)) {
+ union.add(type2);
+ changed = true;
+ }
+ }
+ return changed ? atypeFactory.createUnion(union) : a1;
+ }
+
+ @Override
+ protected AnnotationMirror greatestLowerBoundWithElements(
+ AnnotationMirror a1,
+ QualifierKind qualifierKind1,
+ AnnotationMirror a2,
+ QualifierKind qualifierKind2,
+ QualifierKind glbKind) {
+ // The glb kind has elements, i.e. is the Union kind. @UnionBottom
can't occur here because
+ // the glb of @Union(S) and @UnionBottom is @UnionBottom, which has no
elements and is
+ // therefore handled before this method is called. The only other kind
without elements is
+ // @UnknownUnion, and the glb of @Union(S) and @UnknownUnion is
@Union(S).
+ if (qualifierKind1 != unionKind) {
+ return a2;
+ }
+ if (qualifierKind2 != unionKind) {
+ return a1;
+ }
+ List<TypeMirror> types1 = atypeFactory.getUnionTypes(a1);
+ List<TypeMirror> types2 = atypeFactory.getUnionTypes(a2);
+ if (sameTypes(types1, types2)) {
+ return a1;
+ }
+ return atypeFactory.createUnion(List.of());
+ }
+
+ private boolean containsSameType(List<TypeMirror> list, TypeMirror type) {
+ for (TypeMirror element : list) {
+ if (types.isSameType(element, type)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean sameTypes(List<TypeMirror> types1, List<TypeMirror>
types2) {
+ if (types1.size() != types2.size()) {
+ return false;
+ }
+ for (TypeMirror type1 : types1) {
+ if (!containsSameType(types2, type1)) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git
a/buildutils/union-checker/src/main/java/org/apache/axiom/checker/union/UnionTransfer.java
b/buildutils/union-checker/src/main/java/org/apache/axiom/checker/union/UnionTransfer.java
new file mode 100644
index 000000000..398a4ed7e
--- /dev/null
+++
b/buildutils/union-checker/src/main/java/org/apache/axiom/checker/union/UnionTransfer.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.axiom.checker.union;
+
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.util.Types;
+import org.checkerframework.dataflow.analysis.ConditionalTransferResult;
+import org.checkerframework.dataflow.analysis.TransferInput;
+import org.checkerframework.dataflow.analysis.TransferResult;
+import org.checkerframework.dataflow.cfg.node.InstanceOfNode;
+import org.checkerframework.dataflow.expression.JavaExpression;
+import org.checkerframework.framework.flow.CFAbstractAnalysis;
+import org.checkerframework.framework.flow.CFStore;
+import org.checkerframework.framework.flow.CFTransfer;
+import org.checkerframework.framework.flow.CFValue;
+
+/**
+ * Refines the type of the tested expression to {@code @Union(types = {T})},
where {@code T} is the
+ * type tested against, in the "then" branch of an {@code instanceof} check.
Combined with the
+ * least upper bound computed by {@link UnionQualifierHierarchy} at
control-flow join points, this
+ * makes checks such as {@code x instanceof A || x instanceof B} and the
equivalent {@code if}/{@code
+ * else if} chain refine {@code x} to {@code @Union(types = {A, B})}.
+ */
+final class UnionTransfer extends CFTransfer {
+
+ private final UnionAnnotatedTypeFactory atypeFactory;
+ private final Types types;
+
+ UnionTransfer(CFAbstractAnalysis<CFValue, CFStore, CFTransfer> analysis) {
+ super(analysis);
+ atypeFactory = (UnionAnnotatedTypeFactory) analysis.getTypeFactory();
+ types = atypeFactory.getChecker().getTypeUtils();
+ }
+
+ @Override
+ public TransferResult<CFValue, CFStore> visitInstanceOf(InstanceOfNode
node, TransferInput<CFValue, CFStore> in) {
+ TransferResult<CFValue, CFStore> result = super.visitInstanceOf(node,
in);
+
+ JavaExpression expr = JavaExpression.fromNode(node.getOperand());
+ AnnotationMirror refined =
atypeFactory.createUnion(types.erasure(node.getRefType()));
+
+ CFStore thenStore;
+ CFStore elseStore;
+ if (result.containsTwoStores()) {
+ thenStore = result.getThenStore();
+ elseStore = result.getElseStore();
+ } else {
+ thenStore = result.getRegularStore();
+ elseStore = thenStore.copy();
+ }
+ thenStore.insertValue(expr, refined);
+ return new ConditionalTransferResult<>(result.getResultValue(),
thenStore, elseStore);
+ }
+}
diff --git
a/buildutils/union-checker/src/main/java/org/apache/axiom/checker/union/UnionTreeAnnotator.java
b/buildutils/union-checker/src/main/java/org/apache/axiom/checker/union/UnionTreeAnnotator.java
new file mode 100644
index 000000000..08bebcd88
--- /dev/null
+++
b/buildutils/union-checker/src/main/java/org/apache/axiom/checker/union/UnionTreeAnnotator.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.axiom.checker.union;
+
+import com.sun.source.tree.ConditionalExpressionTree;
+import javax.lang.model.element.AnnotationMirror;
+import org.checkerframework.framework.type.AnnotatedTypeMirror;
+import org.checkerframework.framework.type.treeannotator.TreeAnnotator;
+import org.checkerframework.javacutil.AnnotationUtils;
+
+/**
+ * Improves the type computed for a conditional expression ({@code cond ? a :
b}) where one branch
+ * is {@code @Union(types = {...})} and the other is the default {@code
@UnknownUnion}.
+ *
+ * <p>By default, the least upper bound of {@code @Union(S)} and {@code
@UnknownUnion} is {@code
+ * @UnknownUnion} (the top of the hierarchy), since {@code @UnknownUnion} has
no {@link
+ * Union#types()} to take the union with. This is overly conservative when the
+ * {@code @UnknownUnion}-typed branch's own (erased) type is itself a subtype
of a member of {@code
+ * S}: in that case, {@link UnionTypeHierarchy}'s escape rule already
establishes {@code
+ * @UnknownUnion T <: @Union(S)}, so {@code @Union(S)} is itself a valid (and
more useful) upper
+ * bound for both branches.
+ *
+ * <p>This allows expressions such as {@code data == null ? "" : data}, where
{@code data} is
+ * {@code @Union(types = {String.class, CharacterData.class}) Object}, to be
used directly (e.g. in
+ * a {@code return} statement) without an explicit cast.
+ */
+final class UnionTreeAnnotator extends TreeAnnotator {
+
+ private final UnionAnnotatedTypeFactory atypeFactory;
+
+ UnionTreeAnnotator(UnionAnnotatedTypeFactory atypeFactory) {
+ super(atypeFactory);
+ this.atypeFactory = atypeFactory;
+ }
+
+ @Override
+ public Void visitConditionalExpression(ConditionalExpressionTree tree,
AnnotatedTypeMirror type) {
+ AnnotatedTypeMirror thenType =
atypeFactory.getAnnotatedType(tree.getTrueExpression());
+ AnnotatedTypeMirror elseType =
atypeFactory.getAnnotatedType(tree.getFalseExpression());
+ AnnotationMirror promoted = promote(thenType, elseType);
+ if (promoted == null) {
+ promoted = promote(elseType, thenType);
+ }
+ if (promoted != null) {
+ type.replaceAnnotation(promoted);
+ }
+ return super.visitConditionalExpression(tree, type);
+ }
+
+ /**
+ * If {@code unionSide} is {@code @Union(S)} and {@code unknownSide} is
{@code @UnknownUnion}
+ * with an underlying type that is itself a subtype of some member of
{@code S}, returns {@code
+ * @Union(S)}. Otherwise returns {@code null}.
+ */
+ private AnnotationMirror promote(AnnotatedTypeMirror unionSide,
AnnotatedTypeMirror unknownSide) {
+ AnnotationMirror unionAnno =
unionSide.getPrimaryAnnotationInHierarchy(atypeFactory.UNKNOWN_UNION);
+ if (unionAnno == null || !AnnotationUtils.areSameByName(unionAnno,
Union.class.getCanonicalName())) {
+ return null;
+ }
+ AnnotationMirror unknownAnno =
unknownSide.getPrimaryAnnotationInHierarchy(atypeFactory.UNKNOWN_UNION);
+ if (unknownAnno == null || !AnnotationUtils.areSameByName(unknownAnno,
UnknownUnion.class.getCanonicalName())) {
+ return null;
+ }
+ return
atypeFactory.isSubtypeOfUnionMember(unknownSide.getUnderlyingType(), unionAnno)
? unionAnno : null;
+ }
+}
diff --git
a/buildutils/union-checker/src/main/java/org/apache/axiom/checker/union/UnionTypeHierarchy.java
b/buildutils/union-checker/src/main/java/org/apache/axiom/checker/union/UnionTypeHierarchy.java
new file mode 100644
index 000000000..95ebfc5eb
--- /dev/null
+++
b/buildutils/union-checker/src/main/java/org/apache/axiom/checker/union/UnionTypeHierarchy.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.axiom.checker.union;
+
+import javax.lang.model.element.AnnotationMirror;
+import org.checkerframework.common.basetype.BaseTypeChecker;
+import org.checkerframework.framework.type.AnnotatedTypeMirror;
+import org.checkerframework.framework.type.DefaultTypeHierarchy;
+import org.checkerframework.framework.type.QualifierHierarchy;
+import org.checkerframework.javacutil.AnnotationUtils;
+
+/**
+ * Adds an escape rule to the default subtyping rules: a value of
unconstrained type ({@code
+ * @UnknownUnion}) may be assigned to a {@code @Union(types =
{...})}-annotated location if its
+ * underlying (erased) Java type is itself a subtype of one of {@link
Union#types()}. This allows,
+ * for example, a {@link String}-typed expression to be returned as {@code
@Union(types =
+ * {String.class, ...}) Object} without an explicit cast.
+ */
+final class UnionTypeHierarchy extends DefaultTypeHierarchy {
+
+ private final UnionAnnotatedTypeFactory atypeFactory;
+
+ UnionTypeHierarchy(
+ BaseTypeChecker checker,
+ QualifierHierarchy qualHierarchy,
+ boolean ignoreRawTypes,
+ boolean invariantArrayComponents,
+ UnionAnnotatedTypeFactory atypeFactory) {
+ super(checker, qualHierarchy, ignoreRawTypes,
invariantArrayComponents);
+ this.atypeFactory = atypeFactory;
+ }
+
+ @Override
+ public boolean isSubtype(AnnotatedTypeMirror subtype, AnnotatedTypeMirror
supertype) {
+ if (super.isSubtype(subtype, supertype)) {
+ return true;
+ }
+ AnnotationMirror superAnno =
supertype.getPrimaryAnnotationInHierarchy(atypeFactory.UNKNOWN_UNION);
+ if (superAnno == null || !AnnotationUtils.areSameByName(superAnno,
Union.class.getCanonicalName())) {
+ return false;
+ }
+ AnnotationMirror subAnno =
subtype.getPrimaryAnnotationInHierarchy(atypeFactory.UNKNOWN_UNION);
+ if (subAnno == null || !AnnotationUtils.areSameByName(subAnno,
UnknownUnion.class.getCanonicalName())) {
+ return false;
+ }
+ return
atypeFactory.isSubtypeOfUnionMember(subtype.getUnderlyingType(), superAnno);
+ }
+}
diff --git a/components/core-streams/pom.xml b/components/core-streams/pom.xml
index 71d46b441..67912a443 100644
--- a/components/core-streams/pom.xml
+++ b/components/core-streams/pom.xml
@@ -37,7 +37,7 @@
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
- <artifactId>checker-annotations</artifactId>
+ <artifactId>union-annotations</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
@@ -122,7 +122,7 @@
<annotationProcessorPaths combine.children="append">
<annotationProcessorPath>
<groupId>${project.groupId}</groupId>
-
<artifactId>stringorcharacterdata-checker</artifactId>
+ <artifactId>union-checker</artifactId>
<version>${project.version}</version>
</annotationProcessorPath>
</annotationProcessorPaths>
diff --git
a/components/core-streams/src/main/java/org/apache/axiom/core/stream/CharArrayCharacterData.java
b/components/core-streams/src/main/java/org/apache/axiom/core/stream/CharArrayCharacterData.java
index 1752b338d..756554030 100644
---
a/components/core-streams/src/main/java/org/apache/axiom/core/stream/CharArrayCharacterData.java
+++
b/components/core-streams/src/main/java/org/apache/axiom/core/stream/CharArrayCharacterData.java
@@ -19,8 +19,7 @@
package org.apache.axiom.core.stream;
import java.io.IOException;
-import org.apache.axiom.core.stream.annotations.StringOrCharacterData;
-import org.apache.axiom.core.stream.annotations.UnknownCharacterDataType;
+import org.apache.axiom.checker.union.Union;
/**
* A reusable {@link CharacterData} implementation backed by a {@code char[]}
slice. Instances are
@@ -53,7 +52,7 @@ public final class CharArrayCharacterData implements
CharacterData {
}
@Override
- public String toString(@UnknownCharacterDataType CharArrayCharacterData
this) {
+ public String toString() {
return new String(ch, start, length);
}
@@ -68,7 +67,7 @@ public final class CharArrayCharacterData implements
CharacterData {
}
@Override
- public @StringOrCharacterData Object retain() {
+ public @Union(types = {String.class, CharacterData.class}) Object retain()
{
return new String(ch, start, length);
}
}
diff --git
a/components/core-streams/src/main/java/org/apache/axiom/core/stream/CharacterData.java
b/components/core-streams/src/main/java/org/apache/axiom/core/stream/CharacterData.java
index 5b2cbed07..1ec64322c 100644
---
a/components/core-streams/src/main/java/org/apache/axiom/core/stream/CharacterData.java
+++
b/components/core-streams/src/main/java/org/apache/axiom/core/stream/CharacterData.java
@@ -19,8 +19,7 @@
package org.apache.axiom.core.stream;
import java.io.IOException;
-import org.apache.axiom.core.stream.annotations.StringOrCharacterData;
-import org.apache.axiom.core.stream.annotations.UnknownCharacterDataType;
+import org.apache.axiom.checker.union.Union;
// TODO: clean up this Javadoc
/**
@@ -30,7 +29,7 @@ import
org.apache.axiom.core.stream.annotations.UnknownCharacterDataType;
*/
public interface CharacterData {
@Override
- String toString(@UnknownCharacterDataType CharacterData this);
+ String toString();
void writeTo(CharacterDataSink sink) throws IOException;
@@ -51,6 +50,6 @@ public interface CharacterData {
* @return a {@link String} or {@link CharacterData} representation of
this instance that
* remains valid beyond the current invocation
*/
- @StringOrCharacterData
+ @Union(types = {String.class, CharacterData.class})
Object retain();
}
diff --git
a/components/core-streams/src/main/java/org/apache/axiom/core/stream/DocumentElementExtractingFilterHandler.java
b/components/core-streams/src/main/java/org/apache/axiom/core/stream/DocumentElementExtractingFilterHandler.java
index 7206b41e2..3791754c5 100644
---
a/components/core-streams/src/main/java/org/apache/axiom/core/stream/DocumentElementExtractingFilterHandler.java
+++
b/components/core-streams/src/main/java/org/apache/axiom/core/stream/DocumentElementExtractingFilterHandler.java
@@ -18,7 +18,7 @@
*/
package org.apache.axiom.core.stream;
-import org.apache.axiom.core.stream.annotations.StringOrCharacterData;
+import org.apache.axiom.checker.union.Union;
public final class DocumentElementExtractingFilterHandler extends
XmlHandlerWrapper {
private int depth;
@@ -54,7 +54,8 @@ public final class DocumentElementExtractingFilterHandler
extends XmlHandlerWrap
throws StreamException {}
@Override
- public void processCharacterData(@StringOrCharacterData Object data,
boolean ignorable) throws StreamException {
+ public void processCharacterData(@Union(types = {String.class,
CharacterData.class}) Object data, boolean ignorable)
+ throws StreamException {
if (depth > 0) {
super.processCharacterData(data, ignorable);
}
diff --git
a/components/core-streams/src/main/java/org/apache/axiom/core/stream/XmlHandler.java
b/components/core-streams/src/main/java/org/apache/axiom/core/stream/XmlHandler.java
index bf66d885c..7d1b228a8 100644
---
a/components/core-streams/src/main/java/org/apache/axiom/core/stream/XmlHandler.java
+++
b/components/core-streams/src/main/java/org/apache/axiom/core/stream/XmlHandler.java
@@ -18,7 +18,7 @@
*/
package org.apache.axiom.core.stream;
-import org.apache.axiom.core.stream.annotations.StringOrCharacterData;
+import org.apache.axiom.checker.union.Union;
public interface XmlHandler {
void startDocument(String inputEncoding, String xmlVersion, String
xmlEncoding, Boolean standalone)
@@ -123,7 +123,8 @@ public interface XmlHandler {
* otherwise
* @throws StreamException if an error occurs when processing the event
*/
- void processCharacterData(@StringOrCharacterData Object data, boolean
ignorable) throws StreamException;
+ void processCharacterData(@Union(types = {String.class,
CharacterData.class}) Object data, boolean ignorable)
+ throws StreamException;
/**
* Notify the handler of the beginning of a processing instruction.
diff --git
a/components/core-streams/src/main/java/org/apache/axiom/core/stream/XmlHandlerWrapper.java
b/components/core-streams/src/main/java/org/apache/axiom/core/stream/XmlHandlerWrapper.java
index 2635f6ead..45213b62f 100644
---
a/components/core-streams/src/main/java/org/apache/axiom/core/stream/XmlHandlerWrapper.java
+++
b/components/core-streams/src/main/java/org/apache/axiom/core/stream/XmlHandlerWrapper.java
@@ -18,7 +18,7 @@
*/
package org.apache.axiom.core.stream;
-import org.apache.axiom.core.stream.annotations.StringOrCharacterData;
+import org.apache.axiom.checker.union.Union;
public class XmlHandlerWrapper implements XmlHandler {
private final XmlHandler parent;
@@ -81,7 +81,8 @@ public class XmlHandlerWrapper implements XmlHandler {
}
@Override
- public void processCharacterData(@StringOrCharacterData Object data,
boolean ignorable) throws StreamException {
+ public void processCharacterData(@Union(types = {String.class,
CharacterData.class}) Object data, boolean ignorable)
+ throws StreamException {
parent.processCharacterData(data, ignorable);
}
diff --git
a/components/core-streams/src/main/java/org/apache/axiom/core/stream/stax/push/input/InternalXMLStreamWriter.java
b/components/core-streams/src/main/java/org/apache/axiom/core/stream/stax/push/input/InternalXMLStreamWriter.java
index a410184a7..640ce81ec 100644
---
a/components/core-streams/src/main/java/org/apache/axiom/core/stream/stax/push/input/InternalXMLStreamWriter.java
+++
b/components/core-streams/src/main/java/org/apache/axiom/core/stream/stax/push/input/InternalXMLStreamWriter.java
@@ -20,8 +20,9 @@ package org.apache.axiom.core.stream.stax.push.input;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
-import org.apache.axiom.core.stream.annotations.StringOrCharacterData;
+import org.apache.axiom.checker.union.Union;
+import org.apache.axiom.core.stream.CharacterData;
public interface InternalXMLStreamWriter extends XMLStreamWriter {
- void writeCharacterData(@StringOrCharacterData Object data) throws
XMLStreamException;
+ void writeCharacterData(@Union(types = {String.class,
CharacterData.class}) Object data) throws XMLStreamException;
}
diff --git
a/components/core-streams/src/main/java/org/apache/axiom/core/stream/stax/push/input/XmlHandlerStreamWriter.java
b/components/core-streams/src/main/java/org/apache/axiom/core/stream/stax/push/input/XmlHandlerStreamWriter.java
index 8b5f2ff05..dceedc544 100644
---
a/components/core-streams/src/main/java/org/apache/axiom/core/stream/stax/push/input/XmlHandlerStreamWriter.java
+++
b/components/core-streams/src/main/java/org/apache/axiom/core/stream/stax/push/input/XmlHandlerStreamWriter.java
@@ -26,9 +26,10 @@ import java.util.NoSuchElementException;
import javax.xml.XMLConstants;
import javax.xml.namespace.NamespaceContext;
import javax.xml.stream.XMLStreamException;
+import org.apache.axiom.checker.union.Union;
+import org.apache.axiom.core.stream.CharacterData;
import org.apache.axiom.core.stream.StreamException;
import org.apache.axiom.core.stream.XmlHandler;
-import org.apache.axiom.core.stream.annotations.StringOrCharacterData;
import org.apache.axiom.core.stream.serializer.Serializer;
import
org.apache.axiom.core.stream.serializer.writer.UnmappableCharacterHandler;
import org.apache.commons.logging.Log;
@@ -362,7 +363,8 @@ public final class XmlHandlerStreamWriter implements
InternalXMLStreamWriter, Na
}
@Override
- public void writeCharacterData(@StringOrCharacterData Object data) throws
XMLStreamException {
+ public void writeCharacterData(@Union(types = {String.class,
CharacterData.class}) Object data)
+ throws XMLStreamException {
finishStartElement();
try {
handler.processCharacterData(data, false);
diff --git
a/components/core-streams/src/main/java/org/apache/axiom/core/stream/xop/AbstractXOPDecodingFilterHandler.java
b/components/core-streams/src/main/java/org/apache/axiom/core/stream/xop/AbstractXOPDecodingFilterHandler.java
index 65a61e6d6..d442e8e61 100644
---
a/components/core-streams/src/main/java/org/apache/axiom/core/stream/xop/AbstractXOPDecodingFilterHandler.java
+++
b/components/core-streams/src/main/java/org/apache/axiom/core/stream/xop/AbstractXOPDecodingFilterHandler.java
@@ -21,10 +21,11 @@ package org.apache.axiom.core.stream.xop;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import javax.xml.namespace.QName;
+import org.apache.axiom.checker.union.Union;
+import org.apache.axiom.core.stream.CharacterData;
import org.apache.axiom.core.stream.StreamException;
import org.apache.axiom.core.stream.XmlHandler;
import org.apache.axiom.core.stream.XmlHandlerWrapper;
-import org.apache.axiom.core.stream.annotations.StringOrCharacterData;
public abstract class AbstractXOPDecodingFilterHandler extends
XmlHandlerWrapper {
private static final String SOLE_CHILD_MSG =
@@ -45,7 +46,8 @@ public abstract class AbstractXOPDecodingFilterHandler
extends XmlHandlerWrapper
super(parent);
}
- protected abstract @StringOrCharacterData Object buildCharacterData(String
contentID) throws StreamException;
+ protected abstract @Union(types = {String.class, CharacterData.class})
Object buildCharacterData(String contentID)
+ throws StreamException;
private void inContent() throws StreamException {
switch (state) {
@@ -129,7 +131,8 @@ public abstract class AbstractXOPDecodingFilterHandler
extends XmlHandlerWrapper
}
@Override
- public void processCharacterData(@StringOrCharacterData Object data,
boolean ignorable) throws StreamException {
+ public void processCharacterData(@Union(types = {String.class,
CharacterData.class}) Object data, boolean ignorable)
+ throws StreamException {
inContent();
super.processCharacterData(data, ignorable);
}
diff --git
a/components/core-streams/src/main/java/org/apache/axiom/core/stream/xop/AbstractXOPEncodingFilterHandler.java
b/components/core-streams/src/main/java/org/apache/axiom/core/stream/xop/AbstractXOPEncodingFilterHandler.java
index 41e618243..2acc4b0fc 100644
---
a/components/core-streams/src/main/java/org/apache/axiom/core/stream/xop/AbstractXOPEncodingFilterHandler.java
+++
b/components/core-streams/src/main/java/org/apache/axiom/core/stream/xop/AbstractXOPEncodingFilterHandler.java
@@ -18,10 +18,11 @@
*/
package org.apache.axiom.core.stream.xop;
+import org.apache.axiom.checker.union.Union;
+import org.apache.axiom.core.stream.CharacterData;
import org.apache.axiom.core.stream.StreamException;
import org.apache.axiom.core.stream.XmlHandler;
import org.apache.axiom.core.stream.XmlHandlerWrapper;
-import org.apache.axiom.core.stream.annotations.StringOrCharacterData;
public abstract class AbstractXOPEncodingFilterHandler extends
XmlHandlerWrapper {
private boolean inXOPInclude;
@@ -30,7 +31,8 @@ public abstract class AbstractXOPEncodingFilterHandler
extends XmlHandlerWrapper
super(parent);
}
- protected abstract String processCharacterData(@StringOrCharacterData
Object data) throws StreamException;
+ protected abstract String processCharacterData(@Union(types =
{String.class, CharacterData.class}) Object data)
+ throws StreamException;
/**
* Build a cid URL from the given content ID as described in RFC2392.
@@ -91,7 +93,8 @@ public abstract class AbstractXOPEncodingFilterHandler
extends XmlHandlerWrapper
}
@Override
- public void processCharacterData(@StringOrCharacterData Object data,
boolean ignorable) throws StreamException {
+ public void processCharacterData(@Union(types = {String.class,
CharacterData.class}) Object data, boolean ignorable)
+ throws StreamException {
if (!ignorable) {
String contentID = processCharacterData(data);
if (contentID != null) {
diff --git a/components/pom.xml b/components/pom.xml
index 26bd1b9f5..6d945feb7 100644
--- a/components/pom.xml
+++ b/components/pom.xml
@@ -34,7 +34,6 @@
<modules>
<module>base64-utils</module>
<module>blob</module>
- <module>checker-annotations</module>
<module>core-streams</module>
<module>io</module>
<module>namespace-utils</module>
diff --git a/mixins/core-mixins/pom.xml b/mixins/core-mixins/pom.xml
index 7ca286b79..cd06aa8d5 100644
--- a/mixins/core-mixins/pom.xml
+++ b/mixins/core-mixins/pom.xml
@@ -38,7 +38,7 @@
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
- <artifactId>checker-annotations</artifactId>
+ <artifactId>union-annotations</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
diff --git
a/mixins/core-mixins/src/main/java/org/apache/axiom/core/CoreCharacterDataNode.java
b/mixins/core-mixins/src/main/java/org/apache/axiom/core/CoreCharacterDataNode.java
index ce5d9c2c5..ee410b99f 100644
---
a/mixins/core-mixins/src/main/java/org/apache/axiom/core/CoreCharacterDataNode.java
+++
b/mixins/core-mixins/src/main/java/org/apache/axiom/core/CoreCharacterDataNode.java
@@ -18,14 +18,15 @@
*/
package org.apache.axiom.core;
-import org.apache.axiom.core.stream.annotations.StringOrCharacterData;
+import org.apache.axiom.checker.union.Union;
+import org.apache.axiom.core.stream.CharacterData;
public interface CoreCharacterDataNode extends CoreLeafNode,
CoreCharacterDataContainer {
@Override
- @StringOrCharacterData
+ @Union(types = {String.class, CharacterData.class})
Object coreGetCharacterData();
- void coreSetCharacterData(@StringOrCharacterData Object data);
+ void coreSetCharacterData(@Union(types = {String.class,
CharacterData.class}) Object data);
/**
* Check whether this text node contains element content whitespace (also
called "ignorable
diff --git
a/mixins/core-mixins/src/main/java/org/apache/axiom/core/CoreCharacterDataSinkNode.java
b/mixins/core-mixins/src/main/java/org/apache/axiom/core/CoreCharacterDataSinkNode.java
index 26c4efbdc..032072417 100644
---
a/mixins/core-mixins/src/main/java/org/apache/axiom/core/CoreCharacterDataSinkNode.java
+++
b/mixins/core-mixins/src/main/java/org/apache/axiom/core/CoreCharacterDataSinkNode.java
@@ -18,8 +18,10 @@
*/
package org.apache.axiom.core;
-import org.apache.axiom.core.stream.annotations.StringOrCharacterData;
+import org.apache.axiom.checker.union.Union;
+import org.apache.axiom.core.stream.CharacterData;
public interface CoreCharacterDataSinkNode {
- void coreSetCharacterData(@StringOrCharacterData Object data, Semantics
semantics) throws CoreModelException;
+ void coreSetCharacterData(@Union(types = {String.class,
CharacterData.class}) Object data, Semantics semantics)
+ throws CoreModelException;
}
diff --git
a/mixins/core-mixins/src/main/java/org/apache/axiom/core/CoreCharacterDataSourceNode.java
b/mixins/core-mixins/src/main/java/org/apache/axiom/core/CoreCharacterDataSourceNode.java
index 9c147e10f..8f931f6a0 100644
---
a/mixins/core-mixins/src/main/java/org/apache/axiom/core/CoreCharacterDataSourceNode.java
+++
b/mixins/core-mixins/src/main/java/org/apache/axiom/core/CoreCharacterDataSourceNode.java
@@ -18,9 +18,10 @@
*/
package org.apache.axiom.core;
-import org.apache.axiom.core.stream.annotations.StringOrCharacterData;
+import org.apache.axiom.checker.union.Union;
+import org.apache.axiom.core.stream.CharacterData;
public interface CoreCharacterDataSourceNode extends CoreNode {
- @StringOrCharacterData
+ @Union(types = {String.class, CharacterData.class})
Object coreGetCharacterData() throws CoreModelException;
}
diff --git
a/mixins/core-mixins/src/main/java/org/apache/axiom/core/CoreMixedContentContainer.java
b/mixins/core-mixins/src/main/java/org/apache/axiom/core/CoreMixedContentContainer.java
index a68497dda..02b858dd1 100644
---
a/mixins/core-mixins/src/main/java/org/apache/axiom/core/CoreMixedContentContainer.java
+++
b/mixins/core-mixins/src/main/java/org/apache/axiom/core/CoreMixedContentContainer.java
@@ -18,9 +18,10 @@
*/
package org.apache.axiom.core;
-import org.apache.axiom.core.stream.annotations.StringOrCharacterData;
+import org.apache.axiom.checker.union.Union;
+import org.apache.axiom.core.stream.CharacterData;
public interface CoreMixedContentContainer extends CoreParentNode,
CoreCharacterDataSinkNode {
- @StringOrCharacterData
+ @Union(types = {String.class, CharacterData.class})
Object coreGetCharacterData(ElementAction elementAction) throws
CoreModelException;
}
diff --git
a/mixins/core-mixins/src/main/java/org/apache/axiom/core/CoreParentNode.java
b/mixins/core-mixins/src/main/java/org/apache/axiom/core/CoreParentNode.java
index 2792de09e..2d1f2338b 100644
--- a/mixins/core-mixins/src/main/java/org/apache/axiom/core/CoreParentNode.java
+++ b/mixins/core-mixins/src/main/java/org/apache/axiom/core/CoreParentNode.java
@@ -18,10 +18,11 @@
*/
package org.apache.axiom.core;
+import org.apache.axiom.checker.union.Union;
+import org.apache.axiom.core.stream.CharacterData;
import org.apache.axiom.core.stream.StreamException;
import org.apache.axiom.core.stream.XmlHandler;
import org.apache.axiom.core.stream.XmlReader;
-import org.apache.axiom.core.stream.annotations.StringOrCharacterData;
/** Interface for parent nodes. */
public interface CoreParentNode extends CoreNode {
@@ -102,7 +103,8 @@ public interface CoreParentNode extends CoreNode {
Mapper<S, ? super T> mapper,
Semantics semantics);
- void coreSetCharacterData(@StringOrCharacterData Object data, Semantics
semantics) throws CoreModelException;
+ void coreSetCharacterData(@Union(types = {String.class,
CharacterData.class}) Object data, Semantics semantics)
+ throws CoreModelException;
void coreRemoveChildren(Semantics semantics) throws CoreModelException;
@@ -118,6 +120,6 @@ public interface CoreParentNode extends CoreNode {
Content internalGetContent(boolean create);
- @StringOrCharacterData
+ @Union(types = {String.class, CharacterData.class})
Object internalGetCharacterData(ElementAction elementAction) throws
CoreModelException;
}
diff --git
a/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/AbstractNodeIterator.java
b/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/AbstractNodeIterator.java
index 943b20aa1..95eda5b2f 100644
---
a/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/AbstractNodeIterator.java
+++
b/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/AbstractNodeIterator.java
@@ -136,7 +136,7 @@ public abstract class AbstractNodeIterator<T extends
CoreNode, S> implements Nod
}
@Override
- @SuppressWarnings("stringorcharacterdata")
+ @SuppressWarnings("union")
public final S next() {
if (hasNext()) {
currentNode = nextNode;
diff --git
a/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/TreeWalkerImpl.java
b/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/TreeWalkerImpl.java
index cfebe91d4..848c72be9 100644
---
a/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/TreeWalkerImpl.java
+++
b/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/TreeWalkerImpl.java
@@ -15,6 +15,7 @@
*/
package org.apache.axiom.core.impl;
+import org.apache.axiom.checker.union.Union;
import org.apache.axiom.core.CoreAttribute;
import org.apache.axiom.core.CoreChildNode;
import org.apache.axiom.core.CoreDocument;
@@ -27,6 +28,7 @@ import org.apache.axiom.core.CoreNode;
import org.apache.axiom.core.CoreParentNode;
import org.apache.axiom.core.InputContext;
import org.apache.axiom.core.NodeConsumedException;
+import org.apache.axiom.core.stream.CharacterData;
import org.apache.axiom.core.stream.DocumentElementExtractingFilterHandler;
import org.apache.axiom.core.stream.StreamException;
import org.apache.axiom.core.stream.XmlHandler;
@@ -258,10 +260,10 @@ public final class TreeWalkerImpl implements XmlReader {
}
}
case STATE_CONTENT_VISITED -> {
- @SuppressWarnings("stringorcharacterdata")
-
@org.apache.axiom.core.stream.annotations.StringOrCharacterData
- Object data = ((CoreParentNode)
nextNode).internalGetContent();
- handler.processCharacterData(data, false);
+ handler.processCharacterData(
+ (@Union(types = {String.class,
CharacterData.class}) Object)
+ ((CoreParentNode)
nextNode).internalGetContent(),
+ false);
}
default -> throw new IllegalStateException();
}
diff --git
a/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/builder/BuildableContext.java
b/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/builder/BuildableContext.java
index d460fe3b0..e5c476846 100644
---
a/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/builder/BuildableContext.java
+++
b/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/builder/BuildableContext.java
@@ -18,6 +18,7 @@
*/
package org.apache.axiom.core.impl.builder;
+import org.apache.axiom.checker.union.Union;
import org.apache.axiom.core.Builder;
import org.apache.axiom.core.CoreCDATASection;
import org.apache.axiom.core.CoreCharacterDataNode;
@@ -40,14 +41,13 @@ import org.apache.axiom.core.stream.CharacterData;
import org.apache.axiom.core.stream.NullXmlHandler;
import org.apache.axiom.core.stream.StreamException;
import org.apache.axiom.core.stream.XmlHandler;
-import org.apache.axiom.core.stream.annotations.StringOrCharacterData;
final class BuildableContext extends Context implements InputContext {
private final Context parentContext;
private CoreParentNode target;
- private @StringOrCharacterData Object pendingCharacterData;
+ private @Union(types = {String.class, CharacterData.class}) Object
pendingCharacterData;
/**
* The {@link XmlHandler} object to send events to if pass-through is
enabled. See {@link
@@ -261,7 +261,8 @@ final class BuildableContext extends Context implements
InputContext {
}
@Override
- void processCharacterData(@StringOrCharacterData Object data, boolean
ignorable) throws StreamException {
+ void processCharacterData(@Union(types = {String.class,
CharacterData.class}) Object data, boolean ignorable)
+ throws StreamException {
if (passThroughHandler != null) {
passThroughHandler.processCharacterData(data, ignorable);
} else if (!ignorable && pendingCharacterData == null &&
target.coreGetFirstChildIfAvailable() == null) {
diff --git
a/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/builder/BuilderHandler.java
b/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/builder/BuilderHandler.java
index 0eacd7772..75d949cd8 100644
---
a/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/builder/BuilderHandler.java
+++
b/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/builder/BuilderHandler.java
@@ -21,15 +21,16 @@ package org.apache.axiom.core.impl.builder;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
+import org.apache.axiom.checker.union.Union;
import org.apache.axiom.core.Builder;
import org.apache.axiom.core.CoreDocument;
import org.apache.axiom.core.CoreNSAwareElement;
import org.apache.axiom.core.CoreNode;
import org.apache.axiom.core.DeferredParsingException;
import org.apache.axiom.core.NodeFactory;
+import org.apache.axiom.core.stream.CharacterData;
import org.apache.axiom.core.stream.StreamException;
import org.apache.axiom.core.stream.XmlHandler;
-import org.apache.axiom.core.stream.annotations.StringOrCharacterData;
final class BuilderHandler implements XmlHandler {
final NodeFactory nodeFactory;
@@ -177,7 +178,8 @@ final class BuilderHandler implements XmlHandler {
}
@Override
- public void processCharacterData(@StringOrCharacterData Object data,
boolean ignorable) throws StreamException {
+ public void processCharacterData(@Union(types = {String.class,
CharacterData.class}) Object data, boolean ignorable)
+ throws StreamException {
context.processCharacterData(data, ignorable);
}
diff --git
a/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/builder/Context.java
b/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/builder/Context.java
index 9efe7fe71..26e943676 100644
---
a/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/builder/Context.java
+++
b/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/builder/Context.java
@@ -18,9 +18,10 @@
*/
package org.apache.axiom.core.impl.builder;
+import org.apache.axiom.checker.union.Union;
import org.apache.axiom.core.CoreParentNode;
+import org.apache.axiom.core.stream.CharacterData;
import org.apache.axiom.core.stream.StreamException;
-import org.apache.axiom.core.stream.annotations.StringOrCharacterData;
abstract class Context {
protected final BuilderHandler builderHandler;
@@ -63,7 +64,8 @@ abstract class Context {
abstract void attributesCompleted() throws StreamException;
- abstract void processCharacterData(@StringOrCharacterData Object data,
boolean ignorable) throws StreamException;
+ abstract void processCharacterData(
+ @Union(types = {String.class, CharacterData.class}) Object data,
boolean ignorable) throws StreamException;
abstract Context startProcessingInstruction(String piTarget) throws
StreamException;
diff --git
a/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/builder/UnwrappingContext.java
b/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/builder/UnwrappingContext.java
index 7d163dd03..56fd708f7 100644
---
a/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/builder/UnwrappingContext.java
+++
b/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/builder/UnwrappingContext.java
@@ -18,10 +18,11 @@
*/
package org.apache.axiom.core.impl.builder;
+import org.apache.axiom.checker.union.Union;
import org.apache.axiom.core.CoreNSAwareElement;
import org.apache.axiom.core.CoreParentNode;
+import org.apache.axiom.core.stream.CharacterData;
import org.apache.axiom.core.stream.StreamException;
-import org.apache.axiom.core.stream.annotations.StringOrCharacterData;
final class UnwrappingContext extends Context {
private final CoreNSAwareElement root;
@@ -88,7 +89,8 @@ final class UnwrappingContext extends Context {
}
@Override
- void processCharacterData(@StringOrCharacterData Object data, boolean
ignorable) throws StreamException {
+ void processCharacterData(@Union(types = {String.class,
CharacterData.class}) Object data, boolean ignorable)
+ throws StreamException {
// TODO Auto-generated method stub
}
diff --git
a/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/mixin/CoreCharacterDataContainingParentNodeMixin.java
b/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/mixin/CoreCharacterDataContainingParentNodeMixin.java
index a7796a8bf..78f0b8691 100644
---
a/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/mixin/CoreCharacterDataContainingParentNodeMixin.java
+++
b/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/mixin/CoreCharacterDataContainingParentNodeMixin.java
@@ -18,17 +18,20 @@
*/
package org.apache.axiom.core.impl.mixin;
+import org.apache.axiom.checker.union.Union;
import org.apache.axiom.core.CoreCharacterDataContainingParentNode;
import org.apache.axiom.core.CoreModelException;
import org.apache.axiom.core.ElementAction;
-import org.apache.axiom.core.stream.annotations.StringOrCharacterData;
+import org.apache.axiom.core.stream.CharacterData;
import org.apache.axiom.weaver.annotation.Mixin;
@Mixin
public abstract class CoreCharacterDataContainingParentNodeMixin implements
CoreCharacterDataContainingParentNode {
@Override
- public final @StringOrCharacterData Object coreGetCharacterData() throws
CoreModelException {
- @StringOrCharacterData Object characterData =
internalGetCharacterData(ElementAction.RETURN_NULL);
+ public final @Union(types = {String.class, CharacterData.class}) Object
coreGetCharacterData()
+ throws CoreModelException {
+ @Union(types = {String.class, CharacterData.class})
+ Object characterData =
internalGetCharacterData(ElementAction.RETURN_NULL);
if (characterData == null) {
throw new IllegalStateException();
}
diff --git
a/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/mixin/CoreCharacterDataNodeMixin.java
b/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/mixin/CoreCharacterDataNodeMixin.java
index f0729e82c..43f64e5dc 100644
---
a/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/mixin/CoreCharacterDataNodeMixin.java
+++
b/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/mixin/CoreCharacterDataNodeMixin.java
@@ -18,6 +18,7 @@
*/
package org.apache.axiom.core.impl.mixin;
+import org.apache.axiom.checker.union.Union;
import org.apache.axiom.core.ClonePolicy;
import org.apache.axiom.core.CloneableCharacterData;
import org.apache.axiom.core.CoreCharacterDataNode;
@@ -28,13 +29,12 @@ import org.apache.axiom.core.impl.Flags;
import org.apache.axiom.core.stream.CharacterData;
import org.apache.axiom.core.stream.StreamException;
import org.apache.axiom.core.stream.XmlHandler;
-import org.apache.axiom.core.stream.annotations.StringOrCharacterData;
import org.apache.axiom.weaver.annotation.Mixin;
@Mixin
public abstract class CoreCharacterDataNodeMixin implements
CoreCharacterDataNode {
/** Either a {@link String} or a {@link CharacterData} object. */
- private @StringOrCharacterData Object data;
+ private @Union(types = {String.class, CharacterData.class}) Object data;
@Override
public final NodeType coreGetNodeType() {
@@ -52,24 +52,26 @@ public abstract class CoreCharacterDataNodeMixin implements
CoreCharacterDataNod
}
@Override
- public final @StringOrCharacterData Object coreGetCharacterData() {
+ public final @Union(types = {String.class, CharacterData.class}) Object
coreGetCharacterData() {
return data == null ? "" : data;
}
@Override
- public final void coreSetCharacterData(@StringOrCharacterData Object data)
{
+ public final void coreSetCharacterData(@Union(types = {String.class,
CharacterData.class}) Object data) {
this.data = data;
}
@Override
- public final void coreSetCharacterData(@StringOrCharacterData Object data,
Semantics semantics) {
+ public final void coreSetCharacterData(
+ @Union(types = {String.class, CharacterData.class}) Object data,
Semantics semantics) {
this.data = data;
}
@Override
public final <T> void init(ClonePolicy<T> policy, T options, CoreNode
other) {
CoreCharacterDataNode o = (CoreCharacterDataNode) other;
- @StringOrCharacterData Object otherData = o.coreGetCharacterData();
+ @Union(types = {String.class, CharacterData.class})
+ Object otherData = o.coreGetCharacterData();
data = otherData instanceof CloneableCharacterData
cloneableCharacterData
? cloneableCharacterData.clone(policy, options)
: otherData;
diff --git
a/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/mixin/CoreMixedContentContainerMixin.java
b/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/mixin/CoreMixedContentContainerMixin.java
index e3ebd9354..5d71a6be9 100644
---
a/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/mixin/CoreMixedContentContainerMixin.java
+++
b/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/mixin/CoreMixedContentContainerMixin.java
@@ -18,17 +18,18 @@
*/
package org.apache.axiom.core.impl.mixin;
+import org.apache.axiom.checker.union.Union;
import org.apache.axiom.core.CoreMixedContentContainer;
import org.apache.axiom.core.CoreModelException;
import org.apache.axiom.core.ElementAction;
-import org.apache.axiom.core.stream.annotations.StringOrCharacterData;
+import org.apache.axiom.core.stream.CharacterData;
import org.apache.axiom.weaver.annotation.Mixin;
@Mixin
public abstract class CoreMixedContentContainerMixin implements
CoreMixedContentContainer {
@Override
- public final @StringOrCharacterData Object
coreGetCharacterData(ElementAction elementAction)
- throws CoreModelException {
+ public final @Union(types = {String.class, CharacterData.class}) Object
coreGetCharacterData(
+ ElementAction elementAction) throws CoreModelException {
return internalGetCharacterData(elementAction);
}
}
diff --git
a/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/mixin/CoreParentNodeMixin.java
b/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/mixin/CoreParentNodeMixin.java
index cff323f48..697bd526e 100644
---
a/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/mixin/CoreParentNodeMixin.java
+++
b/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/mixin/CoreParentNodeMixin.java
@@ -18,6 +18,7 @@
*/
package org.apache.axiom.core.impl.mixin;
+import org.apache.axiom.checker.union.Union;
import org.apache.axiom.core.Axis;
import org.apache.axiom.core.Builder;
import org.apache.axiom.core.ChildNotAllowedException;
@@ -52,7 +53,6 @@ import org.apache.axiom.core.stream.CharacterData;
import org.apache.axiom.core.stream.StreamException;
import org.apache.axiom.core.stream.XmlHandler;
import org.apache.axiom.core.stream.XmlReader;
-import org.apache.axiom.core.stream.annotations.StringOrCharacterData;
import org.apache.axiom.weaver.annotation.Mixin;
@Mixin
@@ -124,10 +124,7 @@ public abstract class CoreParentNodeMixin implements
CoreParentNode {
Content content = new Content();
CoreCharacterDataNode cdata =
coreGetNodeFactory().createCharacterDataNode();
cdata.internalSetParent(this);
- @SuppressWarnings("stringorcharacterdata")
- @StringOrCharacterData
- Object characterData = this.content;
- cdata.coreSetCharacterData(characterData);
+ cdata.coreSetCharacterData((@Union(types = {String.class,
CharacterData.class}) Object) this.content);
content.firstChild = cdata;
content.lastChild = cdata;
this.content = content;
@@ -346,15 +343,13 @@ public abstract class CoreParentNodeMixin implements
CoreParentNode {
}
@Override
- public final @StringOrCharacterData Object
internalGetCharacterData(ElementAction elementAction)
- throws CoreModelException {
+ public final @Union(types = {String.class, CharacterData.class}) Object
internalGetCharacterData(
+ ElementAction elementAction) throws CoreModelException {
if (getState() == COMPACT) {
- @SuppressWarnings("stringorcharacterdata")
- @StringOrCharacterData
- Object result = content;
- return result;
+ return (@Union(types = {String.class, CharacterData.class})
Object) content;
} else {
- @StringOrCharacterData Object textContent = null;
+ @Union(types = {String.class, CharacterData.class})
+ Object textContent = null;
StringBuilder buffer = null;
int depth = 0;
CoreChildNode child = coreGetFirstChild();
@@ -379,7 +374,7 @@ public abstract class CoreParentNodeMixin implements
CoreParentNode {
}
} else {
if (child instanceof CoreCharacterDataNode || child
instanceof CoreCDATASection) {
- @StringOrCharacterData
+ @Union(types = {String.class, CharacterData.class})
Object textValue = ((CoreCharacterDataContainer)
child).coreGetCharacterData();
if (textValue instanceof CharacterData || ((String)
textValue).length() != 0) {
if (textContent == null) {
@@ -420,7 +415,8 @@ public abstract class CoreParentNodeMixin implements
CoreParentNode {
}
@Override
- public final void coreSetCharacterData(@StringOrCharacterData Object data,
Semantics semantics)
+ public final void coreSetCharacterData(
+ @Union(types = {String.class, CharacterData.class}) Object data,
Semantics semantics)
throws CoreModelException {
coreRemoveChildren(semantics);
if (data != null && (data instanceof CharacterData || ((String)
data).length() > 0)) {
@@ -453,9 +449,8 @@ public abstract class CoreParentNodeMixin implements
CoreParentNode {
CoreParentNode targetParent = (CoreParentNode) clone;
if (policy.cloneChildren(options, coreGetNodeType()) &&
targetParent.isExpanded()) {
if (getState() == COMPACT) {
- @SuppressWarnings("stringorcharacterdata")
- @StringOrCharacterData
- Object content = this.content;
+ @Union(types = {String.class, CharacterData.class})
+ Object content = (@Union(types = {String.class,
CharacterData.class}) Object) this.content;
if (content instanceof CloneableCharacterData) {
content = ((CloneableCharacterData) content).clone(policy,
options);
}
diff --git a/mixins/dom-mixins/pom.xml b/mixins/dom-mixins/pom.xml
index ae472efa6..7b76f524f 100644
--- a/mixins/dom-mixins/pom.xml
+++ b/mixins/dom-mixins/pom.xml
@@ -49,7 +49,7 @@
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
- <artifactId>checker-annotations</artifactId>
+ <artifactId>union-annotations</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
diff --git a/mixins/om-mixins/pom.xml b/mixins/om-mixins/pom.xml
index d2cb26420..dee606859 100644
--- a/mixins/om-mixins/pom.xml
+++ b/mixins/om-mixins/pom.xml
@@ -50,7 +50,7 @@
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
- <artifactId>checker-annotations</artifactId>
+ <artifactId>union-annotations</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
diff --git
a/mixins/om-mixins/src/main/java/org/apache/axiom/om/impl/common/factory/OMFactoryImpl.java
b/mixins/om-mixins/src/main/java/org/apache/axiom/om/impl/common/factory/OMFactoryImpl.java
index 3a7f44eab..6936abcea 100644
---
a/mixins/om-mixins/src/main/java/org/apache/axiom/om/impl/common/factory/OMFactoryImpl.java
+++
b/mixins/om-mixins/src/main/java/org/apache/axiom/om/impl/common/factory/OMFactoryImpl.java
@@ -23,8 +23,9 @@ import static
org.apache.axiom.util.xml.NSUtils.generatePrefix;
import java.util.Iterator;
import javax.xml.namespace.QName;
import org.apache.axiom.blob.Blob;
+import org.apache.axiom.checker.union.Union;
import org.apache.axiom.core.CoreModelException;
-import org.apache.axiom.core.stream.annotations.StringOrCharacterData;
+import org.apache.axiom.core.stream.CharacterData;
import org.apache.axiom.ext.stax.BlobProvider;
import org.apache.axiom.om.OMAttribute;
import org.apache.axiom.om.OMComment;
@@ -100,7 +101,8 @@ public class OMFactoryImpl implements OMFactory {
return node;
}
- private AxiomText createAxiomText(OMContainer parent,
@StringOrCharacterData Object content, int type) {
+ private AxiomText createAxiomText(
+ OMContainer parent, @Union(types = {String.class,
CharacterData.class}) Object content, int type) {
AxiomText node;
switch (type) {
case OMNode.TEXT_NODE -> {
@@ -158,8 +160,8 @@ public class OMFactoryImpl implements OMFactory {
throw new IllegalArgumentException("QName text arg cannot be
null!");
}
OMNamespace ns = ((AxiomElement)
parent).handleNamespace(text.getNamespaceURI(), text.getPrefix());
- return createAxiomText(
- parent, ns == null ? text.getLocalPart() : ns.getPrefix() +
":" + text.getLocalPart(), type);
+ String content = ns == null ? text.getLocalPart() : ns.getPrefix() +
":" + text.getLocalPart();
+ return createAxiomText(parent, content, type);
}
@Override
@@ -390,6 +392,7 @@ public class OMFactoryImpl implements OMFactory {
}
case OMNode.TEXT_NODE, OMNode.SPACE_NODE,
OMNode.CDATA_SECTION_NODE -> {
OMText text = (OMText) child;
+ @Union(types = {String.class, CharacterData.class})
Object content;
if (text.isBinary()) {
content = new TextContent(text.getContentID(),
text.getBlob(), text.isOptimized());
diff --git
a/mixins/om-mixins/src/main/java/org/apache/axiom/om/impl/intf/TextContent.java
b/mixins/om-mixins/src/main/java/org/apache/axiom/om/impl/intf/TextContent.java
index f16abb98b..b5910109c 100644
---
a/mixins/om-mixins/src/main/java/org/apache/axiom/om/impl/intf/TextContent.java
+++
b/mixins/om-mixins/src/main/java/org/apache/axiom/om/impl/intf/TextContent.java
@@ -21,12 +21,11 @@ package org.apache.axiom.om.impl.intf;
import java.io.IOException;
import org.apache.axiom.blob.Blob;
import org.apache.axiom.blob.Blobs;
+import org.apache.axiom.checker.union.Union;
import org.apache.axiom.core.ClonePolicy;
import org.apache.axiom.core.CloneableCharacterData;
import org.apache.axiom.core.stream.CharacterData;
import org.apache.axiom.core.stream.CharacterDataSink;
-import org.apache.axiom.core.stream.annotations.StringOrCharacterData;
-import org.apache.axiom.core.stream.annotations.UnknownCharacterDataType;
import org.apache.axiom.ext.stax.BlobProvider;
import org.apache.axiom.mime.PartBlob;
import org.apache.axiom.om.OMCloneOptions;
@@ -137,8 +136,7 @@ public final class TextContent implements
CloneableCharacterData {
}
@Override
- @SuppressWarnings("method.invocation")
- public String toString(@UnknownCharacterDataType TextContent this) {
+ public String toString() {
if (blobObject != null) {
try {
return Base64Utils.encode(getBlob());
@@ -204,7 +202,7 @@ public final class TextContent implements
CloneableCharacterData {
}
@Override
- public @StringOrCharacterData Object retain() {
+ public @Union(types = {String.class, CharacterData.class}) Object retain()
{
return this;
}
}
diff --git
a/mixins/om-mixins/src/main/java/org/apache/axiom/om/impl/stream/ds/PushOMDataSourceXOPHandler.java
b/mixins/om-mixins/src/main/java/org/apache/axiom/om/impl/stream/ds/PushOMDataSourceXOPHandler.java
index 873ef836a..038c54407 100644
---
a/mixins/om-mixins/src/main/java/org/apache/axiom/om/impl/stream/ds/PushOMDataSourceXOPHandler.java
+++
b/mixins/om-mixins/src/main/java/org/apache/axiom/om/impl/stream/ds/PushOMDataSourceXOPHandler.java
@@ -21,9 +21,10 @@ package org.apache.axiom.om.impl.stream.ds;
import java.util.HashMap;
import java.util.Map;
import org.apache.axiom.blob.Blob;
+import org.apache.axiom.checker.union.Union;
+import org.apache.axiom.core.stream.CharacterData;
import org.apache.axiom.core.stream.StreamException;
import org.apache.axiom.core.stream.XmlHandler;
-import org.apache.axiom.core.stream.annotations.StringOrCharacterData;
import org.apache.axiom.core.stream.xop.AbstractXOPDecodingFilterHandler;
import org.apache.axiom.om.impl.intf.TextContent;
import org.apache.axiom.om.impl.stream.xop.XOPHandler;
@@ -44,7 +45,8 @@ final class PushOMDataSourceXOPHandler extends
AbstractXOPDecodingFilterHandler
}
@Override
- protected @StringOrCharacterData Object buildCharacterData(String
contentID) throws StreamException {
+ protected @Union(types = {String.class, CharacterData.class}) Object
buildCharacterData(String contentID)
+ throws StreamException {
Blob blob = blobs.get(contentID);
if (blob == null) {
throw new StreamException("No Blob found for content ID " +
contentID);
diff --git
a/mixins/om-mixins/src/main/java/org/apache/axiom/om/impl/stream/xop/XOPDecodingFilterHandler.java
b/mixins/om-mixins/src/main/java/org/apache/axiom/om/impl/stream/xop/XOPDecodingFilterHandler.java
index 59f706aab..189d3a0d2 100644
---
a/mixins/om-mixins/src/main/java/org/apache/axiom/om/impl/stream/xop/XOPDecodingFilterHandler.java
+++
b/mixins/om-mixins/src/main/java/org/apache/axiom/om/impl/stream/xop/XOPDecodingFilterHandler.java
@@ -20,8 +20,9 @@ package org.apache.axiom.om.impl.stream.xop;
import java.io.IOException;
import org.apache.axiom.blob.Blob;
+import org.apache.axiom.checker.union.Union;
+import org.apache.axiom.core.stream.CharacterData;
import org.apache.axiom.core.stream.XmlHandler;
-import org.apache.axiom.core.stream.annotations.StringOrCharacterData;
import org.apache.axiom.core.stream.xop.AbstractXOPDecodingFilterHandler;
import org.apache.axiom.ext.stax.BlobProvider;
import org.apache.axiom.om.OMAttachmentAccessor;
@@ -57,7 +58,7 @@ final class XOPDecodingFilterHandler extends
AbstractXOPDecodingFilterHandler {
}
@Override
- protected @StringOrCharacterData Object buildCharacterData(String
contentID) {
+ protected @Union(types = {String.class, CharacterData.class}) Object
buildCharacterData(String contentID) {
return new TextContent(contentID, new
BlobProviderImpl(attachmentAccessor, contentID), true);
}
}
diff --git a/mixins/pom.xml b/mixins/pom.xml
index 10f48bb92..20869b515 100644
--- a/mixins/pom.xml
+++ b/mixins/pom.xml
@@ -46,7 +46,7 @@
<annotationProcessorPaths combine.children="append">
<annotationProcessorPath>
<groupId>${project.groupId}</groupId>
-
<artifactId>stringorcharacterdata-checker</artifactId>
+ <artifactId>union-checker</artifactId>
<version>${project.version}</version>
</annotationProcessorPath>
</annotationProcessorPaths>