Search in sources :

Example 1 with Types

use of io.sundr.model.utils.Types in project sundrio by sundrio.

the class BuilderUtils method getInlineableConstructors.

public static Set<Method> getInlineableConstructors(Property property) {
    Set<Method> result = new HashSet<Method>();
    TypeRef typeRef = property.getTypeRef();
    TypeRef unwrapped = TypeAs.combine(TypeAs.UNWRAP_COLLECTION_OF, TypeAs.UNWRAP_ARRAY_OF, TypeAs.UNWRAP_OPTIONAL_OF).apply(typeRef);
    if (unwrapped instanceof ClassRef) {
        ClassRef classRef = (ClassRef) unwrapped;
        // We need to handle `new String(String str)` as a special case of Inlineable constructor and deprecate Inlineables of it before we acutally remove it, so here goes...
        if (STRING_REF.equals(typeRef)) {
            result.add(new MethodBuilder().withName("String").addNewArgument().withName("s").withTypeRef(classRef).endArgument().build());
            return result;
        }
        // We only want to inline non java types
        String pkg = Nameable.getPackageName(((ClassRef) unwrapped).getFullyQualifiedName());
        if (!Stream.of(NON_INLINABLE_PACKAGES).filter(s -> pkg.startsWith(s)).findAny().isPresent()) {
            for (Method candidate : GetDefinition.of((ClassRef) unwrapped).getConstructors()) {
                if (isInlineable(candidate)) {
                    result.add(candidate);
                }
            }
        }
    }
    return result;
}
Also used : INIT(io.sundr.model.Attributeable.INIT) Arrays(java.util.Arrays) TypeParamDefBuilder(io.sundr.model.TypeParamDefBuilder) Descendants(io.sundr.builder.internal.functions.Descendants) Optionals(io.sundr.model.utils.Optionals) TypeElement(javax.lang.model.element.TypeElement) Attributeable(io.sundr.model.Attributeable) Nameable(io.sundr.model.Nameable) ClassRef(io.sundr.model.ClassRef) Getter(io.sundr.model.utils.Getter) STRING_REF(io.sundr.model.utils.Types.STRING_REF) Map(java.util.Map) MirroredTypeException(javax.lang.model.type.MirroredTypeException) BuildableRepository(io.sundr.builder.internal.BuildableRepository) Path(java.nio.file.Path) Collections(io.sundr.model.utils.Collections) BuilderContext(io.sundr.builder.internal.BuilderContext) DefinitionRepository(io.sundr.model.repo.DefinitionRepository) Collection(java.util.Collection) Set(java.util.Set) Element(javax.lang.model.element.Element) Method(io.sundr.model.Method) Construct(io.sundr.builder.internal.functions.Construct) Collectors(java.util.stream.Collectors) io.sundr.builder.annotations(io.sundr.builder.annotations) ALSO_IMPORT(io.sundr.model.Attributeable.ALSO_IMPORT) List(java.util.List) ClassRefBuilder(io.sundr.model.ClassRefBuilder) Stream(java.util.stream.Stream) MethodBuilder(io.sundr.model.MethodBuilder) BuilderContextManager(io.sundr.builder.internal.BuilderContextManager) TypeParamDef(io.sundr.model.TypeParamDef) Strings.capitalizeFirst(io.sundr.utils.Strings.capitalizeFirst) StringStatement(io.sundr.model.StringStatement) TypeParamRef(io.sundr.model.TypeParamRef) GetDefinition(io.sundr.model.functions.GetDefinition) TypeDefBuilder(io.sundr.model.TypeDefBuilder) AdapterContext(io.sundr.adapter.api.AdapterContext) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) INIT_FUNCTION(io.sundr.model.Attributeable.INIT_FUNCTION) Assignable(io.sundr.model.functions.Assignable) Types(io.sundr.model.utils.Types) LinkedHashSet(java.util.LinkedHashSet) Constants(io.sundr.builder.Constants) AptContext(io.sundr.adapter.apt.AptContext) TypedVisitor(io.sundr.builder.TypedVisitor) Adapters(io.sundr.adapter.api.Adapters) LAZY_INIT(io.sundr.model.Attributeable.LAZY_INIT) TypeRef(io.sundr.model.TypeRef) Types.isAbstract(io.sundr.model.utils.Types.isAbstract) AnnotationRef(io.sundr.model.AnnotationRef) Kind(io.sundr.model.Kind) Property(io.sundr.model.Property) File(java.io.File) LAZY_COLLECTIONS_INIT_ENABLED(io.sundr.builder.Constants.LAZY_COLLECTIONS_INIT_ENABLED) Statement(io.sundr.model.Statement) TypeDef(io.sundr.model.TypeDef) DEFAULT_VALUE(io.sundr.model.Attributeable.DEFAULT_VALUE) PropertyBuilder(io.sundr.model.PropertyBuilder) TypeAs(io.sundr.builder.internal.functions.TypeAs) DESCENDANTS(io.sundr.builder.Constants.DESCENDANTS) ClassRef(io.sundr.model.ClassRef) TypeRef(io.sundr.model.TypeRef) Method(io.sundr.model.Method) MethodBuilder(io.sundr.model.MethodBuilder) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet)

Example 2 with Types

use of io.sundr.model.utils.Types in project sundrio by sundrio.

the class ToPojo method apply.

public TypeDef apply(RichTypeDef item) {
    List<Property> arguments = new CopyOnWriteArrayList<>();
    List<Property> fields = new CopyOnWriteArrayList<>();
    Map<String, Property> superClassFields = new HashMap<>();
    List<Method> getters = new CopyOnWriteArrayList<>();
    List<Method> additionalMethods = new ArrayList<>();
    List<Property> constructorArgs = new ArrayList<>();
    List<TypeDef> types = new ArrayList<TypeDef>();
    Types.visitParents(item, types);
    TypeDef superClass = null;
    Set<ClassRef> extendsList = new HashSet<>();
    Set<ClassRef> implementsList = new HashSet<>();
    List<ClassRef> additionalImports = new ArrayList<>();
    List<AnnotationRef> annotationRefs = new ArrayList<>();
    String pojoName = Strings.toPojoName(item.getName(), "Default", "");
    String relativePath = ".";
    AnnotationRef pojoRef = null;
    boolean enableStaticBuilder = true;
    boolean enableStaticAdapter = true;
    boolean enableStaticMapAdapter = false;
    boolean autobox = false;
    boolean initialize = false;
    boolean mutable = false;
    final List adapters = new ArrayList();
    for (AnnotationRef r : item.getAnnotations()) {
        if (r.getClassRef() != null) {
            if (r.getClassRef().getFullyQualifiedName().equals(Buildable.class.getTypeName())) {
                if (!annotationRefs.contains(r)) {
                    annotationRefs.add(r);
                }
            }
            if (r.getClassRef().getFullyQualifiedName().equals(Pojo.class.getTypeName())) {
                pojoRef = r;
                Map<String, Object> params = r.getParameters();
                if (params.containsKey("mutable")) {
                    mutable = Boolean.parseBoolean(String.valueOf(r.getParameters().getOrDefault("mutable", false)));
                }
                if (params.containsKey("autobox")) {
                    autobox = Boolean.parseBoolean(String.valueOf(r.getParameters().getOrDefault("autobox", false)));
                }
                if (params.containsKey("initialize")) {
                    initialize = Boolean.parseBoolean(String.valueOf(r.getParameters().getOrDefault("initialize", false)));
                }
                if (params.containsKey("name")) {
                    pojoName = String.valueOf(r.getParameters().getOrDefault("name", pojoName));
                } else if (params.containsKey("prefix") || params.containsKey("suffix")) {
                    String prefix = String.valueOf(r.getParameters().getOrDefault("prefix", ""));
                    String suffix = String.valueOf(r.getParameters().getOrDefault("suffix", ""));
                    pojoName = Strings.toPojoName(item.getName(), prefix, suffix);
                } else if (params.containsKey("relativePath")) {
                    // When the package is different and there is no name clash, just use the same name unless explicitly specified.
                    pojoName = item.getName();
                }
                if (params.containsKey("adapter")) {
                    Object adapter = params.get("adapter");
                    if (adapter != null && adapter.getClass().isArray()) {
                        int length = Array.getLength(adapter);
                        for (int i = 0; i < length; i++) {
                            adapters.add(Array.get(adapter, i));
                        }
                    }
                }
                String superClassName = Types.toClassName(r.getParameters().getOrDefault("superClass", ""));
                if (!superClassName.isEmpty()) {
                    superClassName = superClassName.replaceAll("\\.class$", "");
                    superClass = DefinitionRepository.getRepository().getDefinition(superClassName);
                    if (superClass == null) {
                        BuilderContext context = BuilderContextManager.getContext();
                        AptContext aptContext = AptContext.create(context.getElements(), context.getTypes(), context.getDefinitionRepository());
                        superClass = new TypeDefBuilder(Adapters.adaptType(aptContext.getElements().getTypeElement(superClassName), aptContext.getAdapterContext())).build();
                        BuilderContextManager.getContext().getDefinitionRepository().register(superClass);
                        BuilderContextManager.getContext().getBuildableRepository().register(superClass);
                    }
                    if (superClass != null) {
                        ClassRef superClassRef = superClass.toInternalReference();
                        extendsList.add(superClassRef);
                        BuilderContextManager.getContext().getBuildableRepository().register(GetDefinition.of(superClassRef));
                        BuilderUtils.findBuildableReferences(superClassRef).stream().forEach(b -> BuilderContextManager.getContext().getBuildableRepository().register(GetDefinition.of(b)));
                    }
                }
                if (item.isInterface()) {
                    implementsList.add(item.toInternalReference());
                }
                Arrays.asList(r.getParameters().getOrDefault("interfaces", new Object[] {})).stream().map(String::valueOf).map(s -> s.replaceAll("\\.class$", "")).map(n -> DefinitionRepository.getRepository().getDefinition(n)).filter(d -> d != null).map(d -> d.toInternalReference()).forEach(ref -> implementsList.add(ref));
                if (params.containsKey("relativePath")) {
                    relativePath = String.valueOf(r.getParameters().getOrDefault("relativePath", "."));
                }
                enableStaticBuilder = !"false".equals(String.valueOf(params.get("withStaticBuilderMethod")));
                enableStaticAdapter = !"false".equals(String.valueOf(params.get("withStaticAdapterMethod")));
                enableStaticMapAdapter = !"false".equals(String.valueOf(params.get("withStaticMapAdapterMethod")));
            }
        }
    }
    Set<TypeDef> additionalBuildables = new HashSet<>();
    Set<TypeDef> additionalTypes = new HashSet<>();
    boolean shouldBeAbstract = false;
    for (TypeDef t : types) {
        if (superClass != null) {
            Method constructor = findBuildableConstructor(superClass);
            if (constructor != null) {
                for (Property p : constructor.getArguments()) {
                    String name = Strings.toFieldName(p.getName());
                    superClassFields.put(p.getName(), p);
                }
            }
        }
        if (t.isInterface() && !Annotation.class.getName().equals(t.getFullyQualifiedName())) {
            implementsList.add(t.toInternalReference());
        }
        for (Method method : t.getMethods()) {
            // Ignore static methods and methods with arguments.
            if (method.isStatic() || !method.getArguments().isEmpty()) {
                continue;
            }
            // We need all getters and all annotation methods.
            boolean isAnnotation = t.isAnnotation() && t.equals(item);
            if (Getter.is(method) || isAnnotation) {
                String name = isAnnotation ? method.getName() : Getter.propertyName(method);
                TypeRef returnType = method.getReturnType();
                if (autobox) {
                    returnType = Types.box(returnType);
                }
                // If return type is an annotation also convert the annotation.
                if (method.getReturnType() instanceof ClassRef) {
                    ClassRef ref = (ClassRef) method.getReturnType();
                    if (GetDefinition.of(ref).isAnnotation()) {
                        AnnotationRef inheritedPojoRef = (pojoRef != null ? new AnnotationRefBuilder(pojoRef) : new AnnotationRefBuilder()).removeFromParameters("name").removeFromParameters("superClass").removeFromParameters("interfaces").build();
                        TypeDef p = hasPojoAnnotation(GetDefinition.of(ref)) ? POJO.apply(TypeArguments.apply(GetDefinition.of(ref))) : POJO.apply(TypeArguments.apply(new TypeDefBuilder(GetDefinition.of(ref)).withAnnotations(annotationRefs).addToAnnotations(inheritedPojoRef).withAttributes(item.getAttributes()).build()));
                        additionalBuildables.add(p);
                        // create a reference and apply dimension
                        returnType = new ClassRefBuilder(p.toInternalReference()).withDimensions(ref.getDimensions()).build();
                    }
                }
                Map<AttributeKey, Object> fieldAttributes = new HashMap<>();
                if (method.hasAttribute(DEFAULT_VALUE)) {
                    if (returnType.getDimensions() > 0 || (mutable && initialize)) {
                        fieldAttributes.put(DEFAULT_VALUE, method.getAttribute(DEFAULT_VALUE));
                        fieldAttributes.put(INIT, getDefaultValue(new PropertyBuilder().withTypeRef(returnType).withAttributes(fieldAttributes).build()));
                    }
                }
                // For arguments we need to retain all the original attributes as they affect adapters.
                Property arg = new PropertyBuilder().withName(name).withTypeRef(returnType).withModifiers(Types.modifiersToInt()).withAttributes(method.getAttributes()).build();
                arguments.add(arg);
                // Let's also update superClassFields, so that we reatins default values.
                if (superClassFields.containsKey(name)) {
                    superClassFields.put(name, arg);
                }
                if (!superClassFields.containsKey(Strings.toFieldName(name))) {
                    Property field = new PropertyBuilder().withName(Strings.toFieldName(name)).withTypeRef(returnType).withModifiers(mutable ? Types.modifiersToInt(Modifier.PRIVATE) : Types.modifiersToInt(Modifier.PRIVATE, Modifier.FINAL)).withAttributes(fieldAttributes).build();
                    Method getter = new MethodBuilder(Getter.forProperty(field)).withAnnotations(method.getAnnotations()).withComments(method.getComments()).withModifiers(modifiersToInt(Modifier.PUBLIC)).withNewBlock().withStatements(new StringStatement("return this." + Strings.toFieldName(name) + ";")).endBlock().build();
                    fields.add(field);
                    getters.add(getter);
                    if (field.getTypeRef().equals(Types.BOOLEAN_REF)) {
                        Method primitiveGetter = new MethodBuilder(getter).withName("is" + getter.getName().replaceAll("^get", "")).withReturnType(Types.PRIMITIVE_BOOLEAN_REF).withNewBlock().withStatements(new StringStatement("return this." + Strings.toFieldName(name) + " != null &&  this." + Strings.toFieldName(name) + ";")).endBlock().build();
                        getters.add(primitiveGetter);
                    }
                }
            // Let's try to identify methods that we can't possibly implement and mark the type as abstract if such method is found.
            } else if (method.isDefaultMethod()) {
            // nothing special
            } else if (method.getBlock() != null && method.getBlock().getClass() != null && !method.getBlock().getStatements().isEmpty()) {
            // actual method, nothing special
            } else if (method.getExceptions() != null && !method.getExceptions().isEmpty()) {
                shouldBeAbstract = true;
            }
        }
    }
    List<Statement> statements = new ArrayList<Statement>();
    if (superClass != null) {
        Method constructor = findBuildableConstructor(superClass);
        if (constructor != null) {
            constructorArgs.addAll(constructor.getArguments());
        }
        StringBuilder sb = new StringBuilder();
        sb.append("super(");
        sb.append(Strings.join(constructor.getArguments(), new Function<Property, String>() {

            @Override
            public String apply(Property item) {
                return Strings.toFieldName(item.getName());
            }
        }, ", "));
        sb.append(");");
        statements.add(new StringStatement(sb.toString()));
        for (Property p : fields) {
            statements.add(new StringStatement(fieldIntializer(p, initialize)));
        }
    } else {
        for (Property p : fields) {
            statements.add(new StringStatement(fieldIntializer(p, initialize)));
        }
    }
    List<Method> constructors = new ArrayList();
    Method emptyConstructor = new MethodBuilder().withModifiers(modifiersToInt(Modifier.PUBLIC)).build();
    // We NEED to make sure that the superclass constructor arguments are in place and then add everything else.
    for (Property p : arguments) {
        if (!constructorArgs.contains(p)) {
            constructorArgs.add(p);
        }
    }
    // We don't want to annotate the POJO as @Buildable, as this is likely to re-trigger the processor multiple times.
    // The processor instead explicitly generates fluent and builder for the new pojo.
    Method buildableConstructor = new MethodBuilder().withModifiers(modifiersToInt(Modifier.PUBLIC)).withArguments(constructorArgs).withNewBlock().withStatements(statements).endBlock().accept(new TypedVisitor<PropertyBuilder>() {

        @Override
        public void visit(PropertyBuilder b) {
            String name = b.getName();
            b.withName(Strings.toFieldName(name));
            // That piece of information is lost (as is the case with our super-classs). Let's work-around it.
            if (superClassFields.containsKey(name)) {
                Property f = superClassFields.get(name);
                if (f.getAttributes().containsKey(DEFAULT_VALUE)) {
                    b.addToAttributes(DEFAULT_VALUE, f.getAttribute(DEFAULT_VALUE));
                }
            }
        }
    }).build();
    if (mutable) {
        constructors.add(emptyConstructor);
    }
    constructors.add(buildableConstructor);
    int modifiers = shouldBeAbstract ? modifiersToInt(Modifier.PUBLIC, Modifier.ABSTRACT) : modifiersToInt(Modifier.PUBLIC);
    TypeDef generatedPojo = new TypeDefBuilder().withPackageName(relativePackage(item.getPackageName(), relativePath)).withModifiers(modifiers).withName(pojoName).withAnnotations(annotationRefs).withProperties(fields).withConstructors(constructors).withMethods(getters).withImplementsList(new ArrayList<>(implementsList)).withExtendsList(new ArrayList<>(extendsList)).addToAttributes(item.getAttributes()).build();
    TypeDef pojoBuilder = BUILDER.apply(TypeArguments.apply(generatedPojo));
    if (!shouldBeAbstract) {
        if (enableStaticBuilder) {
            Method staticBuilder = new MethodBuilder().withModifiers(modifiersToInt(Modifier.PUBLIC, Modifier.STATIC)).withName(// avoid clashes in case of inheritance
            extendsList.isEmpty() ? "newBuilder" : "new" + pojoBuilder.getName()).withReturnType(pojoBuilder.toInternalReference()).withNewBlock().addNewStringStatementStatement("return new " + pojoBuilder.getFullyQualifiedName() + "();").endBlock().build();
            additionalMethods.add(staticBuilder);
            StringBuilder sb = new StringBuilder().append("return new " + pojoBuilder.getFullyQualifiedName() + "()");
            for (Method m : item.getMethods()) {
                if (m.hasAttribute(DEFAULT_VALUE)) {
                    if (m.getReturnType().getDimensions() > 0) {
                        continue;
                    }
                    String defaultValue = getDefaultValue(m);
                    if (defaultValue == null || defaultValue.trim().isEmpty() || defaultValue.equals("\"\"") || defaultValue.equals("null")) {
                        continue;
                    }
                    sb.append(".with" + Strings.capitalizeFirst(Strings.toFieldName(m.getName())) + "(" + defaultValue + ")");
                }
            }
            sb.append(";");
            Method staticBuilderFromDefaults = new MethodBuilder().withModifiers(modifiersToInt(Modifier.PUBLIC, Modifier.STATIC)).withName(// avoid clashes in case of inheritance
            extendsList.isEmpty() ? "newBuilderFromDefaults" : "new" + pojoBuilder.getName() + "FromDefaults").withReturnType(pojoBuilder.toInternalReference()).withNewBlock().addNewStringStatementStatement(sb.toString()).endBlock().build();
            additionalMethods.add(staticBuilderFromDefaults);
        }
        Method staticAdapter = new MethodBuilder().withModifiers(modifiersToInt(Modifier.PUBLIC, Modifier.STATIC)).withName("adapt").addNewArgument().withName("instance").withTypeRef(item.toInternalReference()).endArgument().withReturnType(generatedPojo.toInternalReference()).withNewBlock().addNewStringStatementStatement("return newBuilder(instance).build();").endBlock().build();
        Method staticAdaptingBuilder = new MethodBuilder().withModifiers(modifiersToInt(Modifier.PUBLIC, Modifier.STATIC)).withName("newBuilder").addNewArgument().withName("instance").withTypeRef(item.toInternalReference()).endArgument().withReturnType(pojoBuilder.toInternalReference()).withNewBlock().addToStatements(new StringStatement(() -> "return " + convertReference("instance", item, generatedPojo, pojoBuilder) + ";")).endBlock().build();
        Method staticMapAdapterWithDefaults = new MethodBuilder().withModifiers(modifiersToInt(Modifier.PUBLIC, Modifier.STATIC)).withName("adaptWithDefaults").addNewArgument().withName("map").withTypeRef(Collections.MAP.toUnboundedReference()).endArgument().withReturnType(generatedPojo.toInternalReference()).withNewBlock().addToStatements(new StringStatement(() -> "return " + convertMap("map", item, generatedPojo) + ";")).endBlock().build();
        Method staticMapAdapter = new MethodBuilder().withModifiers(modifiersToInt(Modifier.PUBLIC, Modifier.STATIC)).withName("adapt").addNewArgument().withName("map").withTypeRef(Collections.MAP.toUnboundedReference()).endArgument().withReturnType(generatedPojo.toInternalReference()).withNewBlock().addToStatements(new StringStatement(() -> "return " + convertMap("map", item, withoutDefaults(generatedPojo)) + ";")).endBlock().build();
        Method staticMapAdaptingBuilder = new MethodBuilder().withModifiers(modifiersToInt(Modifier.PUBLIC, Modifier.STATIC)).withName("newBuilder").addNewArgument().withName("map").withTypeRef(Collections.MAP.toUnboundedReference()).endArgument().withReturnType(pojoBuilder.toInternalReference()).withNewBlock().addToStatements(new StringStatement(() -> "return " + convertMap("map", item, withoutDefaults(generatedPojo), withoutDefaults(pojoBuilder)) + ";")).endBlock().build();
        Method staticMapAdaptingBuilderWithDefaults = new MethodBuilder().withModifiers(modifiersToInt(Modifier.PUBLIC, Modifier.STATIC)).withName("newBuilderWithDefaults").addNewArgument().withName("map").withTypeRef(Collections.MAP.toUnboundedReference()).endArgument().withReturnType(pojoBuilder.toInternalReference()).withNewBlock().addToStatements(new StringStatement(() -> "return " + convertMap("map", item, generatedPojo, pojoBuilder) + ";")).endBlock().build();
        Method staticToStringArray = new MethodBuilder().withModifiers(modifiersToInt(Modifier.PUBLIC, Modifier.STATIC)).withName("toStringArray").addNewArgument().withName("o").withTypeRef(Types.OBJECT.toInternalReference()).endArgument().withReturnType(Types.STRING_REF.withDimensions(1)).withNewBlock().addToStatements(new StringStatement(TO_STRING_ARRAY_TEXT)).endBlock().build();
        if (enableStaticAdapter && hasArrayFields(item)) {
            item.getMethods().stream().filter(m -> m.getReturnType() instanceof ClassRef && ((ClassRef) m.getReturnType()).getDimensions() > 0).findAny().ifPresent(m -> {
                additionalImports.add(ARRAYS);
                additionalImports.add(COLLECTORS);
            });
            additionalMethods.add(staticAdapter);
            additionalMethods.add(staticAdaptingBuilder);
            additionalMethods.add(staticMapAdapter);
            additionalMethods.add(staticMapAdaptingBuilderWithDefaults);
            additionalMethods.add(staticMapAdapterWithDefaults);
            if (enableStaticMapAdapter) {
                additionalMethods.add(staticMapAdaptingBuilder);
            }
        }
        Method equals = new MethodBuilder().withModifiers(Types.modifiersToInt(Modifier.PUBLIC)).withReturnType(Types.PRIMITIVE_BOOLEAN_REF).addNewArgument().withName("o").withTypeRef(Types.OBJECT.toReference()).endArgument().withName("equals").withNewBlock().withStatements(BuilderUtils.toEquals(generatedPojo, fields)).endBlock().build();
        Method hashCode = new MethodBuilder().withModifiers(Types.modifiersToInt(Modifier.PUBLIC)).withReturnType(Types.PRIMITIVE_INT_REF).withName("hashCode").withNewBlock().withStatements(BuilderUtils.toHashCode(fields)).endBlock().build();
        additionalMethods.add(equals);
        additionalMethods.add(hashCode);
        for (Object o : adapters) {
            if (o instanceof AnnotationRef) {
                AnnotationRef r = (AnnotationRef) o;
                String name = String.valueOf(r.getParameters().getOrDefault("name", ""));
                String prefix = String.valueOf(r.getParameters().getOrDefault("prefix", ""));
                String suffix = String.valueOf(r.getParameters().getOrDefault("suffix", ""));
                String mapperRelativePath = "";
                boolean enableMapAdapter = !"false".equals(String.valueOf(r.getParameters().getOrDefault("withMapAdapterMethod", "false")));
                List<Method> adapterMethods = new ArrayList<>();
                if (Strings.isNullOrEmpty(name) && Strings.isNullOrEmpty(prefix) && Strings.isNullOrEmpty(suffix)) {
                    suffix = "Adapter";
                }
                if (r.getParameters().containsKey("relativePath")) {
                    mapperRelativePath = String.valueOf(r.getParameters().getOrDefault("relativePath", "."));
                }
                String adapterPackage = relativePackage(item.getPackageName(), mapperRelativePath);
                List<ClassRef> adapterImports = new ArrayList<>();
                adapterImports.add(Collections.LIST.toInternalReference());
                if (hasArrayFields(item)) {
                    adapterImports.add(ARRAYS);
                    adapterImports.add(COLLECTORS);
                }
                List<ClassRef> generatedRefs = new ArrayList<>();
                Types.allProperties(generatedPojo).stream().map(i -> i.getTypeRef()).filter(i -> i instanceof ClassRef).forEach(i -> populateReferences((ClassRef) i, generatedRefs));
                adapterImports.addAll(generatedRefs);
                adapterImports.add(TypeAs.SHALLOW_BUILDER.apply(generatedPojo).toInternalReference());
                Types.allProperties(generatedPojo).stream().filter(p -> p.getTypeRef() instanceof ClassRef).map(p -> (ClassRef) p.getTypeRef()).filter(c -> !adapterPackage.equals(GetDefinition.of(c).getPackageName())).collect(toList());
                adapterImports.addAll(Types.allProperties(generatedPojo).stream().filter(p -> p.getTypeRef() instanceof ClassRef).map(p -> (ClassRef) p.getTypeRef()).filter(c -> !adapterPackage.equals(GetDefinition.of(c).getPackageName())).collect(toList()));
                adapterMethods.add(staticAdapter);
                adapterMethods.add(staticAdaptingBuilder);
                adapterMethods.add(staticMapAdapter);
                if (enableMapAdapter) {
                    adapterMethods.add(staticMapAdaptingBuilder);
                }
                adapterMethods.add(staticToStringArray);
                TypeDef mapper = new TypeDefBuilder().withComments("Generated").withModifiers(modifiersToInt(Modifier.PUBLIC)).withPackageName(adapterPackage).withName(!Strings.isNullOrEmpty(name) ? name : Strings.toPojoName(generatedPojo.getName(), prefix, suffix)).withMethods(adapterMethods).addToAttributes(ALSO_IMPORT, adapterImports).build();
                additionalTypes.add(mapper);
            }
        }
    }
    return DefinitionRepository.getRepository().register(new TypeDefBuilder(generatedPojo).withComments("Generated").addAllToMethods(additionalMethods).addToAttributes(ALSO_IMPORT, additionalImports).addToAttributes(ADDITIONAL_BUILDABLES, additionalBuildables).addToAttributes(ADDITIONAL_TYPES, additionalTypes).build());
}
Also used : INIT(io.sundr.model.Attributeable.INIT) Arrays(java.util.Arrays) BuilderUtils.findBuildableConstructor(io.sundr.builder.internal.utils.BuilderUtils.findBuildableConstructor) Array(java.lang.reflect.Array) Modifier(javax.lang.model.element.Modifier) Buildable(io.sundr.builder.annotations.Buildable) AnnotationRefBuilder(io.sundr.model.AnnotationRefBuilder) TO_STRING_ARRAY_SNIPPET(io.sundr.builder.Constants.TO_STRING_ARRAY_SNIPPET) Pojo(io.sundr.builder.annotations.Pojo) BuilderUtils(io.sundr.builder.internal.utils.BuilderUtils) Attributeable(io.sundr.model.Attributeable) ClassRef(io.sundr.model.ClassRef) Getter(io.sundr.model.utils.Getter) PropertyFluent(io.sundr.model.PropertyFluent) Map(java.util.Map) Path(java.nio.file.Path) COLLECTORS(io.sundr.builder.Constants.COLLECTORS) Collections(io.sundr.model.utils.Collections) Strings(io.sundr.utils.Strings) BuilderContext(io.sundr.builder.internal.BuilderContext) DefinitionRepository(io.sundr.model.repo.DefinitionRepository) Strings.loadResourceQuietly(io.sundr.utils.Strings.loadResourceQuietly) Set(java.util.Set) Element(javax.lang.model.element.Element) Method(io.sundr.model.Method) ADDITIONAL_BUILDABLES(io.sundr.builder.Constants.ADDITIONAL_BUILDABLES) Collectors(java.util.stream.Collectors) ALSO_IMPORT(io.sundr.model.Attributeable.ALSO_IMPORT) List(java.util.List) ClassRefBuilder(io.sundr.model.ClassRefBuilder) PrimitiveRef(io.sundr.model.PrimitiveRef) MethodBuilder(io.sundr.model.MethodBuilder) ARRAYS(io.sundr.builder.Constants.ARRAYS) Annotation(java.lang.annotation.Annotation) Optional(java.util.Optional) Pattern(java.util.regex.Pattern) BuilderContextManager(io.sundr.builder.internal.BuilderContextManager) ADDITIONAL_TYPES(io.sundr.builder.Constants.ADDITIONAL_TYPES) CopyOnWriteArrayList(java.util.concurrent.CopyOnWriteArrayList) StringStatement(io.sundr.model.StringStatement) BUILDER(io.sundr.builder.internal.functions.ClazzAs.BUILDER) GetDefinition(io.sundr.model.functions.GetDefinition) HashMap(java.util.HashMap) TypeDefBuilder(io.sundr.model.TypeDefBuilder) Function(java.util.function.Function) Stack(java.util.Stack) ArrayList(java.util.ArrayList) AttributeKey(io.sundr.model.AttributeKey) HashSet(java.util.HashSet) RichTypeDef(io.sundr.model.RichTypeDef) Assignable(io.sundr.model.functions.Assignable) Types(io.sundr.model.utils.Types) POJO(io.sundr.builder.internal.functions.ClazzAs.POJO) AptContext(io.sundr.adapter.apt.AptContext) TypedVisitor(io.sundr.builder.TypedVisitor) Types.modifiersToInt(io.sundr.model.utils.Types.modifiersToInt) ElementKind(javax.lang.model.element.ElementKind) Adapters(io.sundr.adapter.api.Adapters) TypeRef(io.sundr.model.TypeRef) AnnotationRef(io.sundr.model.AnnotationRef) Property(io.sundr.model.Property) TypeArguments(io.sundr.model.utils.TypeArguments) Paths(java.nio.file.Paths) Statement(io.sundr.model.Statement) TypeDef(io.sundr.model.TypeDef) DEFAULT_VALUE(io.sundr.model.Attributeable.DEFAULT_VALUE) PropertyBuilder(io.sundr.model.PropertyBuilder) TypedVisitor(io.sundr.builder.TypedVisitor) Pojo(io.sundr.builder.annotations.Pojo) ClassRef(io.sundr.model.ClassRef) HashMap(java.util.HashMap) TypeRef(io.sundr.model.TypeRef) CopyOnWriteArrayList(java.util.concurrent.CopyOnWriteArrayList) ArrayList(java.util.ArrayList) TypeDefBuilder(io.sundr.model.TypeDefBuilder) MethodBuilder(io.sundr.model.MethodBuilder) Function(java.util.function.Function) RichTypeDef(io.sundr.model.RichTypeDef) TypeDef(io.sundr.model.TypeDef) AnnotationRefBuilder(io.sundr.model.AnnotationRefBuilder) List(java.util.List) CopyOnWriteArrayList(java.util.concurrent.CopyOnWriteArrayList) ArrayList(java.util.ArrayList) Property(io.sundr.model.Property) AnnotationRef(io.sundr.model.AnnotationRef) Buildable(io.sundr.builder.annotations.Buildable) HashSet(java.util.HashSet) PropertyBuilder(io.sundr.model.PropertyBuilder) AptContext(io.sundr.adapter.apt.AptContext) StringStatement(io.sundr.model.StringStatement) Statement(io.sundr.model.Statement) ClassRefBuilder(io.sundr.model.ClassRefBuilder) Method(io.sundr.model.Method) StringStatement(io.sundr.model.StringStatement) Annotation(java.lang.annotation.Annotation) AttributeKey(io.sundr.model.AttributeKey) BuilderContext(io.sundr.builder.internal.BuilderContext) CopyOnWriteArrayList(java.util.concurrent.CopyOnWriteArrayList)

Example 3 with Types

use of io.sundr.model.utils.Types in project sundrio by sundrio.

the class TypeElementToTypeDef method apply.

@Override
public TypeDef apply(TypeElement classElement) {
    // Check SuperClass
    Kind kind = Kind.CLASS;
    Element enclosing = classElement.getEnclosingElement();
    if (enclosing != null && ANY.equals(enclosing.getSimpleName().toString())) {
        throw new SundrException("Failed to read class element:" + classElement.getQualifiedName().toString() + ". " + Messages.POTENTIAL_UNRESOLVED_SYMBOL);
    }
    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 = referenceAdapterFunction.apply(superClass);
    }
    List<TypeParamDef> genericTypes = new ArrayList<TypeParamDef>();
    List<ClassRef> interfaces = new ArrayList<ClassRef>();
    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;
    } else if (classElement.getKind() == ElementKind.ENUM) {
        kind = Kind.ENUM;
    }
    String comments = AptContext.getContext().getElements().getDocComment(classElement);
    List<String> commentList = Strings.isNullOrEmpty(comments) ? new ArrayList<>() : Arrays.stream(comments.split(NEWLINE_PATTERN)).map(String::trim).filter(s -> !s.isEmpty()).collect(Collectors.toList());
    for (TypeMirror interfaceTypeMirrror : classElement.getInterfaces()) {
        TypeRef interfaceType = referenceAdapterFunction.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()) {
        TypeParamDef genericType = typeParamAdapterFunction.apply(typeParameter);
        genericTypes.add(genericType);
    }
    TypeDef baseType = new TypeDefBuilder().withComments(commentList).withKind(kind).withModifiers(Types.modifiersToInt(classElement.getModifiers())).withPackageName(getPackageName(classElement)).withName(getClassName(classElement)).withParameters(genericTypes).withExtendsList(superClassType instanceof ClassRef ? (ClassRef) superClassType : null).withImplementsList(interfaces).withOuterTypeName(classElement.getEnclosingElement() instanceof TypeElement ? classElement.getEnclosingElement().toString() : null).build();
    // We will register the base type first and will replace it with the full blown version later.
    context.getDefinitionRepository().registerIfAbsent(baseType);
    List<TypeDef> innerTypes = new ArrayList<TypeDef>();
    for (TypeElement innerElement : ElementFilter.typesIn(classElement.getEnclosedElements())) {
        TypeDef innerType = context.getDefinitionRepository().register(apply(innerElement));
        if (innerType == null) {
            throw new IllegalStateException("Inner type for:" + innerElement + " is null");
        }
        innerType = new TypeDefBuilder(innerType).withOuterTypeName(baseType.getFullyQualifiedName()).build();
        context.getDefinitionRepository().register(innerType);
        innerTypes.add(innerType);
    }
    TypeDefBuilder builder = new TypeDefBuilder(baseType).withInnerTypes(innerTypes);
    for (ExecutableElement constructor : ElementFilter.constructorsIn(classElement.getEnclosedElements())) {
        builder.addToConstructors(methodAdapterFunction.apply(constructor));
    }
    // Populate Fields
    for (VariableElement variableElement : ElementFilter.fieldsIn(classElement.getEnclosedElements())) {
        builder.addToProperties(propertyAdapterFunction.apply(variableElement));
    }
    Set<ExecutableElement> allMethods = new LinkedHashSet<ExecutableElement>();
    allMethods.addAll(ElementFilter.methodsIn(classElement.getEnclosedElements()));
    allMethods.addAll(getInheritedMethods(classElement));
    for (ExecutableElement method : allMethods) {
        builder.addToMethods(methodAdapterFunction.apply(method));
    }
    for (AnnotationMirror annotationMirror : classElement.getAnnotationMirrors()) {
        builder.addToAnnotations(annotationAdapterFunction.apply(annotationMirror));
    }
    // Let's register the full blown definition
    TypeDef result = context.getDefinitionRepository().register(builder.build());
    // Also register other types
    if (context.isDeep()) {
        Set<TypeElement> references = new HashSet<>(context.getReferences());
        references.stream().filter(t -> !t.equals(classElement)).filter(t -> !t.toString().startsWith("sun.") && !t.toString().startsWith("com.sun.")).forEach(t -> {
            String fqcn = t.toString();
            TypeDef existing = context.getDefinitionRepository().getDefinition(fqcn);
            if (existing == null) {
                context.getDefinitionRepository().registerIfAbsent(fqcn, () -> apply(t));
            }
            context.getReferences().remove(t);
        });
    }
    return result;
}
Also used : LinkedHashSet(java.util.LinkedHashSet) Arrays(java.util.Arrays) Modifier(javax.lang.model.element.Modifier) Apt.getPackageName(io.sundr.adapter.apt.utils.Apt.getPackageName) VariableElement(javax.lang.model.element.VariableElement) TypeElement(javax.lang.model.element.TypeElement) TypeDefBuilder(io.sundr.model.TypeDefBuilder) Function(java.util.function.Function) ArrayList(java.util.ArrayList) ClassRef(io.sundr.model.ClassRef) HashSet(java.util.HashSet) ElementFilter(javax.lang.model.util.ElementFilter) Types(io.sundr.model.utils.Types) LinkedHashSet(java.util.LinkedHashSet) Strings(io.sundr.utils.Strings) ElementKind(javax.lang.model.element.ElementKind) NoType(javax.lang.model.type.NoType) ExecutableElement(javax.lang.model.element.ExecutableElement) SundrException(io.sundr.SundrException) Set(java.util.Set) Element(javax.lang.model.element.Element) Method(io.sundr.model.Method) TypeRef(io.sundr.model.TypeRef) AnnotationRef(io.sundr.model.AnnotationRef) Kind(io.sundr.model.Kind) Collectors(java.util.stream.Collectors) AnnotationMirror(javax.lang.model.element.AnnotationMirror) Property(io.sundr.model.Property) TypeParameterElement(javax.lang.model.element.TypeParameterElement) List(java.util.List) TypeMirror(javax.lang.model.type.TypeMirror) Apt.getClassName(io.sundr.adapter.apt.utils.Apt.getClassName) TypeDef(io.sundr.model.TypeDef) TypeParamDef(io.sundr.model.TypeParamDef) TypeParamDef(io.sundr.model.TypeParamDef) ClassRef(io.sundr.model.ClassRef) TypeRef(io.sundr.model.TypeRef) VariableElement(javax.lang.model.element.VariableElement) TypeElement(javax.lang.model.element.TypeElement) ExecutableElement(javax.lang.model.element.ExecutableElement) Element(javax.lang.model.element.Element) TypeParameterElement(javax.lang.model.element.TypeParameterElement) ExecutableElement(javax.lang.model.element.ExecutableElement) ArrayList(java.util.ArrayList) VariableElement(javax.lang.model.element.VariableElement) TypeDefBuilder(io.sundr.model.TypeDefBuilder) TypeDef(io.sundr.model.TypeDef) TypeMirror(javax.lang.model.type.TypeMirror) ElementKind(javax.lang.model.element.ElementKind) Kind(io.sundr.model.Kind) SundrException(io.sundr.SundrException) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet) NoType(javax.lang.model.type.NoType) TypeElement(javax.lang.model.element.TypeElement) TypeParameterElement(javax.lang.model.element.TypeParameterElement) AnnotationMirror(javax.lang.model.element.AnnotationMirror)

Aggregations

AnnotationRef (io.sundr.model.AnnotationRef)3 ClassRef (io.sundr.model.ClassRef)3 Method (io.sundr.model.Method)3 Property (io.sundr.model.Property)3 TypeDef (io.sundr.model.TypeDef)3 TypeDefBuilder (io.sundr.model.TypeDefBuilder)3 TypeRef (io.sundr.model.TypeRef)3 Adapters (io.sundr.adapter.api.Adapters)2 AptContext (io.sundr.adapter.apt.AptContext)2 TypedVisitor (io.sundr.builder.TypedVisitor)2 BuilderContext (io.sundr.builder.internal.BuilderContext)2 BuilderContextManager (io.sundr.builder.internal.BuilderContextManager)2 Types (io.sundr.model.utils.Types)2 Strings (io.sundr.utils.Strings)2 ArrayList (java.util.ArrayList)2 Arrays (java.util.Arrays)2 HashSet (java.util.HashSet)2 List (java.util.List)2 Set (java.util.Set)2 Function (java.util.function.Function)2