All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.sundr.codegen.functions.ClassTo Maven / Gradle / Ivy

There is a newer version: 1.14.0
Show newest version
/*
 * 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.DefinitionRepository;
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.PrimitiveRefBuilder;
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.TypeParamRefBuilder;
import io.sundr.codegen.model.TypeRef;
import io.sundr.codegen.model.VoidRefBuilder;
import io.sundr.codegen.model.WildcardRefBuilder;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

public class ClassTo {

    private static final String ARGUMENT_PREFIX = "arg";

    public static final Function KIND = FunctionFactory.cache(new Function() {
        public Kind apply(Class item) {
            if (item.isAnnotation()) {
                return Kind.ANNOTATION;
            } else if (item.isEnum()) {
                return Kind.ENUM;
            } else if (item.isInterface()) {
                return Kind.INTERFACE;
            } else {
                return Kind.CLASS;
            }
        }
    });

    public static final Function TYPEREF = FunctionFactory.cache(new Function() {
        public TypeRef apply(Type item) {
            if (item == null) {
                return new VoidRefBuilder().build();
            } else if (item instanceof WildcardType) {
                return new WildcardRefBuilder().withBounds(Arrays.asList(((WildcardType) item).getLowerBounds()).stream().map(t->TYPEREF.apply(t)).collect(Collectors.toList())).build();
            } else if (item instanceof TypeVariable) {
                return new TypeParamRefBuilder().withName(((TypeVariable) item).getName()).build();
            } else if (item instanceof GenericArrayType) {
                Type target = item;
                int dimensions = 0;
                while (target instanceof GenericArrayType) {
                    target = ((GenericArrayType) target).getGenericComponentType();
                    dimensions++;
                }
                TypeRef targetRef = TYPEREF.apply(target);
                return targetRef.withDimensions(dimensions + targetRef.getDimensions());

            } else if (item instanceof ParameterizedType) {
                ParameterizedType parameterizedType = (ParameterizedType) item;
                Type rawType = parameterizedType.getRawType();
                List arguments = new ArrayList();
                for (Type arg : parameterizedType.getActualTypeArguments()) {
                    arguments.add(TYPEREF.apply(arg));
                }
                return new ClassRefBuilder((ClassRef) TYPEREF.apply(rawType))
                        .withArguments(arguments)
                        .build();
            } else if (Object.class.equals(item)) {
                return ClassRef.OBJECT;
            } else if (item instanceof Class) {
                Class c = (Class) item;
                if (c.isPrimitive()) {
                    return new PrimitiveRefBuilder().withName(c.getName()).build();
                } else {
                    List arguments = new ArrayList();
                    for (TypeVariable v : c.getTypeParameters()) {
                        arguments.add(TYPEREF.apply(v));
                    }
                    return new ClassRefBuilder()
                            .withDefinition(TYPEDEF.apply(c))
                            .withArguments(arguments)
                            .build();
                }
            }
            throw new IllegalArgumentException("Can't convert type:"+item+" to a TypeRef");
        }
    });

    public static final Function, AnnotationRef> ANNOTATIONTYPEREF = FunctionFactory.cache(new Function, AnnotationRef>() {

        @Override
        public AnnotationRef apply(Class item) {
            //An annotation can't be a primitive or a void type, so its safe to cast.
            ClassRef classRef = (ClassRef) TYPEREF.apply(item);
            Map parameters;

            return new AnnotationRefBuilder().withClassRef(classRef).build();
        }
    });


    private static final Function INTERNAL_TYPEDEF = new Function() {
        public TypeDef apply(Class item) {

            if (Object.class.equals(item)) {
                return TypeDef.OBJECT;
            }
            Kind kind = KIND.apply(item);
            List extendsList = new ArrayList();
            List implementsList = new ArrayList();
            List properties = new ArrayList();
            List methods = new ArrayList();
            List constructors = new ArrayList();
            List parameters = new ArrayList();

            if (item.getSuperclass() != null && kind == Kind.INTERFACE) {
                extendsList.add((ClassRef) TYPEREF.apply(item.getSuperclass()));
            }

            constructors.addAll(getConstructors(item));
            methods.addAll(getMethods(item));
            properties.addAll(getProperties(item));

            for (Class interfaceClass : item.getInterfaces()) {
                TypeRef ref = TYPEREF.apply(interfaceClass);
                if (ref instanceof ClassRef) {
                    implementsList.add((ClassRef) ref);
                }
            }

            for (TypeVariable typeVariable : item.getTypeParameters()) {
                List bounds = new ArrayList();
                for (Type boundType : typeVariable.getBounds()) {
                    TypeRef typeRef = TYPEREF.apply(boundType);
                    if (typeRef instanceof ClassRef) {
                        bounds.add((ClassRef)typeRef);
                    }
                }
                parameters.add(new TypeParamDefBuilder()
                        .withName(typeVariable.getName())
                        .withBounds(bounds)
                        .build());
            }

            return DefinitionRepository.getRepository().register(new TypeDefBuilder()
                    .withKind(kind)
                    .withName(item.getSimpleName())
                    .withPackageName(item.getPackage() != null ? item.getPackage().getName() : null)
                    .withModifiers(item.getModifiers())
                    .withParameters(parameters)
                    .withConstructors(constructors)
                    .withMethods(methods)
                    .withProperties(properties)
                    .withExtendsList(extendsList)
                    .withImplementsList(implementsList)
                    .build());
        }
    };

    private static final Function INTERNAL_SHALLOW_TYPEDEF = new Function() {

        public TypeDef apply(Class item) {
            if (Object.class.equals(item)) {
                return TypeDef.OBJECT;
            }
            Kind kind = KIND.apply(item);

            return new TypeDefBuilder()
                    .withKind(kind)
                    .withName(item.getSimpleName())
                    .withPackageName(item.getPackage() != null ? item.getPackage().getName() : null)
                    .withModifiers(item.getModifiers())
                    .withParameters()
                    .build();
        }
    };

    public static final Function TYPEDEF = FunctionFactory.cache(INTERNAL_TYPEDEF).withFallback(INTERNAL_SHALLOW_TYPEDEF).withMaximumRecursionLevel(5).withMaximumNestingDepth(5);

    private static Function TYPEPARAMDEF = FunctionFactory.cache(new Function() {

        public TypeParamDef apply(Type item) {
            if (item instanceof TypeVariable) {
                TypeVariable typeVariable = (TypeVariable) item;
                String name = typeVariable.getName();
                List bounds = new ArrayList();

                for (Type b : typeVariable.getBounds()) {
                    if (b instanceof Class) {
                        Class c = (Class) b;
                        bounds.add((ClassRef) TYPEREF.apply(c));
                    }
                }
                return new TypeParamDefBuilder().withName(name).withBounds(bounds).build();
            }
            return null;
        }
    });

    private static Set getProperties(Class item) {
        Set properties = new HashSet();
        for (Field field : item.getDeclaredFields()) {
            List annotationRefs = new ArrayList();
            for (Annotation annotation : field.getDeclaredAnnotations()) {
                annotationRefs.add(ANNOTATIONTYPEREF.apply(annotation.annotationType()));
            }
            field.getDeclaringClass();
            properties.add(new PropertyBuilder()
                    .withName(field.getName())
                    .withModifiers(field.getModifiers())
                    .withAnnotations(annotationRefs)
                    .withTypeRef(TYPEREF.apply(field.getGenericType()))
                    .build());
        }
        return properties;
    }

    private static Set getConstructors(Class item) {
        Set constructors = new HashSet();
        for (java.lang.reflect.Constructor constructor : item.getDeclaredConstructors()) {
            List annotationRefs = new ArrayList();
            for (Annotation annotation : constructor.getDeclaredAnnotations()) {
                annotationRefs.add(ANNOTATIONTYPEREF.apply(annotation.annotationType()));
            }

            List arguments = new ArrayList();
            for (int i = 1; i <= constructor.getGenericParameterTypes().length; i++) {
                Type argumentType = constructor.getGenericParameterTypes()[i - 1];
                arguments.add(new PropertyBuilder()
                        .withName(ARGUMENT_PREFIX + i)
                        .withTypeRef(TYPEREF.apply(argumentType))
                        .build());
            }

            List parameters = new ArrayList();
            for (Type type : constructor.getGenericParameterTypes()) {

                TypeParamDef typeParamDef = TYPEPARAMDEF.apply(type);
                if (typeParamDef != null) {
                    parameters.add(typeParamDef);
                }
            }

            constructors.add(new MethodBuilder()
                    .withName(constructor.getName())
                    .withModifiers(constructor.getModifiers())
                    .withArguments(arguments)
                    .withParameters(parameters)
                    .withAnnotations(annotationRefs)
                    .build());
        }
        return constructors;
    }

    private static Set getMethods(Class item) {
        Set methods = new HashSet();
        for (java.lang.reflect.Method method : item.getDeclaredMethods()) {
            List annotationRefs = new ArrayList();
            for (Annotation annotation : method.getDeclaredAnnotations()) {
                annotationRefs.add(ANNOTATIONTYPEREF.apply(annotation.annotationType()));
            }

            List arguments = new ArrayList();
            for (int i = 1; i <= method.getGenericParameterTypes().length; i++) {
                Type argumentType = method.getGenericParameterTypes()[i - 1];
                arguments.add(new PropertyBuilder()
                        .withName(ARGUMENT_PREFIX + i)
                        .withTypeRef(TYPEREF.apply(argumentType))
                        .build());
            }

            List parameters = new ArrayList();
            for (Type type : method.getGenericParameterTypes()) {

                TypeParamDef typeParamDef = TYPEPARAMDEF.apply(type);
                if (typeParamDef != null) {
                    parameters.add(typeParamDef);
                }
            }
             Map attributes = new HashMap<>();
             if (method.getDefaultValue() != null) {
                attributes.put(Attributeable.DEFAULT_VALUE, method.getDefaultValue());
             }

            methods.add(new MethodBuilder()
                    .withName(method.getName())
                    .withModifiers(method.getModifiers())
                    .withReturnType(TYPEREF.apply(method.getReturnType()))
                    .withArguments(arguments)
                    .withParameters(parameters)
                    .withAnnotations(annotationRefs)
                    .withAttributes(attributes)
                    .build());
        }
        return methods;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy