/**
* Copyright (c) 2009 - 2012 Red Hat, Inc.
*
* This software is licensed to you under the GNU General Public License,
* version 2 (GPLv2). There is NO WARRANTY for this software, express or
* implied, including the implied warranties of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
* along with this software; if not, see
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* Red Hat trademarks are not licensed under GPLv2. No permission is
* granted to use or replicate Red Hat trademarks that are incorporated
* in this software or its documentation.
*/
package org.candlepin.swagger;
import com.fasterxml.jackson.databind.introspect.AnnotatedMember;
import io.swagger.models.Xml;
import io.swagger.models.properties.ArrayProperty;
import io.swagger.models.properties.MapProperty;
import io.swagger.models.properties.ObjectProperty;
import io.swagger.models.properties.Property;
import io.swagger.models.properties.RefProperty;
import org.apache.commons.lang3.StringUtils;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
/**
* The <code>JAXBAnnotationsHelper</code> class defines helper methods for
* applying JAXB annotations to property definitions.
*/
class JAXBAnnotationsHelper {
private static final String JAXB_DEFAULT = "##default";
private JAXBAnnotationsHelper() {
}
/**
* Applies annotations to property's {@link Xml} definition.
*
* @param member annotations provider
* @param property property instance to be updated
*/
public static void apply(AnnotatedMember member, Property property) {
if (member.hasAnnotation(XmlElementWrapper.class) || member.hasAnnotation(XmlElement.class)) {
applyElement(member, property);
}
else if (member.hasAnnotation(XmlAttribute.class) && isAttributeAllowed(property)) {
applyAttribute(member, property);
}
}
/**
* Puts definitions for XML element.
*
* @param member annotations provider
* @param property property instance to be updated
*/
private static void applyElement(AnnotatedMember member, Property property) {
final XmlElementWrapper wrapper = member.getAnnotation(XmlElementWrapper.class);
if (wrapper != null) {
final Xml xml = getXml(property);
xml.setWrapped(true);
if (!"##default".equals(wrapper.name()) && !wrapper.name().isEmpty()) {
xml.setName(wrapper.name());
}
}
final XmlElement element = member.getAnnotation(XmlElement.class);
if (element != null) {
setName(element.namespace(), element.name(), property);
}
}
/**
* Puts definitions for XML attribute.
*
* @param member annotations provider
* @param property property instance to be updated
*/
private static void applyAttribute(AnnotatedMember member, Property property) {
final XmlAttribute attribute = member.getAnnotation(XmlAttribute.class);
if (attribute != null) {
final Xml xml = getXml(property);
xml.setAttribute(true);
setName(attribute.namespace(), attribute.name(), property);
}
}
private static Xml getXml(Property property) {
final Xml existing = property.getXml();
if (existing != null) {
return existing;
}
final Xml created = new Xml();
property.setXml(created);
return created;
}
/**
* Puts name space and name for XML node or attribute.
*
* @param ns name space
* @param name name
* @param property property instance to be updated
* @return <code>true</code> if name space and name have been set
*/
private static boolean setName(String ns, String name, Property property) {
boolean apply = false;
final String cleanName = StringUtils.trimToNull(name);
final String useName;
if (!isEmpty(cleanName) && !cleanName.equals(property.getName())) {
useName = cleanName;
apply = true;
}
else {
useName = null;
}
final String cleanNS = StringUtils.trimToNull(ns);
final String useNS;
if (!isEmpty(cleanNS)) {
useNS = cleanNS;
apply = true;
}
else {
useNS = null;
}
// Set everything or nothing
if (apply) {
getXml(property).name(useName).namespace(useNS);
}
return apply;
}
/**
* Checks whether the passed property can be represented as node attribute.
*
* @param property property instance to be checked
* @return <code>true</code> if the passed property can be represented as
* node attribute
*/
private static boolean isAttributeAllowed(Property property) {
for (Class<?> item : new Class<?>[]{
ArrayProperty.class, MapProperty.class, ObjectProperty.class, RefProperty.class}) {
if (item.isInstance(property)) {
return false;
}
}
return true;
}
private static boolean isEmpty(String name) {
return StringUtils.isEmpty(name) || JAXB_DEFAULT.equals(name);
}
}