Search in sources :

Example 16 with ClassRefBuilder

use of io.sundr.model.ClassRefBuilder in project sundrio by sundrio.

the class ReplacePackage method visitTypeDefBuilder.

private void visitTypeDefBuilder(TypeDefBuilder builder) {
    if (target.equals(builder.getPackageName())) {
        builder.withPackageName(replacement);
    }
    if (builder.getAttributes().containsKey(TypeDef.ALSO_IMPORT)) {
        Set<ClassRef> updatedImports = new LinkedHashSet<ClassRef>();
        for (ClassRef classRef : (Set<ClassRef>) builder.getAttributes().get(TypeDef.ALSO_IMPORT)) {
            if (target.equals(classRef.getPackageName())) {
                updatedImports.add(new ClassRefBuilder(classRef).accept(this).build());
            } else {
                updatedImports.add(classRef);
            }
        }
        builder.getAttributes().put(TypeDef.ALSO_IMPORT, updatedImports);
    }
}
Also used : LinkedHashSet(java.util.LinkedHashSet) Set(java.util.Set) LinkedHashSet(java.util.LinkedHashSet) ClassRef(io.sundr.model.ClassRef) ClassRefBuilder(io.sundr.model.ClassRefBuilder)

Example 17 with ClassRefBuilder

use of io.sundr.model.ClassRefBuilder 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 18 with ClassRefBuilder

use of io.sundr.model.ClassRefBuilder in project sundrio by sundrio.

the class BuilderUtils method findBuildableReferences.

/**
 * Returns all references of a {@link ClassRef} that are considered buildable.
 *
 * @param ref The reference.
 * @return The list with all detected references.
 */
public static List<ClassRef> findBuildableReferences(ClassRef ref) {
    List<ClassRef> result = new ArrayList<>();
    TypeDef def = new TypeDefBuilder(GetDefinition.of(ref)).accept(new TypedVisitor<ClassRefBuilder>() {

        @Override
        public void visit(ClassRefBuilder builder) {
            ClassRef candidate = builder.build();
            if (isBuildable(candidate)) {
                result.add(candidate);
            }
        }
    }).build();
    return result;
}
Also used : TypedVisitor(io.sundr.builder.TypedVisitor) ClassRef(io.sundr.model.ClassRef) TypeDef(io.sundr.model.TypeDef) ClassRefBuilder(io.sundr.model.ClassRefBuilder) ArrayList(java.util.ArrayList) TypeDefBuilder(io.sundr.model.TypeDefBuilder)

Example 19 with ClassRefBuilder

use of io.sundr.model.ClassRefBuilder in project sundrio by sundrio.

the class BuilderUtils method buildableField.

public static Property buildableField(Property property) {
    TypeRef typeRef = property.getTypeRef();
    ClassRef targetType = (ClassRef) TypeAs.combine(UNWRAP_COLLECTION_OF, UNWRAP_ARRAY_OF, UNWRAP_OPTIONAL_OF).apply(typeRef);
    boolean isArray = Types.isArray(typeRef);
    boolean isSet = Types.isSet(typeRef);
    boolean isAbstractSet = isSet && Types.isAbstract(typeRef);
    boolean isList = Types.isList(typeRef);
    boolean isAbstractList = isList && Types.isAbstract(typeRef);
    boolean isMap = Types.isMap(typeRef);
    boolean isOptional = Types.isOptional(typeRef);
    boolean isOptionalDouble = Types.isOptionalDouble(typeRef);
    boolean isOptionalLong = Types.isOptionalLong(typeRef);
    // For fields that are concrete we can possibly create an instance of a VisitableBuilder.
    // For everything else we can have a builder e.g. Builder<Foo> = () -> fooInstance but it won't be visitable
    ClassRef builderType = Types.isConcrete(targetType) ? TypeAs.BUILDER.apply(GetDefinition.of(targetType)).toInternalReference() : TypeAs.VISITABLE_BUILDER.apply(targetType);
    if (isArray || isList) {
        ClassRef listRef = isArray || isAbstractList ? Collections.ARRAY_LIST.toReference(builderType) : new ClassRefBuilder((ClassRef) typeRef).withArguments(builderType).withDimensions(0).build();
        TypeDef listDef = new TypeDefBuilder(TypeDef.forName(listRef.getFullyQualifiedName())).addNewConstructor().endConstructor().addNewConstructor().addNewArgument().withTypeRef(Collections.LIST.toReference(builderType)).withName("l").endArgument().endConstructor().build();
        return new PropertyBuilder(property).withTypeRef(listRef).addToAttributes(LAZY_INIT, " new " + listRef + "()").addToAttributes(INIT_FUNCTION, new Construct(listDef, targetType)).addToAttributes(ALSO_IMPORT, alsoImport(property, listRef, builderType)).build();
    }
    if (isSet) {
        ClassRef setRef = isAbstractSet ? Collections.LINKED_HASH_SET.toReference(builderType) : new ClassRefBuilder((ClassRef) typeRef).withArguments(builderType).build();
        TypeDef setDef = new TypeDefBuilder(TypeDef.forName(setRef.getFullyQualifiedName())).addNewConstructor().endConstructor().addNewConstructor().addNewArgument().withTypeRef(Collections.SET.toReference(builderType)).withName("s").endArgument().endConstructor().build();
        return new PropertyBuilder(property).withTypeRef(setRef).addToAttributes(LAZY_INIT, " new " + setRef + "()").addToAttributes(INIT_FUNCTION, new Construct(setDef, targetType)).addToAttributes(ALSO_IMPORT, alsoImport(property, setRef, builderType)).build();
    }
    if (isOptionalLong) {
        ClassRef optionalRef = Optionals.OPTIONAL_LONG.toReference(builderType);
        return new PropertyBuilder(property).withTypeRef(optionalRef).addToAttributes(INIT, " OptionalLong.empty()").build();
    }
    if (isOptionalDouble) {
        ClassRef optionalRef = Optionals.OPTIONAL_DOUBLE.toReference(builderType);
        return new PropertyBuilder(property).withTypeRef(optionalRef).addToAttributes(INIT, " OptionalDouble.empty()").build();
    }
    if (Types.isOptionalInt(targetType)) {
        ClassRef optionalRef = Optionals.OPTIONAL_INT.toReference(builderType);
        return new PropertyBuilder(property).withTypeRef(optionalRef).addToAttributes(INIT, " OptionalInt.empty()").build();
    }
    if (isOptional) {
        ClassRef optionalRef = Optionals.OPTIONAL.toReference(builderType);
        return new PropertyBuilder(property).withTypeRef(optionalRef).addToAttributes(INIT, " Optional.empty()").addToAttributes(ALSO_IMPORT, alsoImport(property, optionalRef, builderType)).build();
    }
    if (Types.isConcrete(builderType) && BuilderUtils.hasDefaultConstructor(builderType) && property.hasAttribute(DEFAULT_VALUE)) {
        return new PropertyBuilder(property).withTypeRef(builderType).addToAttributes(ALSO_IMPORT, alsoImport(property, builderType)).addToAttributes(INIT, "new " + builderType + "()").build();
    }
    return new PropertyBuilder(property).withTypeRef(builderType).addToAttributes(ALSO_IMPORT, alsoImport(property, builderType)).removeFromAttributes(INIT).build();
}
Also used : ClassRef(io.sundr.model.ClassRef) TypeDef(io.sundr.model.TypeDef) TypeRef(io.sundr.model.TypeRef) ClassRefBuilder(io.sundr.model.ClassRefBuilder) Construct(io.sundr.builder.internal.functions.Construct) TypeDefBuilder(io.sundr.model.TypeDefBuilder) PropertyBuilder(io.sundr.model.PropertyBuilder)

Example 20 with ClassRefBuilder

use of io.sundr.model.ClassRefBuilder in project sundrio by sundrio.

the class InitEnricher method visit.

@Override
public void visit(PropertyBuilder builder) {
    TypeRef typeRef = builder.buildTypeRef();
    TypeRef unwrapped = TypeAs.combine(TypeAs.UNWRAP_ARRAY_OF, TypeAs.UNWRAP_COLLECTION_OF, TypeAs.UNWRAP_OPTIONAL_OF).apply(typeRef);
    boolean isBuildable = isBuildable(unwrapped);
    boolean hasDescendants = false;
    if (!(typeRef instanceof ClassRef)) {
        return;
    }
    Property parent = (Property) builder.getAttributes().get(DESCENDANT_OF);
    if (parent != null) {
        typeRef = parent.getTypeRef();
        unwrapped = TypeAs.combine(TypeAs.UNWRAP_ARRAY_OF, TypeAs.UNWRAP_COLLECTION_OF, TypeAs.UNWRAP_OPTIONAL_OF).apply(typeRef);
    } else if (builder.getAttributes().containsKey(DESCENDANTS) && !((Collection) builder.getAttributes().get(DESCENDANTS)).isEmpty()) {
        hasDescendants = true;
    }
    List<TypeRef> arguments = ((ClassRef) typeRef).getArguments();
    TypeRef targetType = unwrapped;
    if (isBuildable || hasDescendants) {
        ClassRef unwarppedClassRef = (unwrapped instanceof ClassRef) ? (ClassRef) unwrapped : null;
        targetType = isAbstract(unwarppedClassRef) || GetDefinition.of(unwarppedClassRef).getKind() == Kind.INTERFACE ? TypeAs.VISITABLE_BUILDER.apply(unwarppedClassRef) : TypeAs.BUILDER.apply(GetDefinition.of(unwarppedClassRef)).toInternalReference();
    }
    boolean isArray = Types.isArray(typeRef);
    boolean isSet = Types.isSet(typeRef);
    boolean isAbstractSet = isSet && Types.isAbstract(typeRef);
    boolean isList = Types.isList(typeRef);
    boolean isAbstractList = isList && Types.isAbstract(typeRef);
    boolean isMap = Types.isMap(typeRef);
    boolean isAbstractMap = isMap && Types.isAbstract(typeRef);
    boolean isOptional = Types.isOptional(typeRef);
    boolean isOptionalInt = Types.isOptionalInt(typeRef);
    boolean isOptionalDouble = Types.isOptionalDouble(typeRef);
    boolean isOptionalLong = Types.isOptionalLong(typeRef);
    if (isArray || isList) {
        ClassRef listRef = isArray || isAbstractList ? Collections.ARRAY_LIST.toReference(targetType) : new ClassRefBuilder((ClassRef) typeRef).withArguments(targetType).withDimensions(0).build();
        TypeDef listDef = new TypeDefBuilder(TypeDef.forName(listRef.getFullyQualifiedName())).addNewConstructor().endConstructor().addNewConstructor().addNewArgument().withTypeRef(Collections.LIST.toReference(targetType)).withName("l").endArgument().endConstructor().build();
        builder.addToAttributes(LAZY_INIT, "new " + listRef + "()").addToAttributes(INIT, builder.getAttributes().containsKey(LAZY_COLLECTIONS_INIT_ENABLED) && (Boolean) builder.getAttributes().get(LAZY_COLLECTIONS_INIT_ENABLED) ? null : builder.getAttributes().get(LAZY_INIT)).addToAttributes(INIT_FUNCTION, new Construct(listDef, targetType)).addToAttributes(ALSO_IMPORT, Arrays.asList(targetType, listRef));
    } else if (isSet) {
        ClassRef setRef = isAbstractSet ? Collections.LINKED_HASH_SET.toReference(targetType) : new ClassRefBuilder((ClassRef) typeRef).withArguments(targetType).build();
        TypeDef setDef = new TypeDefBuilder(TypeDef.forName(setRef.getFullyQualifiedName())).addNewConstructor().endConstructor().addNewConstructor().addNewArgument().withTypeRef(Collections.SET.toReference(targetType)).withName("s").endArgument().endConstructor().build();
        builder.addToAttributes(LAZY_INIT, "new " + setRef + "()").addToAttributes(INIT, builder.getAttributes().containsKey(LAZY_COLLECTIONS_INIT_ENABLED) && (Boolean) builder.getAttributes().get(LAZY_COLLECTIONS_INIT_ENABLED) ? null : builder.getAttributes().get(LAZY_INIT)).addToAttributes(INIT_FUNCTION, new Construct(setDef, unwrapped)).addToAttributes(ALSO_IMPORT, Arrays.asList(targetType, setRef));
    } else if (isMap) {
        ClassRef mapRef = isAbstractMap ? Collections.LINKED_HASH_MAP.toReference(arguments) : new ClassRefBuilder((ClassRef) typeRef).withArguments(arguments).build();
        TypeDef mapDef = new TypeDefBuilder(TypeDef.forName(mapRef.getFullyQualifiedName())).addNewConstructor().endConstructor().addNewConstructor().addNewArgument().withTypeRef(Collections.MAP.toReference(arguments)).withName("m").endArgument().endConstructor().build();
        builder.addToAttributes(LAZY_INIT, "new " + mapRef + "()").addToAttributes(INIT, builder.getAttributes().containsKey(LAZY_MAP_INIT_ENABLED) && (Boolean) builder.getAttributes().get(LAZY_MAP_INIT_ENABLED) ? null : builder.getAttributes().get(LAZY_INIT)).addToAttributes(INIT_FUNCTION, new Construct(mapDef, arguments)).addToAttributes(ALSO_IMPORT, Arrays.asList(targetType, mapRef));
    } else if (isOptional) {
        final ClassRef ref = new ClassRefBuilder(Optionals.OPTIONAL.toReference()).withArguments(java.util.Collections.EMPTY_LIST).build();
        builder.addToAttributes(INIT, "Optional.empty()").addToAttributes(INIT_FUNCTION, new Construct(Optionals.OPTIONAL, targetType, "of")).addToAttributes(ALSO_IMPORT, Arrays.asList(targetType, ref));
    } else if (isOptionalDouble) {
        final ClassRef ref = Optionals.OPTIONAL_DOUBLE.toReference();
        builder.addToAttributes(INIT, "OptionalDouble.empty()").addToAttributes(INIT_FUNCTION, new Construct(Optionals.OPTIONAL_DOUBLE, targetType, "of")).addToAttributes(ALSO_IMPORT, Arrays.asList(targetType, ref));
    } else if (isOptionalInt) {
        final ClassRef ref = Optionals.OPTIONAL_INT.toReference();
        builder.addToAttributes(INIT, "OptionalInt.empty()").addToAttributes(INIT_FUNCTION, new Construct(Optionals.OPTIONAL_INT, targetType, "of")).addToAttributes(ALSO_IMPORT, Arrays.asList(targetType, ref));
    } else if (isOptionalLong) {
        final ClassRef ref = Optionals.OPTIONAL_LONG.toReference();
        builder.addToAttributes(INIT, "OptionalLong.empty()").addToAttributes(INIT_FUNCTION, new Construct(Optionals.OPTIONAL_LONG, targetType, "of")).addToAttributes(ALSO_IMPORT, Arrays.asList(targetType, ref));
    }
}
Also used : ClassRef(io.sundr.model.ClassRef) TypeDef(io.sundr.model.TypeDef) TypeRef(io.sundr.model.TypeRef) ClassRefBuilder(io.sundr.model.ClassRefBuilder) Construct(io.sundr.builder.internal.functions.Construct) Property(io.sundr.model.Property) TypeDefBuilder(io.sundr.model.TypeDefBuilder)

Aggregations

ClassRefBuilder (io.sundr.model.ClassRefBuilder)22 ClassRef (io.sundr.model.ClassRef)18 TypeRef (io.sundr.model.TypeRef)13 ArrayList (java.util.ArrayList)8 TypedVisitor (io.sundr.builder.TypedVisitor)6 TypeDef (io.sundr.model.TypeDef)6 TypeParamRef (io.sundr.model.TypeParamRef)6 TypeDefBuilder (io.sundr.model.TypeDefBuilder)5 AttributeKey (io.sundr.model.AttributeKey)3 Property (io.sundr.model.Property)3 PropertyBuilder (io.sundr.model.PropertyBuilder)3 RichTypeDef (io.sundr.model.RichTypeDef)3 LinkedHashSet (java.util.LinkedHashSet)3 ClassOrInterfaceType (com.github.javaparser.ast.type.ClassOrInterfaceType)2 ReferenceType (com.github.javaparser.ast.type.ReferenceType)2 WildcardType (com.github.javaparser.ast.type.WildcardType)2 Construct (io.sundr.builder.internal.functions.Construct)2 PrimitiveRefBuilder (io.sundr.model.PrimitiveRefBuilder)2 PropertyFluent (io.sundr.model.PropertyFluent)2 TypeParamRefBuilder (io.sundr.model.TypeParamRefBuilder)2