Package com.avast.syringe.config.perspective

Source Code of com.avast.syringe.config.perspective.ModuleDescriptor$ClassDescriptor$PropertyDescriptor

package com.avast.syringe.config.perspective;

import com.avast.syringe.*;
import com.avast.syringe.config.ConfigBean;
import com.avast.syringe.config.internal.ConfigClassAnalyzer;
import com.avast.syringe.config.internal.InjectableProperty;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;

import java.io.Writer;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* <pre>
*  {
*      package
*      moduleDesc
*      moduleName
*      moduleTraits
*      classDescriptors: [{
*          name
*          simpleName
*          builderMethodName
*          builderTraits
*          propertyDescriptors: [{
*              name
*              type
*          }]
*      }]
* </pre>
* <p/>
* User: slajchrt
* Date: 6/4/12
* Time: 5:28 PM
*/
public class ModuleGenerator {

    public class ModuleDescriptor {

        public class ClassDescriptor {

            public class PropertyDescriptor {

                public class Argument {
                    private String name;
                    private String type;

                    public Argument(String name, String type) {
                        this.name = name;
                        this.type = type;
                    }

                    public String getName() {
                        return name;
                    }

                    public String getType() {
                        return type;
                    }
                }

                final String name;
                final String setterName;
                final List<Argument> arguments;

                public PropertyDescriptor(InjectableProperty prop) {
                    if (prop.isCollection() || prop.isArray()) {
                        setterName = "addTo" + makeFirstUpperCase(prop.getName());
                        arguments = Collections.singletonList(
                                new Argument("value", convertToScalaType(prop.getArrayOrCollectionComponentType())));
                    } else if (prop.isMap()) {
                        setterName = "putTo" + makeFirstUpperCase(prop.getName());
                        arguments = Arrays.asList(
                                new Argument("key", convertToScalaType(prop.getMapKeyType())),
                                new Argument("value", convertToScalaType(prop.getMapValueType()))
                        );
                    } else {
                        setterName = prop.getName();
                        arguments = Collections.singletonList(new Argument("value", convertToScalaType(prop.getType())));
                    }
                    this.name = prop.getName();
                }

                public String getName() {
                    return name;
                }

                public String getSetterName() {
                    return setterName;
                }

                public List<Argument> getArguments() {
                    return arguments;
                }
            }

            final String name;
            final String simpleName;
            final String builderMethodName;
            final String singletonBuilderMethodName;
            final List<PropertyDescriptor> propertyDescriptors;
            final List<String> genericParameters = Lists.newArrayList();
            final boolean generic;
            final Set<String> builderTraits = Sets.newLinkedHashSet();

            private final boolean provider;

            final String typeName;
            final List<String> typeGenericParameters = Lists.newArrayList();
            final boolean typeGeneric;

            public ClassDescriptor(Class<?> cls, Properties builderTraitMappings) {
                provider = com.avast.syringe.Provider.class.isAssignableFrom(cls);
                Type typeType = provider ? findProviderParameter(cls) : cls;
                Class typeCls = getClassForType(typeType);

                if (provider) {
                    name = cls.getName();
                    typeName = typeCls.getName();
                } else {
                    name = typeName = cls.getName();
                }

                ConfigBean cfgBeanAnnot = cls.getAnnotation(ConfigBean.class);
                if (cfgBeanAnnot != null && !"".equals(cfgBeanAnnot.value())) {
                    simpleName = cfgBeanAnnot.value();
                } else {
                    simpleName = cls.getSimpleName();
                }

                builderMethodName = "new" + simpleName;
                singletonBuilderMethodName = makeFirstLowerCase(simpleName);

                propertyDescriptors = Lists.transform(new ConfigClassAnalyzer(cls).getConfigProperties(),
                        new Function<InjectableProperty, PropertyDescriptor>() {
                            @Override
                            public PropertyDescriptor apply(InjectableProperty prop) {
                                return new PropertyDescriptor(prop);
                            }
                        });

                TypeVariable[] clsParameters = cls.getTypeParameters();
                generic = clsParameters.length > 0;

                for (TypeVariable clsParameter : clsParameters) {
                    genericParameters.add(constructGenericScalaPlaceholder(clsParameter));
                }

                if (provider) {
                    TypeVariable[] typeParameters = typeCls.getTypeParameters();
                    typeGeneric = typeParameters.length > 0;

                    for (TypeVariable typeParameter : typeParameters) {
                        typeGenericParameters.add(constructGenericScalaPlaceholder(typeParameter));
                    }

                } else {
                    typeGeneric = generic;
                    typeGenericParameters.addAll(genericParameters);
                }

                if (builderTraitMappings != null) {
                    for (Map.Entry<Object, Object> builderTraitMapping : builderTraitMappings.entrySet()) {
                        String productClassNamePatternSource = builderTraitMapping.getKey().toString();
                        Pattern productClassNamePattern = Pattern.compile(productClassNamePatternSource);
                        Matcher matcher = productClassNamePattern.matcher(cls.getName());
                        if (matcher.matches()) {
                            String builderTraitsSource = builderTraitMapping.getValue().toString();
                            Iterable<String> splitTraits = Splitter.on("\n").trimResults().split(builderTraitsSource);
                            for (String splitTrait : splitTraits) {
                                builderTraits.add(splitTrait);
                            }

                        }
                    }
                }
            }

            public String getName() {
                return name;
            }

            public String getSimpleName() {
                return simpleName;
            }

            public String getBuilderMethodName() {
                return builderMethodName;
            }

            public String getSingletonBuilderMethodName() {
                return singletonBuilderMethodName;
            }

            public List<PropertyDescriptor> getPropertyDescriptors() {
                return propertyDescriptors;
            }

            public List<String> getGenericParameters() {
                return genericParameters;
            }

            public boolean isProvider() {
                return provider;
            }

            public boolean isGeneric() {
                return generic;
            }

            public Set<String> getBuilderTraits() {
                return builderTraits;
            }

            public String getTypeName() {
                return typeName;
            }

            public List<String> getTypeGenericParameters() {
                return typeGenericParameters;
            }

            public boolean isTypeGeneric() {
                return typeGeneric;
            }
        }

        final String pkg;
        final String moduleDesc;
        final String moduleName;
        final List<ClassDescriptor> classDescriptors;
        final List<String> moduleTraits;

        public ModuleDescriptor(String pkg, String moduleDesc, String moduleName, List<Class> classes,
                                List<String> moduleTraits, final Properties builderTraitMappings) {
            this.pkg = pkg;
            this.moduleDesc = moduleDesc;
            this.moduleName = moduleName;
            this.moduleTraits = moduleTraits == null ? Collections.<String>emptyList() : moduleTraits;

            ImmutableList<Class> nonAbstractClasses = ImmutableList.copyOf(Iterables.filter(classes, new Predicate<Class>() {
                @Override
                public boolean apply(Class cls) {
                    return !Modifier.isAbstract(cls.getModifiers());
                }
            }));

            this.classDescriptors = Lists.transform(nonAbstractClasses, new Function<Class, ClassDescriptor>() {
                @Override
                public ClassDescriptor apply(Class cls) {
                    return new ClassDescriptor(cls, builderTraitMappings);
                }
            });
        }

        public String getPkg() {
            return pkg;
        }

        public String getModuleDesc() {
            return moduleDesc;
        }

        public String getModuleName() {
            return moduleName;
        }

        public List<ClassDescriptor> getClassDescriptors() {
            return classDescriptors;
        }

        public List<String> getModuleTraits() {
            return moduleTraits;
        }
    }

    private static final ModuleGenerator INSTANCE = new ModuleGenerator();

    private final Configuration fmCfg;

    private ModuleGenerator() {
        fmCfg = new Configuration();
        fmCfg.setClassForTemplateLoading(ModuleGenerator.class, "");
        fmCfg.setObjectWrapper(new DefaultObjectWrapper());
        fmCfg.setTemplateLoader(new OsSpecificTemplateLoader(fmCfg.getTemplateLoader()));
    }

    public static ModuleGenerator getInstance() {
        return INSTANCE;
    }

    public void generate(String pkg, String moduleDesc, String module, List<Class> classes, List<String> moduleTraits,
                         Properties builderTraitMappings, Writer writer)
            throws Exception {
        Template template = fmCfg.getTemplate("module-template.ftl");
        ModuleDescriptor model = new ModuleDescriptor(pkg, moduleDesc, module, classes, moduleTraits,
                builderTraitMappings);
        template.process(model, writer);
        writer.flush();
    }

    private static String convertToScalaType(Class type) {
        final String typeName = type.getName();

        if ("byte".equals(typeName) || Byte.class.getName().equals(typeName)) {
            return "Byte";
        }
        if ("short".equals(typeName) || Short.class.getName().equals(typeName)) {
            return "Short";
        }
        if ("int".equals(typeName) || Integer.class.getName().equals(typeName)) {
            return "Int";
        }
        if ("long".equals(typeName) || Long.class.getName().equals(typeName)) {
            return "Long";
        }
        if ("float".equals(typeName) || Float.class.getName().equals(typeName)) {
            return "Float";
        }
        if ("double".equals(typeName) || Double.class.getName().equals(typeName)) {
            return "Double";
        }
        if ("char".equals(typeName) || Character.class.getName().equals(typeName)) {
            return "Char";
        }
        if ("boolean".equals(typeName) || Boolean.class.getName().equals(typeName)) {
            return "Boolean";
        }
        if (String.class.getName().equals(typeName)) {
            return "String";
        }

        //return SyringeModule.SyringeBuilder.class.getSimpleName() + "[" +
        return Builder.class.getSimpleName() + "[" +
                constructGenericScalaTypeName(type) + "]";
    }

    private static String constructGenericScalaTypeName(Class type) {
        // TODO:
        return "_";
    }

    private static String constructGenericScalaPlaceholder(TypeVariable typeParameter) {
        // TODO:
        return "_";
    }

    private static String makeFirstUpperCase(String name) {
        return Character.toUpperCase(name.charAt(0)) + name.substring(1);
    }

    private static String makeFirstLowerCase(String name) {
        return Character.toLowerCase(name.charAt(0)) + name.substring(1);
    }

    static Class getClassForType(Type t) {
        if (t instanceof Class) {
            return (Class) t;
        } if (t instanceof ParameterizedType) {
            Type rawType = ((ParameterizedType) t).getRawType();
            if (rawType instanceof Class) {
                return (Class) rawType;
            } else {
                throw new IllegalArgumentException("Unsupported type " + t);
            }
        } else {
            throw new IllegalArgumentException("Unsupported type " + t);
        }
    }

    static Type findProviderParameter(Class<?> cls) {
        Type[] genericInterfaces = cls.getGenericInterfaces();
        for (Type genericInterface : genericInterfaces) {
            if (genericInterface instanceof ParameterizedType &&
                    ((ParameterizedType) genericInterface).getRawType() instanceof Class &&
                    com.avast.syringe.Provider.class.isAssignableFrom((Class)((ParameterizedType) genericInterface).getRawType())) {

                if (((ParameterizedType) genericInterface).getRawType() == com.avast.syringe.Provider.class) {
                    Type providerParamType = ((ParameterizedType) genericInterface).getActualTypeArguments()[0];
                    if (providerParamType instanceof Class) {
                        return providerParamType;
                    } if (providerParamType instanceof ParameterizedType) {
                        return providerParamType;
                    } else {
                        throw new IllegalArgumentException("Provider class " + cls + " must specify the product type");
                    }
                } else {
                    return findProviderParameter((Class)((ParameterizedType) genericInterface).getRawType());
                }

            }
        }

        if (cls == Object.class || cls.getSuperclass() == Object.class) {
            throw new IllegalArgumentException("Provider class " + cls + " must specify the product type");
        }

        try {
            return findProviderParameter(cls.getSuperclass());
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException("Provider class " + cls + " must specify the product type\n", e);
        }
    }


}
TOP

Related Classes of com.avast.syringe.config.perspective.ModuleDescriptor$ClassDescriptor$PropertyDescriptor

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.