Package org.codehaus.enunciate.contract.jaxb

Source Code of org.codehaus.enunciate.contract.jaxb.Element

/*
* Copyright 2006-2008 Web Cohesion
*
* Licensed 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.codehaus.enunciate.contract.jaxb;

import com.sun.mirror.apt.AnnotationProcessorEnvironment;
import com.sun.mirror.declaration.ClassDeclaration;
import com.sun.mirror.declaration.MemberDeclaration;
import com.sun.mirror.declaration.TypeDeclaration;
import com.sun.mirror.type.*;
import com.sun.mirror.util.Types;
import net.sf.jelly.apt.Context;
import net.sf.jelly.apt.decorations.TypeMirrorDecorator;
import net.sf.jelly.apt.decorations.declaration.DecoratedTypeDeclaration;
import net.sf.jelly.apt.decorations.type.DecoratedTypeMirror;
import org.codehaus.enunciate.contract.jaxb.types.XmlClassType;
import org.codehaus.enunciate.contract.jaxb.types.XmlType;
import org.codehaus.enunciate.contract.jaxb.types.XmlTypeException;
import org.codehaus.enunciate.contract.jaxb.types.XmlTypeFactory;
import org.codehaus.enunciate.contract.validation.ValidationException;
import org.codehaus.enunciate.json.JsonName;

import javax.xml.bind.annotation.*;
import javax.xml.namespace.QName;
import java.util.ArrayList;
import java.util.Collection;

/**
* An accessor that is marshalled in xml to an xml element.
*
* @author Ryan Heaton
*/
public class Element extends Accessor {

  private final XmlElement xmlElement;
  private final Collection<Element> choices;
  private boolean isChoice = false;

  public Element(MemberDeclaration delegate, TypeDefinition typedef) {
    super(delegate, typedef);

    XmlElement xmlElement = getAnnotation(XmlElement.class);
    XmlElements xmlElements = getAnnotation(XmlElements.class);
    if (xmlElements != null) {
      XmlElement[] elementChoices = xmlElements.value();
      if (elementChoices.length == 0) {
        xmlElements = null;
      }
      else if ((xmlElement == null) && (elementChoices.length == 1)) {
        xmlElement = elementChoices[0];
        xmlElements = null;
      }
    }

    this.xmlElement = xmlElement;
    this.choices = new ArrayList<Element>();
    if (xmlElements != null) {
      for (XmlElement element : xmlElements.value()) {
        try {
          Class clazz = element.type();
          if ((clazz == null) || (clazz == XmlElement.DEFAULT.class)) {
            throw new ValidationException(getPosition(), "Member " + getName() + " of " + typedef.getQualifiedName() + ": an element choice must have its type specified.");
          }
          else if ((clazz.isArray()) || (Collection.class.isAssignableFrom(clazz))) {
            throw new ValidationException(getPosition(), "Member " + getName() + " of " + typedef.getQualifiedName() + ": an element choice must not be a collection or an array.");
          }
        }
        catch (MirroredTypeException e) {
          // Fall through.
          // If the mirrored type exception is thrown, we couldn't load the class.  This probably
          // implies that the type is valid and it's in the source base.
        }

        this.choices.add(new Element((MemberDeclaration) getDelegate(), getTypeDefinition(), element));
      }
    }
    else {
      this.choices.add(this);
    }
  }

  /**
   * Construct an element accessor with a specific element annotation.
   *
   * @param delegate   The delegate.
   * @param typedef    The type definition.
   * @param xmlElement The specific element annotation.
   */
  protected Element(MemberDeclaration delegate, TypeDefinition typedef, XmlElement xmlElement) {
    super(delegate, typedef);
    this.xmlElement = xmlElement;
    this.choices = new ArrayList<Element>();
    this.choices.add(this);
    this.isChoice = true;
  }

  // Inherited.
  public String getName() {
    String propertyName = getSimpleName();

    if ((xmlElement != null) && (!"##default".equals(xmlElement.name()))) {
      propertyName = xmlElement.name();
    }

    return propertyName;
  }

  // Inherited.
  public String getNamespace() {
    String namespace = null;

    if (getForm() == XmlNsForm.QUALIFIED) {
      namespace = getTypeDefinition().getNamespace();
    }

    if ((xmlElement != null) && (!"##default".equals(xmlElement.namespace()))) {
      namespace = xmlElement.namespace();
    }

    return namespace;
  }

  /**
   * The form of this element.
   *
   * @return The form of this element.
   */
  public XmlNsForm getForm() {
    XmlNsForm elementForm = getTypeDefinition().getSchema().getElementFormDefault();

    if (elementForm == null || elementForm == XmlNsForm.UNSET) {
      elementForm = XmlNsForm.UNQUALIFIED;
    }

    return elementForm;
  }

  /**
   * The qname for the referenced element, if this element is a reference to a global element, or null if
   * this element is not a reference element.
   *
   * @return The qname for the referenced element, if exists.
   */
  public QName getRef() {
    QName ref = null;

    boolean qualified = getForm() == XmlNsForm.QUALIFIED;
    String typeNamespace = getTypeDefinition().getNamespace();
    typeNamespace = typeNamespace == null ? "" : typeNamespace;
    String elementNamespace = isWrapped() ? getWrapperNamespace() : getNamespace();
    elementNamespace = elementNamespace == null ? "" : elementNamespace;
    if ((!elementNamespace.equals(typeNamespace)) && (qualified || !"".equals(elementNamespace))) {
      //the namespace is different; must be a ref...
      return new QName(elementNamespace, isWrapped() ? getWrapperName() : getName());
    }
    else {
      //check to see if this is an implied ref as per the jaxb spec, section 8.9.1.2
      XmlType baseType = getBaseType();
      if ((baseType.isAnonymous()) && (baseType instanceof XmlClassType)) {
        TypeDefinition baseTypeDef = ((XmlClassType) baseType).getTypeDefinition();
        if (baseTypeDef.getAnnotation(XmlRootElement.class) != null) {
          RootElementDeclaration rootElement = new RootElementDeclaration((ClassDeclaration) baseTypeDef.getDelegate(), baseTypeDef);
          ref = new QName(rootElement.getNamespace(), rootElement.getName());
        }
      }
    }

    return ref;
  }

  /**
   * The type of an element accessor can be specified by an annotation.
   *
   * @return The accessor type.
   */
  @Override
  public TypeMirror getAccessorType() {
    TypeMirror specifiedType = null;
    try {
      if ((xmlElement != null) && (xmlElement.type() != XmlElement.DEFAULT.class)) {
        Class clazz = xmlElement.type();
        specifiedType = getAccessorType(clazz);
      }
    }
    catch (MirroredTypeException e) {
      // The mirrored type exception implies that the specified type is within the source base.
      specifiedType = TypeMirrorDecorator.decorate(e.getTypeMirror());
    }

    if (specifiedType != null) {
      if (!isChoice) {
        DecoratedTypeMirror accessorType = (DecoratedTypeMirror) super.getAccessorType();

        if (accessorType.isCollection()) {
          AnnotationProcessorEnvironment ape = Context.getCurrentEnvironment();
          Types types = ape.getTypeUtils();
          if (specifiedType instanceof PrimitiveType) {
            specifiedType = types.getPrimitiveType(((PrimitiveType) specifiedType).getKind());
          }
          else {
            specifiedType = types.getDeclaredType(ape.getTypeDeclaration(((DeclaredType) specifiedType).getDeclaration().getQualifiedName()));
          }
          specifiedType = TypeMirrorDecorator.decorate(types.getDeclaredType(ape.getTypeDeclaration(((DeclaredType) accessorType).getDeclaration().getQualifiedName()), specifiedType));
        }
        else if (accessorType.isArray() && !(specifiedType instanceof ArrayType)) {
          Types types = Context.getCurrentEnvironment().getTypeUtils();
          if (specifiedType instanceof PrimitiveType) {
            specifiedType = types.getPrimitiveType(((PrimitiveType) specifiedType).getKind());
          }
          else {
            TypeDeclaration decl = ((DeclaredType) specifiedType).getDeclaration();
            while (decl instanceof DecoratedTypeDeclaration) {
              decl = (TypeDeclaration) ((DecoratedTypeDeclaration) decl).getDelegate();
            }
            specifiedType = types.getDeclaredType(decl);
          }
          specifiedType = TypeMirrorDecorator.decorate(types.getArrayType(specifiedType));
        }
      }

      return specifiedType;
    }

    return super.getAccessorType();
  }

  /**
   * Get the accessor type for the specified class.
   *
   * @param clazz The class.
   * @return The accessor type.
   */
  protected TypeMirror getAccessorType(Class clazz) {
    AnnotationProcessorEnvironment env = Context.getCurrentEnvironment();
    TypeMirror undecorated;
    if (clazz.isPrimitive()) {
      if (Boolean.TYPE == clazz) {
        undecorated = env.getTypeUtils().getPrimitiveType(PrimitiveType.Kind.BOOLEAN);
      }
      else if (Byte.TYPE == clazz) {
        undecorated = env.getTypeUtils().getPrimitiveType(PrimitiveType.Kind.BYTE);
      }
      else if (Character.TYPE == clazz) {
        undecorated = env.getTypeUtils().getPrimitiveType(PrimitiveType.Kind.CHAR);
      }
      else if (Double.TYPE == clazz) {
        undecorated = env.getTypeUtils().getPrimitiveType(PrimitiveType.Kind.DOUBLE);
      }
      else if (Float.TYPE == clazz) {
        undecorated = env.getTypeUtils().getPrimitiveType(PrimitiveType.Kind.FLOAT);
      }
      else if (Integer.TYPE == clazz) {
        undecorated = env.getTypeUtils().getPrimitiveType(PrimitiveType.Kind.INT);
      }
      else if (Long.TYPE == clazz) {
        undecorated = env.getTypeUtils().getPrimitiveType(PrimitiveType.Kind.LONG);
      }
      else if (Short.TYPE == clazz) {
        undecorated = env.getTypeUtils().getPrimitiveType(PrimitiveType.Kind.SHORT);
      }
      else {
        throw new IllegalArgumentException("Unknown primitive type: " + clazz.getName());
      }
    }
    else if (clazz.isArray()) {
      undecorated = env.getTypeUtils().getArrayType(getAccessorType(clazz.getComponentType()));
    }
    else {
      TypeDeclaration typeDeclaration = env.getTypeDeclaration(clazz.getName());
      //todo: worry about the formal type parameters?
      undecorated = env.getTypeUtils().getDeclaredType(typeDeclaration);
    }

    return TypeMirrorDecorator.decorate(undecorated);
  }

  /**
   * The base type of an element accessor can be specified by an annotation.
   *
   * @return The base type.
   */
  @Override
  public XmlType getBaseType() {
    if (xmlElement != null) {
      Class typeClass = null;
      TypeMirror typeMirror = null;
      try {
        typeClass = xmlElement.type();
      }
      catch (MirroredTypeException e) {
        typeMirror = e.getTypeMirror();
      }

      try {
        if (typeClass == null) {
          return XmlTypeFactory.getXmlType(typeMirror);
        }
        else if (typeClass != XmlElement.DEFAULT.class) {
          return XmlTypeFactory.getXmlType(typeClass);
        }
      }
      catch (XmlTypeException e) {
        throw new ValidationException(getPosition(), "Member " + getName() + " of " + getTypeDefinition().getQualifiedName() + e.getMessage());
      }
    }

    return super.getBaseType();
  }

  /**
   * Whether this element is nillable.
   *
   * @return Whether this element is nillable.
   */
  public boolean isNillable() {
    boolean nillable = false;

    if (xmlElement != null) {
      nillable = xmlElement.nillable();
    }

    return nillable;
  }

  /**
   * Whether this element is required.
   *
   * @return Whether this element is required.
   */
  public boolean isRequired() {
    boolean required = false;

    if (xmlElement != null) {
      required = xmlElement.required();
    }

    return required;
  }

  /**
   * The min occurs of this element.
   *
   * @return The min occurs of this element.
   */
  public int getMinOccurs() {
    if (isRequired()) {
      return 1;
    }

    TypeMirror accessorType = getAccessorType();
    boolean primitive = (accessorType instanceof PrimitiveType);
    if ((!primitive) && (accessorType instanceof ArrayType)) {
      //we have to check if the component type if its an array type, too.
      TypeMirror componentType = ((ArrayType) accessorType).getComponentType();
      primitive = (componentType instanceof PrimitiveType) && (((PrimitiveType)componentType).getKind() != PrimitiveType.Kind.BYTE);
    }

    return primitive ? 1 : 0;
  }

  /**
   * The max occurs of this element.
   *
   * @return The max occurs of this element.
   */
  public String getMaxOccurs() {
    return isCollectionType() ? "unbounded" : "1";
  }

  /**
   * The default value, or null if none exists.
   *
   * @return The default value, or null if none exists.
   */
  public String getDefaultValue() {
    String defaultValue = null;

    if ((xmlElement != null) && (!"\u0000".equals(xmlElement.defaultValue()))) {
      defaultValue = xmlElement.defaultValue();
    }

    return defaultValue;
  }

  /**
   * The choices for this element.
   *
   * @return The choices for this element.
   */
  public Collection<? extends Element> getChoices() {
    return choices;
  }

  /**
   * Whether this xml element is wrapped.
   *
   * @return Whether this xml element is wrapped.
   */
  public boolean isWrapped() {
    return (isCollectionType() && (getAnnotation(XmlElementWrapper.class) != null));
  }

  /**
   * The name of the wrapper element.
   *
   * @return The name of the wrapper element.
   */
  public String getWrapperName() {
    String name = getSimpleName();

    XmlElementWrapper xmlElementWrapper = getAnnotation(XmlElementWrapper.class);
    if ((xmlElementWrapper != null) && (!"##default".equals(xmlElementWrapper.name()))) {
      name = xmlElementWrapper.name();
    }

    return name;
  }

  /**
   * The namespace of the wrapper element.
   *
   * @return The namespace of the wrapper element.
   */
  public String getWrapperNamespace() {
    String namespace = null;

    if (getForm() == XmlNsForm.QUALIFIED) {
      namespace = getTypeDefinition().getNamespace();
    }

    XmlElementWrapper xmlElementWrapper = getAnnotation(XmlElementWrapper.class);
    if ((xmlElementWrapper != null) && (!"##default".equals(xmlElementWrapper.namespace()))) {
      namespace = xmlElementWrapper.namespace();
    }

    return namespace;
  }

  /**
   * Whether the wrapper is nillable.
   *
   * @return Whether the wrapper is nillable.
   */
  public boolean isWrapperNillable() {
    boolean nillable = false;

    XmlElementWrapper xmlElementWrapper = getAnnotation(XmlElementWrapper.class);
    if (xmlElementWrapper != null) {
      nillable = xmlElementWrapper.nillable();
    }

    return nillable;
  }

  /**
   * Whether this is a choice of multiple element refs.
   *
   * @return Whether this is a choice of multiple element refs.
   */
  public boolean isElementRefs() {
    return false;
  }

  @Override
  public String getJsonMemberName() {
    JsonName jsonName = getAnnotation(JsonName.class);
    return jsonName == null ? (isWrapped() ? getWrapperName() : getName()) : jsonName.value();
  }
}
TOP

Related Classes of org.codehaus.enunciate.contract.jaxb.Element

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.