Search in sources :

Example 1 with TypedVisitor

use of io.sundr.builder.TypedVisitor in project sundrio by sundrio.

the class AbstractBuilderProcessor method inlineableOf.

static TypeDef inlineableOf(BuilderContext ctx, TypeDef type, Inline inline) {
    final String inlineableName = !inline.name().isEmpty() ? inline.name() : inline.prefix() + type.getName() + inline.suffix();
    List<Method> constructors = new ArrayList<Method>();
    final TypeDef builderType = TypeAs.BUILDER.apply(type);
    TypeDef inlineType = BuilderUtils.getInlineType(ctx, inline);
    TypeDef returnType = BuilderUtils.getInlineReturnType(ctx, inline, type);
    final ClassRef inlineTypeRef = inlineType.toReference(returnType.toReference());
    // Use the builder as the base of the inlineable. Just add interface and change name.
    final TypeDef shallowInlineType = new TypeDefBuilder(builderType).withName(inlineableName).withImplementsList(inlineTypeRef).withProperties().withMethods().withConstructors().build();
    TypeRef functionType = Constants.FUNCTION.toReference(type.toInternalReference(), returnType.toInternalReference());
    Property builderProperty = new PropertyBuilder().withTypeRef(TypeAs.BUILDER.apply(type).toInternalReference()).withName(BUILDER).withModifiers(Types.modifiersToInt(Modifier.PRIVATE, Modifier.FINAL)).build();
    Property functionProperty = new PropertyBuilder().withTypeRef(functionType).withName(FUNCTION).withModifiers(Types.modifiersToInt(Modifier.PRIVATE, Modifier.FINAL)).build();
    Method inlineMethod = new MethodBuilder().withReturnType(returnType.toInternalReference()).withName(inline.value()).withNewBlock().addNewStringStatementStatement(BUILD_AND_APPLY_FUNCTION).endBlock().withModifiers(Types.modifiersToInt(Modifier.PUBLIC)).build();
    constructors.add(new MethodBuilder().withReturnType(inlineTypeRef).withName(EMPTY).addNewArgument().withName(FUNCTION).withTypeRef(functionType).and().withModifiers(Types.modifiersToInt(Modifier.PUBLIC)).withNewBlock().addNewStringStatementStatement(String.format(NEW_BULDER_AND_SET_FUNCTION_FORMAT, builderType.getName())).endBlock().build());
    constructors.add(new MethodBuilder().withReturnType(inlineTypeRef).withName(EMPTY).addNewArgument().withName(ITEM).withTypeRef(type.toInternalReference()).and().addNewArgument().withName(FUNCTION).withTypeRef(functionType).and().withModifiers(Types.modifiersToInt(Modifier.PUBLIC)).withNewBlock().addNewStringStatementStatement(String.format(NEW_BULDER_WITH_ITEM_AND_SET_FUNCTION_FORMAT, builderType.getName())).endBlock().build());
    if (type.equals(returnType)) {
        constructors.add(new MethodBuilder().withReturnType(inlineTypeRef).withName(EMPTY).addNewArgument().withName(ITEM).withTypeRef(type.toInternalReference()).and().withModifiers(Types.modifiersToInt(Modifier.PUBLIC)).withNewBlock().addNewStringStatementStatement(String.format(NEW_BUILDER_AND_EMTPY_FUNCTION_FORMAT, builderType.getName(), String.format(EMPTY_FUNCTION_TEXT, type.toInternalReference(), returnType.toInternalReference(), returnType.toInternalReference(), type.toInternalReference()))).endBlock().build());
    }
    return new TypeDefBuilder(shallowInlineType).withAnnotations().withModifiers(Types.modifiersToInt(Modifier.PUBLIC)).withConstructors(constructors).addToProperties(builderProperty, functionProperty).addToMethods(inlineMethod).accept(new TypedVisitor<ClassRefBuilder>() {

        @Override
        public void visit(ClassRefBuilder builder) {
            List<TypeRef> updatedArguments = new ArrayList<TypeRef>();
            for (TypeRef arg : builder.getArguments()) {
                if (arg.equals(builderType.toInternalReference())) {
                    updatedArguments.add(shallowInlineType.toInternalReference());
                } else {
                    updatedArguments.add(arg);
                }
            }
            builder.withArguments(updatedArguments);
        }
    }).build();
}
Also used : TypedVisitor(io.sundr.builder.TypedVisitor) ClassRef(io.sundr.model.ClassRef) TypeRef(io.sundr.model.TypeRef) ClassRefBuilder(io.sundr.model.ClassRefBuilder) ArrayList(java.util.ArrayList) Method(io.sundr.model.Method) TypeDefBuilder(io.sundr.model.TypeDefBuilder) MethodBuilder(io.sundr.model.MethodBuilder) RichTypeDef(io.sundr.model.RichTypeDef) TypeDef(io.sundr.model.TypeDef) Property(io.sundr.model.Property) PropertyBuilder(io.sundr.model.PropertyBuilder)

Example 2 with TypedVisitor

use of io.sundr.builder.TypedVisitor in project sundrio by sundrio.

the class BindDefinition method mapGenericProperties.

/**
 * Map generic properties to known {@link TypeRef} based on the specified mappings.
 * Example: Given a property {@code T size} and a map containing {@code T -> Integer} the final
 * property will be: {@code Integer type}.
 *
 * @param mappings A map that maps class arguments names to types.
 * @return a visitors that performs the actual mapping.
 */
private static TypedVisitor<PropertyBuilder> mapGenericProperties(Map<String, TypeRef> mappings) {
    return new TypedVisitor<PropertyBuilder>() {

        @Override
        public void visit(PropertyBuilder property) {
            TypeRef typeRef = property.buildTypeRef();
            if (typeRef instanceof TypeParamRef) {
                TypeParamRef typeParamRef = (TypeParamRef) typeRef;
                String key = typeParamRef.getName();
                TypeRef paramRef = mappings.get(key);
                if (paramRef != null) {
                    property.withTypeRef(paramRef);
                }
            }
        }
    };
}
Also used : TypedVisitor(io.sundr.builder.TypedVisitor) TypeParamRef(io.sundr.model.TypeParamRef) TypeRef(io.sundr.model.TypeRef) PropertyBuilder(io.sundr.model.PropertyBuilder)

Example 3 with TypedVisitor

use of io.sundr.builder.TypedVisitor in project sundrio by sundrio.

the class BindDefinition method mapClassRefArguments.

/**
 * Map arguments, of {@link ClassRef} instances to known {@link TypeRef} based on the specified mappings.
 * Example: Given a class reference to {@code Shape<T>} and a map containing {@code T -> Integer}
 * the final reference will be: {@code Shape<Integer> type}.
 *
 * @param mappings A map that maps class arguments names to types.
 * @return a visitors that performs the actual mapping.
 */
private static TypedVisitor<ClassRefBuilder> mapClassRefArguments(Map<String, TypeRef> mappings) {
    return new TypedVisitor<ClassRefBuilder>() {

        @Override
        public void visit(ClassRefBuilder c) {
            List<TypeRef> arguments = new ArrayList<>();
            for (TypeRef arg : c.buildArguments()) {
                TypeRef mappedRef = arg;
                if (arg instanceof TypeParamRef) {
                    TypeParamRef typeParamRef = (TypeParamRef) arg;
                    TypeRef mapping = mappings.get(typeParamRef.getName());
                    if (mapping != null) {
                        mappedRef = mapping;
                    }
                }
                arguments.add(mappedRef);
            }
            c.withArguments(arguments);
        }
    };
}
Also used : TypedVisitor(io.sundr.builder.TypedVisitor) TypeParamRef(io.sundr.model.TypeParamRef) TypeRef(io.sundr.model.TypeRef) ClassRefBuilder(io.sundr.model.ClassRefBuilder) ArrayList(java.util.ArrayList)

Example 4 with TypedVisitor

use of io.sundr.builder.TypedVisitor in project sundrio by sundrio.

the class BindDefinition method mapGenericReturnTypes.

/**
 * Map generic properties to known {@link TypeRef} based on the specified mappings.
 * Example: Given a property {@code T size} and a map containing {@code T -> Integer} the final
 * property will be: {@code Integer type}.
 *
 * @param mappings A map that maps class arguments names to types.
 * @return a visitors that performs the actual mapping.
 */
private static TypedVisitor<MethodBuilder> mapGenericReturnTypes(Map<String, TypeRef> mappings) {
    return new TypedVisitor<MethodBuilder>() {

        @Override
        public void visit(MethodBuilder method) {
            TypeRef typeRef = method.buildReturnType();
            if (typeRef instanceof TypeParamRef) {
                TypeParamRef typeParamRef = (TypeParamRef) typeRef;
                String key = typeParamRef.getName();
                TypeRef paramRef = mappings.get(key);
                if (paramRef != null) {
                    method.withReturnType(paramRef);
                }
            }
        }
    };
}
Also used : TypedVisitor(io.sundr.builder.TypedVisitor) TypeParamRef(io.sundr.model.TypeParamRef) TypeRef(io.sundr.model.TypeRef) MethodBuilder(io.sundr.model.MethodBuilder)

Example 5 with TypedVisitor

use of io.sundr.builder.TypedVisitor 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)

Aggregations

TypedVisitor (io.sundr.builder.TypedVisitor)6 TypeRef (io.sundr.model.TypeRef)5 ClassRefBuilder (io.sundr.model.ClassRefBuilder)4 ArrayList (java.util.ArrayList)4 ClassRef (io.sundr.model.ClassRef)3 MethodBuilder (io.sundr.model.MethodBuilder)3 PropertyBuilder (io.sundr.model.PropertyBuilder)3 TypeDef (io.sundr.model.TypeDef)3 TypeDefBuilder (io.sundr.model.TypeDefBuilder)3 TypeParamRef (io.sundr.model.TypeParamRef)3 Method (io.sundr.model.Method)2 Property (io.sundr.model.Property)2 RichTypeDef (io.sundr.model.RichTypeDef)2 Adapters (io.sundr.adapter.api.Adapters)1 AptContext (io.sundr.adapter.apt.AptContext)1 ADDITIONAL_BUILDABLES (io.sundr.builder.Constants.ADDITIONAL_BUILDABLES)1 ADDITIONAL_TYPES (io.sundr.builder.Constants.ADDITIONAL_TYPES)1 ARRAYS (io.sundr.builder.Constants.ARRAYS)1 COLLECTORS (io.sundr.builder.Constants.COLLECTORS)1 TO_STRING_ARRAY_SNIPPET (io.sundr.builder.Constants.TO_STRING_ARRAY_SNIPPET)1