Package org.codehaus.enunciate.contract.jaxb.types

Source Code of org.codehaus.enunciate.contract.jaxb.types.XmlTypeVisitor

/*
* 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.types;

import com.sun.mirror.declaration.ClassDeclaration;
import com.sun.mirror.type.*;
import com.sun.mirror.util.TypeVisitor;
import net.sf.jelly.apt.freemarker.FreemarkerModel;
import org.codehaus.enunciate.apt.EnunciateFreemarkerModel;
import org.codehaus.enunciate.contract.jaxb.TypeDefinition;
import org.codehaus.enunciate.contract.jaxb.adapters.AdapterType;
import org.codehaus.enunciate.contract.jaxb.adapters.AdapterUtil;
import org.codehaus.enunciate.util.MapType;
import org.codehaus.enunciate.util.MapTypeUtil;

import java.util.Iterator;

/**
* Utility visitor for discovering the xml types of type mirrors.
*
* @author Ryan Heaton
*/
class XmlTypeVisitor implements TypeVisitor {

  /**
   * State-keeping variable used to determine whether we've already been visited by an array type.
   */
  boolean isInArray;
  /**
   * State-keeping variable used to determine whether we've already been visited by a collection type.
   */
  boolean isInCollection;
  private XmlType xmlType;
  private String errorMessage = null;

  XmlTypeVisitor() {
  }

  /**
   * Get the xml type.
   *
   * @return The xml type of the visitor.
   */
  public XmlType getXmlType() {
    return xmlType;
  }

  /**
   * The error message.  Its existence implies an error when visiting a type.
   *
   * @return The error message.
   */
  public String getErrorMessage() {
    return errorMessage;
  }

  public void visitTypeMirror(TypeMirror typeMirror) {
    this.xmlType = null;
    this.errorMessage = "Unknown xml type: " + typeMirror;
  }

  public void visitPrimitiveType(PrimitiveType primitiveType) {
    if (isInArray && (primitiveType.getKind() == PrimitiveType.Kind.BYTE)) {
      //special case for byte[]
      this.xmlType = KnownXmlType.BASE64_BINARY;
    }
    else {
      this.xmlType = new XmlPrimitiveType(primitiveType);
    }
  }

  public void visitVoidType(VoidType voidType) {
    this.xmlType = null;
    this.errorMessage = "Void is not a valid xml type.";
  }

  public void visitReferenceType(ReferenceType referenceType) {
    this.xmlType = null;
    this.errorMessage = "Unknown xml type: " + referenceType;
  }

  public void visitDeclaredType(DeclaredType declaredType) {
    MapType mapType = MapTypeUtil.findMapType(declaredType);
    if (mapType != null) {
      setMapXmlType(mapType);
    }
    else {
      this.xmlType = null;
      this.errorMessage = "Unknown xml type: " + declaredType;
    }
  }

  public void visitClassType(ClassType classType) {
    MapType mapType = MapTypeUtil.findMapType(classType);
    if (mapType != null) {
      setMapXmlType(mapType);
    }
    else {
      XmlType xmlType = null;
      EnunciateFreemarkerModel model = (EnunciateFreemarkerModel) FreemarkerModel.get();
      ClassDeclaration declaration = classType.getDeclaration();
      if (declaration != null) {
        XmlType knownType = model.getKnownType(declaration);
        if (knownType != null) {
          xmlType = knownType;
        }
        else {
          //type not known, not specified.  Last chance: look for the type definition.
          TypeDefinition typeDefinition = model.findTypeDefinition(declaration);
          if (typeDefinition != null) {
            xmlType = new XmlClassType(typeDefinition);
          }
        }
      }
      this.xmlType = xmlType;
      if (xmlType == null) {
        this.errorMessage = "Unknown xml type for class: " + classType +
          ".  If this is a class that is already compiled, you either need to specify an 'api-import' " +
          "element in the configuration file, or your class needs to be explicitly exported. See the FAQ " +
          "( http://tinyurl.com/cte3oq ) for details.";
      }
    }
  }

  public void visitEnumType(EnumType enumType) {
    visitClassType(enumType);
  }

  public void visitInterfaceType(InterfaceType interfaceType) {
    AdapterType adapterType = AdapterUtil.findAdapterType(interfaceType.getDeclaration());
    if (adapterType != null) {
      adapterType.getAdaptingType().accept(this);
    }
    else {
      MapType mapType = MapTypeUtil.findMapType(interfaceType);
      if (mapType != null) {
        setMapXmlType(mapType);
      }
      else if (isInCollection) {
        this.xmlType = KnownXmlType.ANY_TYPE;
      }
      else {
        this.xmlType = null;
        this.errorMessage = "An interface type cannot be an xml type.";
      }
    }
  }

  /**
   * Sets the map xml type.
   *
   * @param mapType The map type to use.
   */
  private void setMapXmlType(MapType mapType) {
    try {
      XmlType keyType = XmlTypeFactory.getXmlType(mapType.getKeyType());
      XmlType valueType = XmlTypeFactory.getXmlType(mapType.getValueType());
      this.xmlType = new MapXmlType(keyType, valueType);
    }
    catch (XmlTypeException e) {
      this.errorMessage = "Error with map type: " + e.getMessage();
    }
  }

  public void visitAnnotationType(AnnotationType annotationType) {
    this.xmlType = null;
    this.errorMessage = "An annotation type cannot be an xml type.";
  }

  public void visitArrayType(ArrayType arrayType) {
    if (isInArray) {
      this.xmlType = null;
      this.errorMessage = "No support yet for multidimensional arrays.";
      return;
    }

    arrayType.getComponentType().accept(this);

    if (this.errorMessage != null) {
      this.errorMessage = "Problem with the array component type: " + this.errorMessage;
    }
  }

  public void visitTypeVariable(TypeVariable typeVariable) {
    Iterator<ReferenceType> bounds = typeVariable.getDeclaration().getBounds().iterator();
    if (!bounds.hasNext()) {
      this.xmlType = KnownXmlType.ANY_TYPE;
    }
    else {
      bounds.next().accept(this);
      if (this.errorMessage != null) {
        this.errorMessage = "Problem with the type variable bounds: " + this.errorMessage;
      }
    }
  }

  public void visitWildcardType(WildcardType wildcardType) {
    Iterator<ReferenceType> upperBounds = wildcardType.getUpperBounds().iterator();
    if (!upperBounds.hasNext()) {
      this.xmlType = KnownXmlType.ANY_TYPE;
    }
    else {
      upperBounds.next().accept(this);

      if (this.errorMessage != null) {
        this.errorMessage = "Problem with wildcard bounds: " + this.errorMessage;
      }
    }
  }


}
TOP

Related Classes of org.codehaus.enunciate.contract.jaxb.types.XmlTypeVisitor

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.