All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.fasterxml.jackson.xml.JacksonXmlAnnotationIntrospector Maven / Gradle / Ivy

package com.fasterxml.jackson.xml;

import javax.xml.namespace.QName;

import org.codehaus.jackson.annotate.JsonTypeInfo;
import org.codehaus.jackson.map.introspect.Annotated;
import org.codehaus.jackson.map.introspect.AnnotatedField;
import org.codehaus.jackson.map.introspect.AnnotatedMethod;
import org.codehaus.jackson.map.introspect.AnnotatedParameter;
import org.codehaus.jackson.map.introspect.JacksonAnnotationIntrospector;
import org.codehaus.jackson.map.jsontype.TypeIdResolver;
import org.codehaus.jackson.map.jsontype.impl.StdTypeResolverBuilder;

import com.fasterxml.jackson.xml.annotate.*;

/**
 * Extension of {@link JacksonAnnotationIntrospector} that is needed to support
 * additional xml-specific annotation that Jackson provides. Note, however, that
 * there is no JAXB annotation support here; that is provided with
 * separate introspector (see {@link org.codehaus.jackson.xc.JaxbAnnotationIntrospector}).
 * 
 * @since 1.7
 */
public class JacksonXmlAnnotationIntrospector
    extends JacksonAnnotationIntrospector
    implements XmlAnnotationIntrospector
{    
    /*
    /**********************************************************
    /* XmlAnnotationIntrospector
    /**********************************************************
     */

    @Override
    public Boolean isOutputAsAttribute(Annotated ann)
    {
        JacksonXmlProperty prop = ann.getAnnotation(JacksonXmlProperty.class);
        if (prop != null) {
            return prop.isAttribute() ? Boolean.TRUE : Boolean.FALSE;
        }
        return null;
    }

    @Override
    public String findNamespace(Annotated ann)
    {
        JacksonXmlProperty prop = ann.getAnnotation(JacksonXmlProperty.class);
        if (prop != null) {
            return prop.namespace();
        }
        return null;
    }

    @Override
    public QName findWrapperElement(Annotated ann)
    {
        JacksonXmlElementWrapper w = ann.getAnnotation(JacksonXmlElementWrapper.class);
        if (w != null) {
            return new QName(w.namespace(), w.localName());
        }
        return null;
    }
    
    /*
    /**********************************************************
    /* Overrides for name, property detection
    /**********************************************************
     */
    
    @Override
    public String findSerializablePropertyName(AnnotatedField af)
    {
        JacksonXmlProperty pann = af.getAnnotation(JacksonXmlProperty.class);
        if (pann != null) {
            return pann.localName();
        }
        return super.findSerializablePropertyName(af);
    }

    @Override
    public String findSettablePropertyName(AnnotatedMethod am)
    {
        JacksonXmlProperty pann = am.getAnnotation(JacksonXmlProperty.class);
        if (pann != null) {
            return pann.localName();
        }
        return super.findSettablePropertyName(am);
    }

    @Override
    public String findDeserializablePropertyName(AnnotatedField af)
    {
        JacksonXmlProperty pann = af.getAnnotation(JacksonXmlProperty.class);
        if (pann != null) {
            return pann.localName();
        }
        return super.findDeserializablePropertyName(af);
    }

    @Override
    public String findPropertyNameForParam(AnnotatedParameter ap)
    {
        JacksonXmlProperty pann = ap.getAnnotation(JacksonXmlProperty.class);
        // can not return empty String here, so:
        if (pann != null) {
            String name = pann.localName();
            if (name.length() > 0) {
                return name;
            }
        }
        return super.findPropertyNameForParam(ap);
    }

    /*
    /**********************************************************
    /* Overrides for non-public helper methods
    /**********************************************************
     */

    /**
     * We will override this method so that we can return instance
     * that cleans up type id property name to be a valid xml name.
     */
    @Override
    protected StdTypeResolverBuilder _constructStdTypeResolverBuilder()
    {
        return new XmlTypeResolverBuilder();
    }
    
    /*
    /**********************************************************
    /* Internal helper methods
    /**********************************************************
     */

    /**
     * Since XML names can not contain all characters JSON names can, we may
     * need to replace characters. Let's start with trivial replacement of
     * ASCII characters that can not be included.
     */
    protected static String sanitizeXmlName(String name)
    {
        StringBuilder sb = new StringBuilder(name);
        int changes = 0;
        for (int i = 0, len = name.length(); i < len; ++i) {
            char c = name.charAt(i);
            if (c > 127) continue;
            if (c >= 'a' && c <= 'z') continue;
            if (c >= 'A' && c <= 'Z') continue;
            if (c >= '0' && c <= '9') continue;
            if (c == '_' || c == '.' || c == '-') continue;
            // Ok, need to replace
            ++changes;
            sb.setCharAt(i, '_');
        }
        if (changes == 0) {
            return name;
        }
        return sb.toString();
    }

    /*
    /**********************************************************
    /* Helper classes
    /**********************************************************
     */

    /**
     * Custom specialization of {@link StdTypeResolverBuilder}; needed so that
     * type id property name can be modified as necessary to make it legal
     * xml element or attribute name.
     */
    protected static class XmlTypeResolverBuilder extends StdTypeResolverBuilder
    {
        @Override
        public StdTypeResolverBuilder init(JsonTypeInfo.Id idType, TypeIdResolver idRes)
        {
            super.init(idType, idRes);
            if (_typeProperty != null) {
                _typeProperty = sanitizeXmlName(_typeProperty);
            }
            return this;
        }

        @Override
        public StdTypeResolverBuilder typeProperty(String typeIdPropName)
        {
            // ok to have null/empty; will restore to use defaults
            if (typeIdPropName == null || typeIdPropName.length() == 0) {
                typeIdPropName = _idType.getDefaultPropertyName();
            }
            _typeProperty = sanitizeXmlName(typeIdPropName);
            return this;
        }
    }
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy