/*******************************************************************************
* Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* 08/10/2009-2.0 Guy Pelletier
* - 267391: JPA 2.0 implement/extend/use an APT tooling library for MetaModel API canonical classes
******************************************************************************/
package org.eclipse.persistence.internal.jpa.modelgen.visitors;
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.ErrorType;
import javax.lang.model.type.ExecutableType;
import javax.lang.model.type.NoType;
import javax.lang.model.type.NullType;
import javax.lang.model.type.PrimitiveType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable;
import javax.lang.model.type.WildcardType;
import javax.lang.model.util.SimpleTypeVisitor6;
import org.eclipse.persistence.internal.jpa.metadata.accessors.objects.MetadataAnnotatedElement;
import org.eclipse.persistence.internal.jpa.metadata.accessors.objects.MetadataClass;
import org.eclipse.persistence.internal.jpa.metadata.accessors.objects.MetadataMethod;
import org.eclipse.persistence.internal.jpa.modelgen.MetadataMirrorFactory;
/**
* A type visitor.
*
* @author Guy Pelletier
* @since EclipseLink 1.2
*/
public class TypeVisitor<R, P> extends SimpleTypeVisitor6<MetadataAnnotatedElement, MetadataAnnotatedElement> {
public static String GENERIC_TYPE = "? extends Object";
/**
* INTERNAL:
*/
public TypeVisitor() {}
/**
* INTERNAL:
* Visit a declared array field.
*/
@Override
public MetadataAnnotatedElement visitArray(ArrayType arrayType, MetadataAnnotatedElement annotatedElement) {
annotatedElement.setType(arrayType.toString());
return annotatedElement;
}
/**
* INTERNAL:
* Visit a declared field or Class.
*/
@Override
public MetadataAnnotatedElement visitDeclared(DeclaredType declaredType, MetadataAnnotatedElement annotatedElement) {
// Get the metadata class of the declared type from the factory.
MetadataMirrorFactory factory = (MetadataMirrorFactory) annotatedElement.getMetadataFactory();
MetadataClass cls = factory.getMetadataClass(declaredType);
// Set the type, which is the class name.
annotatedElement.setType(cls.getName());
// Set the generic types. Internally EclipseLink wants the class name
// in the 0 position of the generic list.
annotatedElement.addGenericType(cls.getName());
for (TypeMirror typeArgument : declaredType.getTypeArguments()) {
// Set the type from the metadata class as it may be a generic and
// we don't want to set the letter type, rather our default GENERIC_TYPE.
annotatedElement.addGenericType(factory.getMetadataClass(typeArgument).getType());
}
return annotatedElement;
}
/**
* INTERNAL:
*/
@Override
public MetadataAnnotatedElement visitError(ErrorType errorType, MetadataAnnotatedElement annotatedElement) {
// We will hit this case when there exists a compile error on the model.
// However our annotation processor will still be called and we
// therefore want to ensure our annotatedElement still has a type set
// on it and not null. This will avoid exceptions when we go through
// the pre-processing of our metadata classes.
annotatedElement.setType(GENERIC_TYPE);
return annotatedElement;
}
/**
* INTERNAL:
* Visit a method.
*/
@Override
public MetadataAnnotatedElement visitExecutable(ExecutableType executableType, MetadataAnnotatedElement annotatedElement) {
MetadataMirrorFactory factory = ((MetadataMirrorFactory) annotatedElement.getMetadataFactory());
MetadataMethod method = (MetadataMethod) annotatedElement;
// Set the parameters.
for (TypeMirror parameter : executableType.getParameterTypes()) {
method.addParameter(factory.getMetadataClass(parameter).getType());
}
// Visit the return type (will set the type and generic types).
executableType.getReturnType().accept(this, method);
method.setReturnType(method.getType());
return method;
}
/**
* INTERNAL:
* Method that returns void.
*/
@Override
public MetadataAnnotatedElement visitNoType(NoType noType, MetadataAnnotatedElement annotatedElement) {
// Should this be Void.class?
annotatedElement.setType(GENERIC_TYPE);
return annotatedElement;
}
/**
* INTERNAL:
*/
@Override
public MetadataAnnotatedElement visitNull(NullType nullType, MetadataAnnotatedElement annotatedElement) {
// We will hit this case when there exists a compile error on the model??
// However our annotation processor will still be called and we
// therefore want to ensure our annotatedElement still has a type set
// on it and not null. This will avoid exceptions when we go through
// the pre-processing of our metadata classes.
annotatedElement.setType(GENERIC_TYPE);
return annotatedElement;
}
/**
* INTERNAL:
* Visit a declared primitive field.
*/
@Override
public MetadataAnnotatedElement visitPrimitive(PrimitiveType primitiveType, MetadataAnnotatedElement annotatedElement) {
// We can not set the boxed type here. We must preserve the actual type
// otherwise during accessor pre-process a validation exception will
// occur under property access since we'll look for the equivalent
// set method with the boxed class which will not be found. We deal with
// boxing the type when generating the canonical model.
annotatedElement.setPrimitiveType(primitiveType);
return annotatedElement;
}
/**
* INTERNAL:
*/
@Override
public MetadataAnnotatedElement visitTypeVariable(TypeVariable typeVariable, MetadataAnnotatedElement annotatedElement) {
annotatedElement.setType(GENERIC_TYPE);
return annotatedElement;
}
/**
* INTERNAL:
*/
@Override
public MetadataAnnotatedElement visitWildcard(WildcardType wildcardType, MetadataAnnotatedElement annotatedElement) {
annotatedElement.setType(wildcardType.toString());
return annotatedElement;
}
}