XmlAnnotationIntrospector.java

package tools.jackson.dataformat.xml;

import tools.jackson.databind.AnnotationIntrospector;
import tools.jackson.databind.PropertyName;
import tools.jackson.databind.cfg.MapperConfig;
import tools.jackson.databind.introspect.Annotated;
import tools.jackson.databind.introspect.AnnotationIntrospectorPair;
import tools.jackson.databind.util.ClassUtil;

/**
 * Additional extension interface used above and beyond
 * {@link AnnotationIntrospector} to handle XML-specific configuration.
 */
public interface XmlAnnotationIntrospector
    extends AnnotationIntrospector.XmlExtensions
{
    /**
     * Mutant factory for getting an introspector that uses given default for
     * List wrapping (for Lists and arrays without explicit wrapper annotation):
     * returns this instance if there is no change (or no such setting), a
     * re-configured copy otherwise. Must never modify this instance, as an
     * introspector may be shared by multiple (immutable) mappers; see
     * {@code XmlMapper.rebuild()}.
     *<p>
     * Default implementation returns {@code this}, for introspectors that have
     * no such setting.
     *<p>
     * NOTE: implementations are expected to extend {@link AnnotationIntrospector},
     * and value returned MUST also be an {@link AnnotationIntrospector} (since it
     * is used as the replacement introspector by
     * {@code XmlMapper.Builder.defaultUseWrapper()}).
     *
     * @param defaultUseWrapper Whether to use wrapping by default or not
     *
     * @return Introspector that uses given default for wrapping
     *
     * @since 3.3
     */
    default XmlAnnotationIntrospector withDefaultUseWrapper(boolean defaultUseWrapper) {
        return this;
    }

    /*
    /**********************************************************************
    /* Replacement of 'AnnotationIntrospector.Pair' to use when combining
    /* (potential) XMLAnnotationIntrospector instance
    /**********************************************************************
     */

    /**
     * Extension of <code>AnnotationIntrospector.Pair</code> that can
     * also dispatch 'XmlAnnotationIntrospector' methods.
     */
    public static class Pair extends AnnotationIntrospectorPair
        implements XmlAnnotationIntrospector
    {
        private static final long serialVersionUID = 1L;

        protected final AnnotationIntrospector.XmlExtensions _xmlPrimary;
        protected final AnnotationIntrospector.XmlExtensions _xmlSecondary;

        public Pair(AnnotationIntrospector p, AnnotationIntrospector s)
        {
            super(p, s);
            if (p instanceof AnnotationIntrospector.XmlExtensions xmlExt) {
                _xmlPrimary = xmlExt;
            } else {
                _xmlPrimary = null;
            }

            if (s instanceof AnnotationIntrospector.XmlExtensions xmlExt) {
                _xmlSecondary = xmlExt;
            } else {
                _xmlSecondary = null;
            }
        }

        public static XmlAnnotationIntrospector.Pair instance(AnnotationIntrospector a1, AnnotationIntrospector a2) {
            return new XmlAnnotationIntrospector.Pair(a1, a2);
        }

        /**
         * Sub-classes MUST override this method to retain their type; otherwise
         * an {@link IllegalStateException} is thrown when a re-configured copy
         * would be needed.
         *
         * @since 3.3
         */
        @Override
        public XmlAnnotationIntrospector withDefaultUseWrapper(boolean defaultUseWrapper)
        {
            AnnotationIntrospector p = _withDefaultUseWrapper(_primary, defaultUseWrapper);
            AnnotationIntrospector s = _withDefaultUseWrapper(_secondary, defaultUseWrapper);
            if ((p == _primary) && (s == _secondary)) {
                return this;
            }
            ClassUtil.verifyMustOverride(XmlAnnotationIntrospector.Pair.class, this,
                    "withDefaultUseWrapper");
            return new XmlAnnotationIntrospector.Pair(p, s);
        }

        protected static AnnotationIntrospector _withDefaultUseWrapper(AnnotationIntrospector ai,
                boolean defaultUseWrapper)
        {
            if (ai instanceof XmlAnnotationIntrospector xmlAi) {
                return (AnnotationIntrospector) xmlAi.withDefaultUseWrapper(defaultUseWrapper);
            }
            return ai;
        }
        
        @Override
        public String findNamespace(MapperConfig<?> config, Annotated ann)
        {
            String value = (_xmlPrimary == null) ? null : _xmlPrimary.findNamespace(config, ann);
            if ((value == null) && (_xmlSecondary != null)) {
                value = _xmlSecondary.findNamespace(config, ann);
            }
            return value;
        }

        @Override
        public Boolean isOutputAsAttribute(MapperConfig<?> config, Annotated ann)
        {
            Boolean value = (_xmlPrimary == null) ? null : _xmlPrimary.isOutputAsAttribute(config, ann);
            if ((value == null) && (_xmlSecondary != null)) {
                value = _xmlSecondary.isOutputAsAttribute(config, ann);
            }
            return value;
        }

        @Override
        public Boolean isOutputAsText(MapperConfig<?> config, Annotated ann)
        {
            Boolean value = (_xmlPrimary == null) ? null : _xmlPrimary.isOutputAsText(config, ann);
            if ((value == null) && (_xmlSecondary != null)) {
                value = _xmlSecondary.isOutputAsText(config, ann);
            }
            return value;
        }

        @Override
        public Boolean isOutputAsCData(MapperConfig<?> config, Annotated ann) {
            Boolean value = (_xmlPrimary == null) ? null : _xmlPrimary.isOutputAsCData(config, ann);
            if ((value == null) && (_xmlSecondary != null)) {
                value = _xmlSecondary.isOutputAsCData(config, ann);
            }
            return value;
        }

        // [dataformat-xml#27]
        @Override
        public PropertyName findXmlPropertyInnerName(MapperConfig<?> config, Annotated ann)
        {
            PropertyName value = (_xmlPrimary == null) ? null
                    : _xmlPrimary.findXmlPropertyInnerName(config, ann);
            if ((value == null) && (_xmlSecondary != null)) {
                value = _xmlSecondary.findXmlPropertyInnerName(config, ann);
            }
            return value;
        }
    }
}