io.sundr.codegen.functions.ElementTo Maven / Gradle / Ivy
/*
* Copyright 2016 The original authors.
*
* 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 io.sundr.codegen.functions;
import io.sundr.FunctionFactory;
import io.sundr.Function;
import io.sundr.codegen.CodegenContext;
import io.sundr.codegen.DefinitionRepository;
import io.sundr.codegen.converters.TypeRefTypeVisitor;
import io.sundr.codegen.model.AnnotationRef;
import io.sundr.codegen.model.AnnotationRefBuilder;
import io.sundr.codegen.model.AttributeKey;
import io.sundr.codegen.model.Attributeable;
import io.sundr.codegen.model.ClassRef;
import io.sundr.codegen.model.ClassRefBuilder;
import io.sundr.codegen.model.Kind;
import io.sundr.codegen.model.Method;
import io.sundr.codegen.model.MethodBuilder;
import io.sundr.codegen.model.Property;
import io.sundr.codegen.model.PropertyBuilder;
import io.sundr.codegen.model.TypeDef;
import io.sundr.codegen.model.TypeDefBuilder;
import io.sundr.codegen.model.TypeParamDef;
import io.sundr.codegen.model.TypeParamDefBuilder;
import io.sundr.codegen.model.TypeParamRef;
import io.sundr.codegen.model.TypeParamRefBuilder;
import io.sundr.codegen.model.TypeRef;
import io.sundr.codegen.model.VoidRef;
import io.sundr.codegen.utils.TypeUtils;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.TypeParameterElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.NoType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable;
import javax.lang.model.util.ElementFilter;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import static io.sundr.codegen.utils.ModelUtils.getClassName;
import static io.sundr.codegen.utils.ModelUtils.getPackageName;
public class ElementTo {
private static final String OBJECT_BOUND = "java.lang.Object";
private static final String JAVA_PEFIX = "java.";
private static final String JAVAX_PEFIX = "javax.";
private static final String COM_SUN_PREFIX = "com.sun.";
private static final String EMPTY_PARENTHESIS = "()";
private static final String EMPTY = "";
private static final Function IS_JAVA_TYPE_MIRROR = new Function() {
public Boolean apply(TypeMirror item) {
String fqn = item.toString();
return fqn.startsWith(JAVA_PEFIX) || fqn.startsWith(JAVAX_PEFIX) || fqn.startsWith(COM_SUN_PREFIX);
}
};
private static final Function IS_JAVA_ELEMENT = new Function() {
public Boolean apply(TypeElement item) {
String fqn = item.toString();
return fqn.startsWith(JAVA_PEFIX) || fqn.startsWith(JAVAX_PEFIX) || fqn.startsWith(COM_SUN_PREFIX);
}
};
private static final Function DEEP_MIRROR_TO_TYPEREF = new Function() {
public TypeRef apply(TypeMirror item) {
if (item instanceof NoType) {
return new VoidRef();
}
Element element = CodegenContext.getContext().getTypes().asElement(item);
TypeDef known = element != null ? CodegenContext.getContext().getDefinitionRepository().getDefinition(element.toString()) : null;
if (known == null && element instanceof TypeElement) {
known = TYPEDEF.apply((TypeElement) element);
}
TypeRef typeRef = item.accept(new TypeRefTypeVisitor(), 0);
if (typeRef instanceof ClassRef && known != null) {
return new ClassRefBuilder((ClassRef) typeRef).withDefinition(known).build();
}
return typeRef;
}
};
private static final Function SHALLOW_MIRROR_TO_TYPEREF = new Function() {
public TypeRef apply(TypeMirror item) {
return item.accept(new TypeRefTypeVisitor(), 0);
}
};
public static final Function MIRROR_TO_TYPEREF = FunctionFactory.cache(DEEP_MIRROR_TO_TYPEREF)
.withFallback(SHALLOW_MIRROR_TO_TYPEREF)
.withFallbackPredicate(IS_JAVA_TYPE_MIRROR)
.withMaximumRecursionLevel(10)
.withMaximumNestingDepth(10);
public static final Function TYPEPARAMDEF = new Function () {
public TypeParamDef apply(TypeParameterElement item) {
List typeRefs = new ArrayList();
for (TypeMirror typeMirror : item.getBounds()) {
//TODO: Fix this
//typeRefs.add(toTypeRef.apply(typeMirror));
}
return new TypeParamDefBuilder()
.withName(item.getSimpleName().toString())
.withBounds(typeRefs)
.build();
}
};
public static final Function TYPEVARIABLE_TO_TYPEPARAM_REF = new Function() {
public TypeParamRef apply(TypeVariable item) {
return new TypeParamRefBuilder().withName(item.asElement().getSimpleName().toString()).build();
}
};
public static final Function PROPERTY = new Function() {
public Property apply(final VariableElement variableElement) {
String name = variableElement.getSimpleName().toString();
TypeRef type = MIRROR_TO_TYPEREF.apply(variableElement.asType());
List annotations = new ArrayList();
for (AnnotationMirror annotationMirror : variableElement.getAnnotationMirrors()) {
annotations.add(ANNOTATION_REF.apply(annotationMirror));
}
return new PropertyBuilder()
.withName(name)
.withTypeRef(type)
.withAnnotations(annotations)
.withModifiers(TypeUtils.modifiersToInt(variableElement.getModifiers()))
.build();
}
};
public static final Function METHOD = new Function() {
public Method apply(ExecutableElement executableElement) {
Map attributes = new HashMap<>();
if (executableElement.getDefaultValue() != null) {
attributes.put(Attributeable.DEFAULT_VALUE, executableElement.getDefaultValue().getValue());
}
MethodBuilder methodBuilder = new MethodBuilder()
.withModifiers(TypeUtils.modifiersToInt(executableElement.getModifiers()))
.withName(executableElement.getSimpleName().toString())
.withReturnType(MIRROR_TO_TYPEREF.apply(executableElement.getReturnType()))
.withAttributes(attributes);
//Populate constructor parameters
for (VariableElement variableElement : executableElement.getParameters()) {
methodBuilder = methodBuilder.addToArguments(PROPERTY.apply(variableElement));
List exceptionRefs = new ArrayList();
for (TypeMirror thrownType : executableElement.getThrownTypes()) {
if (thrownType instanceof ClassRef) {
exceptionRefs.add((ClassRef) thrownType);
}
}
methodBuilder = methodBuilder.withExceptions(exceptionRefs);
}
List annotationRefs = new ArrayList();
for (AnnotationMirror annotationMirror : executableElement.getAnnotationMirrors()) {
methodBuilder.withAnnotations(ANNOTATION_REF.apply(annotationMirror));
}
return methodBuilder.build();
}
};
public static final Function INTERNAL_TYPEDEF = new Function() {
public TypeDef apply(TypeElement classElement) {
//Check SuperClass
Kind kind = Kind.CLASS;
TypeMirror superClass = classElement.getSuperclass();
TypeRef superClassType = TypeDef.OBJECT_REF;
if (superClass == null) {
//ignore
} else if (superClass instanceof NoType) {
//ignore
} else if (superClass.toString().equals(TypeDef.OBJECT.getFullyQualifiedName())) {
//ignore
} else {
superClassType = MIRROR_TO_TYPEREF.apply(superClass);
}
List genericTypes = new ArrayList();
List interfaces = new ArrayList();
if (classElement.getKind() == ElementKind.INTERFACE) {
kind = Kind.INTERFACE;
} else if (classElement.getKind() == ElementKind.CLASS) {
kind = Kind.CLASS;
} else if (classElement.getKind() == ElementKind.ANNOTATION_TYPE) {
kind = Kind.ANNOTATION;
}
for (TypeMirror interfaceTypeMirrror : classElement.getInterfaces()) {
TypeRef interfaceType = MIRROR_TO_TYPEREF.apply(interfaceTypeMirrror);
if (interfaceType instanceof ClassRef) {
interfaces.add((ClassRef) interfaceType);
} else {
throw new IllegalStateException("Interface: [" + interfaceType + "] not mapped to a class ref.");
}
}
for (TypeParameterElement typeParameter : classElement.getTypeParameters()) {
List genericBounds = new ArrayList();
if (!typeParameter.getBounds().isEmpty()) {
TypeMirror bound = typeParameter.getBounds().get(0);
if (!OBJECT_BOUND.equals(bound.toString())) {
TypeRef boundRef = MIRROR_TO_TYPEREF.apply(bound);
if (boundRef instanceof ClassRef) {
genericBounds.add((ClassRef) boundRef);
} else {
throw new IllegalStateException("Parameter bound: [" + boundRef + "] not mapped to a class ref.");
}
}
}
TypeParamDef genericType = new TypeParamDefBuilder().withName(typeParameter.getSimpleName().toString())
.withBounds(genericBounds)
.build();
genericTypes.add(genericType);
}
TypeDef baseType = new TypeDefBuilder()
.withKind(kind)
.withModifiers(TypeUtils.modifiersToInt(classElement.getModifiers()))
.withPackageName(getPackageName(classElement))
.withName(getClassName(classElement))
.withParameters(genericTypes)
.withExtendsList(superClassType instanceof ClassRef ? (ClassRef) superClassType : null)
.withImplementsList(interfaces)
.withOuterType(classElement.getEnclosingElement() instanceof TypeElement ? TYPEDEF.apply((TypeElement) classElement.getEnclosingElement()) : null)
.build();
List innerTypes = new ArrayList();
for (TypeElement innerElement : ElementFilter.typesIn(classElement.getEnclosedElements())) {
TypeDef innerType = TYPEDEF.apply(innerElement);
innerType = new TypeDefBuilder(innerType).withOuterType(baseType).build();
DefinitionRepository.getRepository().register(innerType);
innerTypes.add(innerType);
}
TypeDefBuilder builder = new TypeDefBuilder(baseType)
.withInnerTypes(innerTypes);
for (ExecutableElement constructor : ElementFilter.constructorsIn(classElement.getEnclosedElements())) {
builder.addToConstructors(METHOD.apply(constructor));
}
//Populate Fields
for (VariableElement variableElement : ElementFilter.fieldsIn(classElement.getEnclosedElements())) {
builder.addToProperties(PROPERTY.apply(variableElement));
}
Set allMethods = new LinkedHashSet();
allMethods.addAll(ElementFilter.methodsIn(classElement.getEnclosedElements()));
allMethods.addAll(getInheritedMethods(classElement));
for (ExecutableElement method : allMethods) {
builder.addToMethods(METHOD.apply(method));
}
for (AnnotationMirror annotationMirror : classElement.getAnnotationMirrors()) {
builder.addToAnnotations(ANNOTATION_REF.apply(annotationMirror));
}
return DefinitionRepository.getRepository().register(builder.build());
}
public Set getInheritedMethods(TypeElement typeElement) {
Set result = new LinkedHashSet();
if (typeElement != null) {
for (ExecutableElement method : ElementFilter.methodsIn(typeElement.getEnclosedElements())) {
if (!method.getModifiers().contains(Modifier.PRIVATE)) {
result.add(method);
}
}
result.addAll(getInheritedMethods(typeElement.getSuperclass() != null ?
CodegenContext.getContext().getElements().getTypeElement(typeElement.getSuperclass().toString()) : null));
}
return result;
}
};
public static final Function SHALLOW_TYPEDEF = new Function() {
public TypeDef apply(TypeElement classElement) {
List extendsList = new ArrayList();
//Check SuperClass
Kind kind = Kind.CLASS;
if (classElement.getKind() == ElementKind.INTERFACE) {
kind = Kind.INTERFACE;
} else if (classElement.getKind() == ElementKind.CLASS) {
kind = Kind.CLASS;
extendsList.add(TypeDef.OBJECT_REF);
} else if (classElement.getKind() == ElementKind.ANNOTATION_TYPE) {
kind = Kind.ANNOTATION;
}
Set allMethods = new LinkedHashSet();
for (ExecutableElement method : ElementFilter.methodsIn(classElement.getEnclosedElements())) {
}
return new TypeDefBuilder()
.withKind(kind)
.withModifiers(TypeUtils.modifiersToInt(classElement.getModifiers()))
.withPackageName(getPackageName(classElement))
.withName(getClassName(classElement))
.withExtendsList(extendsList)
.addAllToMethods(allMethods)
.withOuterType(classElement.getEnclosingElement() instanceof TypeElement ? SHALLOW_TYPEDEF.apply((TypeElement) classElement.getEnclosingElement()) : null)
.build();
}
};
public static final Function TYPEDEF = FunctionFactory.cache(INTERNAL_TYPEDEF)
.withFallback(SHALLOW_TYPEDEF)
.withFallbackPredicate(IS_JAVA_ELEMENT)
.withMaximumRecursionLevel(10)
.withMaximumNestingDepth(10);
private static Function ANNOTATION_REF = FunctionFactory.cache(new Function() {
@Override
public AnnotationRef apply(AnnotationMirror item) {
TypeRef annotationType = item.getAnnotationType().accept(new TypeRefTypeVisitor(), 0);
Map parameters = new HashMap();
if (annotationType instanceof ClassRef) {
for (Map.Entry extends ExecutableElement, ? extends AnnotationValue> entry
: item.getElementValues().entrySet()) {
String key = entry.getKey().toString().replace(EMPTY_PARENTHESIS, EMPTY);
Object value = mapAnnotationValue(entry.getValue().getValue());
parameters.put(key, value);
}
return new AnnotationRefBuilder()
.withClassRef((ClassRef) annotationType)
.withParameters(parameters)
.build();
}
throw new IllegalStateException("Annotation type: ["+annotationType+"] is not a class reference.");
}
});
private static Object mapAnnotationValue(Object value) {
if (value instanceof Collection) {
return ((Collection)value).stream()
.map(ElementTo::mapAnnotationValue)
.collect(Collectors.toList());
} else if (value instanceof AnnotationMirror) {
return ANNOTATION_REF.apply((AnnotationMirror) value);
} else if (value instanceof AnnotationValue){
return ((AnnotationValue) value).getValue();
} else if (value instanceof TypeMirror) {
return MIRROR_TO_TYPEREF.apply((TypeMirror) value);
}
else {
return value;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy