/*
* Copyright (C) 2003-2011 eXo Platform SAS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.etk.reflect.apt.jxlr.metadata;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.TypeParameterElement;
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.NoType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable;
import javax.lang.model.type.WildcardType;
import org.etk.reflect.api.definition.ClassKind;
import org.etk.reflect.api.definition.LiteralKind;
import org.etk.reflect.api.definition.TypeKind;
import org.etk.reflect.api.metadata.GenericDeclarationKind;
import org.etk.reflect.api.metadata.TypeMetadata;
/**
* Created by The eXo Platform SAS
* Author : eXoPlatform
* exo@exoplatform.com
* Jul 13, 2011
*/
public class JxLTypeMetadata implements TypeMetadata<Object> {
/** . */
static final Map<String, LiteralKind> primitiveWrapperMap;
static {
Map<String, LiteralKind> map = new HashMap<String, LiteralKind>();
map.put(Boolean.class.getName(), LiteralKind.BOOLEAN);
map.put(Byte.class.getName(), LiteralKind.BYTE);
map.put(Short.class.getName(), LiteralKind.SHORT);
map.put(Integer.class.getName(), LiteralKind.INT);
map.put(Long.class.getName(), LiteralKind.LONG);
map.put(Float.class.getName(), LiteralKind.FLOAT);
map.put(Double.class.getName(), LiteralKind.DOUBLE);
primitiveWrapperMap = map;
}
public TypeKind getKind(Object type) {
if (type instanceof TypeElement) {
// We always assume that a type element is a class
TypeElement elt = (TypeElement)type;
String name = elt.getQualifiedName().toString();
if (primitiveWrapperMap.containsKey(name)) {
return TypeKind.SIMPLE;
} else {
return TypeKind.CLASS;
}
} else {
TypeMirror mirror = (TypeMirror)type;
switch (mirror.getKind()) {
case VOID:
return TypeKind.VOID;
case BOOLEAN:
case BYTE:
case SHORT:
case INT:
case LONG:
case FLOAT:
case DOUBLE:
return TypeKind.SIMPLE;
case DECLARED:
// In case of
DeclaredType declaredType = (DeclaredType)mirror;
if (declaredType.getTypeArguments().isEmpty()) {
String name = ((TypeElement)declaredType.asElement()).getQualifiedName().toString();
if (primitiveWrapperMap.containsKey(name)) {
return TypeKind.SIMPLE;
} else {
return TypeKind.CLASS;
}
} else {
return TypeKind.PARAMETERIZED;
}
case TYPEVAR:
return TypeKind.VARIABLE;
case WILDCARD:
return TypeKind.WILDCARD;
case ARRAY:
return TypeKind.ARRAY;
default:
throw new AssertionError("Cannot handle type " + type + " of kind " + mirror.getKind());
}
}
}
public Object getEnclosing(Object classType) {
if (classType instanceof TypeElement) {
TypeElement typeElt = (TypeElement)classType;
switch (typeElt.getNestingKind()) {
case TOP_LEVEL:
return null;
case MEMBER:
return typeElt.getEnclosingElement();
case LOCAL:
case ANONYMOUS:
throw new UnsupportedOperationException("todo nesting kind");
}
return typeElt.getQualifiedName().toString();
} else {
TypeMirror typeMirror = (TypeMirror)classType;
switch (typeMirror.getKind()) {
case BOOLEAN:
case BYTE:
case SHORT:
case INT:
case LONG:
case FLOAT:
case DOUBLE:
case VOID:
return null;
case DECLARED:
DeclaredType declaredType = (DeclaredType)classType;
return getEnclosing(declaredType.asElement());
default:
throw new AssertionError("Cannot handle type " + typeMirror + " of kind " + typeMirror.getKind() + " as class type");
}
}
}
public String getClassName(Object classType) {
if (classType instanceof TypeElement) {
TypeElement typeElt = (TypeElement)classType;
switch (typeElt.getNestingKind()) {
case TOP_LEVEL:
return typeElt.getQualifiedName().toString();
case MEMBER:
return getClassName(typeElt.getEnclosingElement()) + "$" + typeElt.getSimpleName();
case LOCAL:
case ANONYMOUS:
throw new UnsupportedOperationException("todo nesting kind");
}
return typeElt.getQualifiedName().toString();
} else {
TypeMirror typeMirror = (TypeMirror)classType;
switch (typeMirror.getKind()) {
case BOOLEAN:
return boolean.class.getName();
case BYTE:
return byte.class.getName();
case SHORT:
return short.class.getName();
case INT:
return int.class.getName();
case LONG:
return long.class.getName();
case FLOAT:
return float.class.getName();
case DOUBLE:
return double.class.getName();
case VOID:
return Void.class.getName();
case DECLARED:
DeclaredType declaredType = (DeclaredType)classType;
return getClassName(declaredType.asElement());
default:
throw new AssertionError("Cannot handle type " + typeMirror + " of kind " + typeMirror.getKind() + " as class type");
}
}
}
public Iterable<Object> getInterfaces(Object classType) {
if (classType instanceof TypeElement) {
TypeElement typeElt = (TypeElement)classType;
List<Object> interfaces = new ArrayList<Object>();
for (TypeMirror itf : typeElt.getInterfaces()) {
interfaces.add(itf);
}
return interfaces;
} else {
DeclaredType declaredType = (DeclaredType)classType;
return getInterfaces(declaredType.asElement());
}
}
public ClassKind getClassKind(Object classType) {
if (classType instanceof TypeElement) {
TypeElement typeElt = (TypeElement)classType;
switch (typeElt.getKind()) {
case ENUM:
return ClassKind.ENUM;
case ANNOTATION_TYPE:
return ClassKind.ANNOTATION;
case INTERFACE:
return ClassKind.INTERFACE;
case CLASS:
return ClassKind.CLASS;
default:
throw new AssertionError("Cannot handle type " + typeElt + " of kind " + typeElt.getKind() + " as class type");
}
} else {
TypeMirror mirror = (TypeMirror)classType;
switch (mirror.getKind()) {
case BOOLEAN:
case BYTE:
case SHORT:
case INT:
case LONG:
case FLOAT:
case DOUBLE:
return ClassKind.CLASS;
case VOID:
return ClassKind.CLASS;
case DECLARED:
DeclaredType declared = (DeclaredType)mirror;
return getClassKind(declared.asElement());
default:
throw new AssertionError();
}
}
}
public Object getSuperClass(Object classType) {
if (classType instanceof TypeElement) {
TypeElement typeElt = (TypeElement)classType;
TypeMirror superType = typeElt.getSuperclass();
if (superType instanceof NoType) {
return null;
} else {
return superType;
}
} else {
DeclaredType declaredType = (DeclaredType)classType;
return getSuperClass(declaredType.asElement());
}
}
public Iterable<Object> getTypeParameters(Object classType) {
if (classType instanceof TypeElement) {
TypeElement typeElt = (TypeElement)classType;
List<Object> typeParameters = new ArrayList<Object>();
for (TypeParameterElement typeParameterElt : typeElt.getTypeParameters()) {
typeParameters.add(typeParameterElt.asType());
}
return typeParameters;
} else {
DeclaredType declaredType = (DeclaredType)classType;
return getTypeParameters(declaredType.asElement());
}
}
public String getName(Object typeVariable) {
TypeParameterElement tpe = (TypeParameterElement)((TypeVariable)typeVariable).asElement();
return tpe.getSimpleName().toString();
}
public GenericDeclarationKind getGenericDeclarationKind(Object typeVariable) {
TypeParameterElement tpe = (TypeParameterElement)((TypeVariable)typeVariable).asElement();
Element genericElt =tpe.getGenericElement();
switch (genericElt.getKind()) {
case INTERFACE:
case CLASS:
return GenericDeclarationKind.TYPE;
case METHOD:
return GenericDeclarationKind.METHOD;
default:
throw new AssertionError();
}
}
public LiteralKind getLiteralType(Object simpleType) {
if (simpleType instanceof TypeElement) {
TypeElement elt = (TypeElement)simpleType;
String name = elt.getQualifiedName().toString();
LiteralKind literalType = primitiveWrapperMap.get(name);
if (literalType == null) {
throw new AssertionError("Cannot handle type " + simpleType);
} else {
return literalType;
}
} else {
TypeMirror mirror = (TypeMirror)simpleType;
switch (mirror.getKind()) {
case BOOLEAN:
return LiteralKind.BOOLEAN;
case BYTE:
return LiteralKind.BYTE;
case SHORT:
return LiteralKind.SHORT;
case INT:
return LiteralKind.INT;
case LONG:
return LiteralKind.LONG;
case FLOAT:
return LiteralKind.FLOAT;
case DOUBLE:
return LiteralKind.DOUBLE;
case DECLARED:
return getLiteralType(((DeclaredType)mirror).asElement());
default:
throw new AssertionError("Cannot handle type " + simpleType + " of kind " + mirror.getKind());
}
}
}
public Object getComponentType(Object arrayType) {
return ((ArrayType)arrayType).getComponentType();
}
public boolean isPrimitive(Object simpleType) {
if (simpleType instanceof TypeElement) {
TypeElement elt = (TypeElement)simpleType;
String name = elt.getQualifiedName().toString();
if (primitiveWrapperMap.containsKey(name)) {
return false;
} else {
throw new AssertionError("Cannot handle type " + simpleType);
}
} else {
TypeMirror mirror = (TypeMirror)simpleType;
switch (mirror.getKind()) {
case BOOLEAN:
case BYTE:
case SHORT:
case INT:
case LONG:
case FLOAT:
case DOUBLE:
return true;
case DECLARED:
return isPrimitive(((DeclaredType)mirror).asElement());
default:
throw new AssertionError("Cannot handle type " + simpleType + " of kind " + mirror.getKind());
}
}
}
public Object getGenericDeclaration(Object typeVariable) {
return ((TypeParameterElement)((TypeVariable)typeVariable).asElement()).getGenericElement();
}
public Object getRawType(Object parameterizedType) {
return ((DeclaredType)parameterizedType).asElement();
}
public Iterable<Object> getTypeArguments(Object parameterizedType) {
List<Object> typeArguments = new ArrayList<Object>();
for (TypeMirror typeArgument : ((DeclaredType)parameterizedType).getTypeArguments()) {
typeArguments.add(typeArgument);
}
return typeArguments;
}
private List<Object> resolveBounds(TypeMirror bound) {
if (bound == null) {
return Collections.emptyList();
} else {
ArrayList<Object> bounds = new ArrayList<Object>();
if (bound instanceof DeclaredType) {
DeclaredType bilto = (DeclaredType)bound;
TypeElement boundElt = (TypeElement)bilto.asElement();
switch (boundElt.getNestingKind()) {
case ANONYMOUS:
// We need to rewrite it
if (!(boundElt.getSuperclass() instanceof NoType)) {
bounds.add(boundElt.getSuperclass());
}
for (TypeMirror itf : boundElt.getInterfaces()) {
bounds.add(itf);
}
break;
default:
bounds.add(bound);
break;
}
} else {
bounds.add(bound);
}
return bounds;
}
}
public Iterable<Object> getBounds(Object typeVariable) {
TypeMirror upperBound = ((TypeVariable)typeVariable).getUpperBound();
return resolveBounds(upperBound);
}
public Iterable<Object> getUpperBounds(Object wildcardType) {
TypeMirror extendsBound = ((WildcardType)wildcardType).getExtendsBound();
return resolveBounds(extendsBound);
}
public Iterable<Object> getLowerBounds(Object wildcardType) {
TypeMirror superBounds = ((WildcardType)wildcardType).getSuperBound();
return resolveBounds(superBounds);
}
}