Package org.codehaus.enunciate.contract.jaxb

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

/*
* 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.*;
import com.sun.mirror.type.*;
import com.sun.mirror.util.Types;
import net.sf.jelly.apt.Context;
import net.sf.jelly.apt.decorations.DeclarationDecorator;
import net.sf.jelly.apt.decorations.TypeMirrorDecorator;
import net.sf.jelly.apt.decorations.declaration.DecoratedClassDeclaration;
import net.sf.jelly.apt.decorations.declaration.DecoratedMemberDeclaration;
import net.sf.jelly.apt.decorations.declaration.PropertyDeclaration;
import net.sf.jelly.apt.decorations.type.DecoratedTypeMirror;
import org.codehaus.enunciate.contract.Facet;
import org.codehaus.enunciate.contract.HasFacets;
import org.codehaus.enunciate.contract.jaxb.adapters.Adaptable;
import org.codehaus.enunciate.contract.jaxb.adapters.AdapterType;
import org.codehaus.enunciate.contract.jaxb.adapters.AdapterUtil;
import org.codehaus.enunciate.contract.jaxb.types.KnownXmlType;
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.jaxb.util.JAXBUtil;
import org.codehaus.enunciate.contract.validation.ValidationException;
import org.codehaus.enunciate.qname.XmlQNameEnumRef;
import org.codehaus.enunciate.util.MapTypeUtil;
import org.codehaus.enunciate.util.MapType;
import org.codehaus.enunciate.ClientName;

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

/**
* An accessor for a field or method value into a type.
*
* @author Ryan Heaton
*/
public abstract class Accessor extends DecoratedMemberDeclaration implements Adaptable, HasFacets {

  private final TypeDefinition typeDefinition;
  private final AdapterType adapterType;
  private final Set<Facet> facets = new TreeSet<Facet>();

  public Accessor(MemberDeclaration delegate, TypeDefinition typeDef) {
    super(delegate);

    if ((!(delegate instanceof FieldDeclaration)) && (!(delegate instanceof PropertyDeclaration))) {
      throw new IllegalArgumentException("Only a field or a property can be a JAXB accessor.");
    }

    this.typeDefinition = typeDef;
    this.adapterType = AdapterUtil.findAdapterType(this);
    this.facets.addAll(Facet.gatherFacets(delegate));
    this.facets.addAll(typeDef.getFacets());
  }

  /**
   * The name of the accessor.
   *
   * @return The name of the accessor.
   */
  public abstract String getName();

  /**
   * The namespace of the accessor.
   *
   * @return The namespace of the accessor.
   */
  public abstract String getNamespace();

  /**
   * The simple name for client-side code generation.
   *
   * @return The simple name for client-side code generation.
   */
  public String getClientSimpleName() {
    String clientSimpleName = getSimpleName();
    ClientName clientName = getAnnotation(ClientName.class);
    if (clientName != null) {
      clientSimpleName = clientName.value();
    }
    return clientSimpleName;
  }

  /**
   * The type of the accessor.
   *
   * @return The type of the accessor.
   */
  public TypeMirror getAccessorType() {
    TypeMirror accessorType;
    Declaration delegate = getDelegate();
    if (delegate instanceof FieldDeclaration) {
      accessorType = ((FieldDeclaration) delegate).getType();
    }
    else {
      accessorType = ((PropertyDeclaration) delegate).getPropertyType();
    }

    TypeMirror bareCollection = JAXBUtil.getNormalizedCollection(accessorType);
    if (bareCollection != null) {
      accessorType = bareCollection;
    }
    else {
      MapType mapType = MapTypeUtil.findMapType(accessorType);
      if (mapType != null) {
        accessorType = mapType;
      }
    }

    return accessorType;
  }

  /**
   * The bare (i.e. unwrapped) type of the accessor.
   *
   * @return The bare type of the accessor.
   */
  public TypeMirror getBareAccessorType() {
    return isCollectionType() ? getCollectionItemType() : getAccessorType();
  }

  /**
   * The base xml type of the accessor. The base type is either:
   * <p/>
   * <ol>
   * <li>The xml type of the accessor type.</li>
   * <li>The xml type of the component type of the accessor type if the accessor
   * type is a collection type.</li>
   * </ol>
   *
   * @return The base type.
   */
  public XmlType getBaseType() {
    //first check to see if the base type is dictated by a specific annotation.
    if (isXmlID()) {
      return KnownXmlType.ID;
    }

    if (isXmlIDREF()) {
      return KnownXmlType.IDREF;
    }

    if (isSwaRef()) {
      return KnownXmlType.SWAREF;
    }

    try {
      XmlType xmlType = XmlTypeFactory.findSpecifiedType(this);
      return (xmlType != null) ? xmlType : XmlTypeFactory.getXmlType(getAccessorType());
    }
    catch (XmlTypeException e) {
      throw new ValidationException(getPosition(), "Accessor " + getName() + " of " + getTypeDefinition().getQualifiedName() + ": " + e.getMessage());
    }
  }

  /**
   * The qname for the referenced accessor, if this accessor 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() {
    return null;
  }

  /**
   * The type definition for this accessor.
   *
   * @return The type definition for this accessor.
   */
  public TypeDefinition getTypeDefinition() {
    return typeDefinition;
  }

  /**
   * Whether this accessor is specified as an xml list.
   *
   * @return Whether this accessor is specified as an xml list.
   */
  public boolean isXmlList() {
    return getAnnotation(XmlList.class) != null;
  }

  /**
   * Whether this accessor is an XML ID.
   *
   * @return Whether this accessor is an XMLID.
   */
  public boolean isXmlID() {
    return getAnnotation(XmlID.class) != null;
  }

  /**
   * Whether this accessor is an XML IDREF.
   *
   * @return Whether this accessor is an XML IDREF.
   */
  public boolean isXmlIDREF() {
    return getAnnotation(XmlIDREF.class) != null;
  }

  /**
   * Whether this accessor consists of binary data.
   *
   * @return Whether this accessor consists of binary data.
   */
  public boolean isBinaryData() {
    return isSwaRef() || KnownXmlType.BASE64_BINARY.getQname().equals(getBaseType().getQname());
  }

  /**
   * Whether this access is a QName type.
   *
   * @return Whether this access is a QName type.
   */
  public boolean isQNameType() {
    return getBaseType() == KnownXmlType.QNAME;
  }

  /**
   * Get the resolved accessor type for this accessor.
   *
   * @return the resolved accessor type for this accessor.
   */
  public TypeMirror getResolvedAccessorType() {
    TypeMirror accessorType = getAccessorType();

    if (isAdapted()) {
      accessorType = getAdapterType().getAdaptingType(accessorType);
    }

    return accessorType;
  }

  /**
   * Whether this accessor is a swa ref.
   *
   * @return Whether this accessor is a swa ref.
   */
  public boolean isSwaRef() {
    return (getAnnotation(XmlAttachmentRef.class) != null)
      && (getAccessorType() instanceof DeclaredType)
      && (((DeclaredType) getAccessorType()).getDeclaration() != null)
      && ("javax.activation.DataHandler".equals(((DeclaredType) getAccessorType()).getDeclaration().getQualifiedName()));
  }

  /**
   * Whether this accessor is an MTOM attachment.
   *
   * @return Whether this accessor is an MTOM attachment.
   */
  public boolean isMTOMAttachment() {
    return (getAnnotation(XmlInlineBinaryData.class) == null) && (KnownXmlType.BASE64_BINARY.getQname().equals(getBaseType().getQname()));
  }

  /**
   * The suggested mime type of the binary data, or null if none.
   *
   * @return The suggested mime type of the binary data, or null if none.
   */
  public String getMimeType() {
    XmlMimeType mimeType = getAnnotation(XmlMimeType.class);
    if (mimeType != null) {
      return mimeType.value();
    }

    return null;
  }

  /**
   * Whether the accessor type is a collection type.
   *
   * @return Whether the accessor type is a collection type.
   */
  public boolean isCollectionType() {
    if (isXmlList()) {
      return false;
    }

    DecoratedTypeMirror accessorType;
    if (isAdapted()) {
      accessorType = (DecoratedTypeMirror) TypeMirrorDecorator.decorate(getAdapterType().getAdaptingType(getAccessorType()));
    }
    else {
      accessorType = (DecoratedTypeMirror) TypeMirrorDecorator.decorate(getAccessorType());
    }

    if (accessorType.isArray()) {
      TypeMirror componentType = ((ArrayType) accessorType).getComponentType();
      //special case for byte[]
      return !(componentType instanceof PrimitiveType) || !(((PrimitiveType) componentType).getKind() == PrimitiveType.Kind.BYTE);
    }

    return accessorType.isCollection();
  }

  /**
   * If this is a collection type, return the type parameter of the collection, or null if this isn't a
   * parameterized collection type.
   *
   * @return the type parameter of the collection.
   */
  public TypeMirror getCollectionItemType() {
    DecoratedTypeMirror accessorType;
    if (isAdapted()) {
      accessorType = (DecoratedTypeMirror) TypeMirrorDecorator.decorate(getAdapterType().getAdaptingType(getAccessorType()));
    }
    else {
      accessorType = (DecoratedTypeMirror) TypeMirrorDecorator.decorate(getAccessorType());
    }

    if (accessorType.isArray()) {
      return ((ArrayType) accessorType).getComponentType();
    }
    else if (accessorType.isCollection()) {
      Iterator<TypeMirror> itemTypes = ((DeclaredType) accessorType).getActualTypeArguments().iterator();
      if (!itemTypes.hasNext()) {
        AnnotationProcessorEnvironment env = Context.getCurrentEnvironment();
        Types typeUtils = env.getTypeUtils();
        return TypeMirrorDecorator.decorate(typeUtils.getDeclaredType(env.getTypeDeclaration(java.lang.Object.class.getName())));
      }
      else {
        return itemTypes.next();
      }
    }

    return null;
  }

  /**
   * Returns the accessor for the XML id, or null if none was found or if this isn't an Xml IDREF accessor.
   *
   * @return The accessor, or null.
   */
  public MemberDeclaration getAccessorForXmlID() {
    if (isXmlIDREF()) {
      TypeMirror accessorType = getBareAccessorType();
      if (accessorType instanceof ClassType) {
        return getXmlIDAccessor((ClassType) accessorType);
      }
    }

    return null;
  }

  /**
   * Gets the xml id accessor for the specified class type (recursively through superclasses).
   *
   * @param classType The class type.
   * @return The xml id accessor.
   */
  private MemberDeclaration getXmlIDAccessor(ClassType classType) {
    ClassDeclaration declaration = classType.getDeclaration();
    if ((declaration == null) || (Object.class.getName().equals(declaration.getQualifiedName()))) {
      return null;
    }

    DecoratedClassDeclaration decoratedDeclaration = (DecoratedClassDeclaration) DeclarationDecorator.decorate(declaration);

    for (FieldDeclaration field : decoratedDeclaration.getFields()) {
      if (field.getAnnotation(XmlID.class) != null) {
        return field;
      }
    }

    for (PropertyDeclaration property : decoratedDeclaration.getProperties()) {
      if (property.getAnnotation(XmlID.class) != null) {
        return property;
      }
    }

    return getXmlIDAccessor(classType.getSuperclass());
  }

  /**
   * @return The list of class names that this type definition wants you to "see also".
   */
  public Collection<TypeMirror> getSeeAlsos() {
    Collection<TypeMirror> seeAlsos = null;
    XmlSeeAlso seeAlsoInfo = getAnnotation(XmlSeeAlso.class);
    if (seeAlsoInfo != null) {
      seeAlsos = new ArrayList<TypeMirror>();
      try {
        AnnotationProcessorEnvironment env = Context.getCurrentEnvironment();
        for (Class clazz : seeAlsoInfo.value()) {
          TypeDeclaration typeDeclaration = env.getTypeDeclaration(clazz.getName());
          DeclaredType undecorated = env.getTypeUtils().getDeclaredType(typeDeclaration);
          seeAlsos.add(undecorated);
        }
      }
      catch (MirroredTypesException e) {
        seeAlsos.addAll(e.getTypeMirrors());
      }
    }
    return seeAlsos;
  }

  // Inherited.
  public boolean isAdapted() {
    return this.adapterType != null;
  }

  // Inherited.
  public AdapterType getAdapterType() {
    return this.adapterType;
  }

  /**
   * Whether this accessor is an attribute.
   *
   * @return Whether this accessor is an attribute.
   */
  public boolean isAttribute() {
    return false;
  }

  /**
   * Whether this accessor is a value.
   *
   * @return Whether this accessor is a value.
   */
  public boolean isValue() {
    return false;
  }

  /**
   * Whether this accessor is an element ref.
   *
   * @return Whether this accessor is an element ref.
   */
  public boolean isElementRef() {
    return false;
  }

  /**
   * Whether this QName accessor references a QName enum type.
   *
   * @return Whether this QName accessor references a QName enum type.
   */
  public boolean isReferencesQNameEnum() {
    return getAnnotation(XmlQNameEnumRef.class) != null;
  }

  /**
   * The enum type containing the known qnames for this qname enum accessor, or null is this accessor doesn't reference a known qname type.
   *
   * @return The enum type containing the known qnames for this qname enum accessor.
   */
  public TypeMirror getQNameEnumRef() {
    XmlQNameEnumRef enumRef = getAnnotation(XmlQNameEnumRef.class);
    TypeMirror qnameEnumType = null;
    if (enumRef != null) {
      AnnotationProcessorEnvironment env = Context.getCurrentEnvironment();
      try {
        TypeDeclaration decl = env.getTypeDeclaration(enumRef.value().getName());
        qnameEnumType = env.getTypeUtils().getDeclaredType(decl);
      }
      catch (MirroredTypeException e) {
        qnameEnumType = e.getTypeMirror();
      }
    }
    return qnameEnumType;
  }

  /**
   * Set of (human-readable) locations that this type definition is referenced from.
   *
   * @return The referenced-from list.
   */
  public Set<String> getReferencedFrom() {
    TreeSet<String> referenceFrom = new TreeSet<String>();
    for (String location : this.typeDefinition.getReferencedFrom()) {
      referenceFrom.add("type definition " + this.typeDefinition.getQualifiedName() + " referenced from " + location);
    }
    return referenceFrom;
  }

  /**
   * The facets here applicable.
   *
   * @return The facets here applicable.
   */
  public Set<Facet> getFacets() {
    return facets;
  }

  /**
   * Get the name for the JSON member to which this element will be serialized.
   *
   * @return The JSON member name.
   */
  public abstract String getJsonMemberName();
}
TOP

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

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.