Search in sources :

Example 1 with AttributeKey

use of io.sundr.model.AttributeKey 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 2 with AttributeKey

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

the class ExecutableElementToMethod method apply.

public Method apply(ExecutableElement executableElement) {
    Map<AttributeKey, Object> attributes = new HashMap<>();
    if (executableElement.getDefaultValue() != null) {
        attributes.put(Attributeable.DEFAULT_VALUE, String.valueOf(executableElement.getDefaultValue()));
    }
    String comments = context.getElements().getDocComment(executableElement);
    List<String> commentList = Strings.isNullOrEmpty(comments) ? new ArrayList<>() : Arrays.stream(comments.split(NEWLINE_PATTERN)).map(String::trim).filter(s -> !s.isEmpty()).collect(Collectors.toList());
    MethodBuilder methodBuilder = new MethodBuilder().withComments(commentList).withDefaultMethod(executableElement.isDefault()).withModifiers(Types.modifiersToInt(executableElement.getModifiers())).withName(executableElement.getSimpleName().toString()).withReturnType(referenceAdapterFunction.apply(executableElement.getReturnType())).withVarArgPreferred(executableElement.isVarArgs()).withAttributes(attributes);
    // Populate constructor parameters
    for (VariableElement variableElement : executableElement.getParameters()) {
        methodBuilder = methodBuilder.addToArguments(propertyAdapterFunction.apply(variableElement));
    }
    List<ClassRef> exceptionRefs = new ArrayList<ClassRef>();
    for (TypeMirror thrownType : executableElement.getThrownTypes()) {
        TypeRef thrownRef = referenceAdapterFunction.apply(thrownType);
        if (thrownRef instanceof ClassRef) {
            exceptionRefs.add((ClassRef) thrownRef);
        }
        methodBuilder = methodBuilder.withExceptions(exceptionRefs);
    }
    for (AnnotationMirror annotationMirror : executableElement.getAnnotationMirrors()) {
        methodBuilder = methodBuilder.withAnnotations(annotationAdapterFunction.apply(annotationMirror));
    }
    return methodBuilder.build();
}
Also used : ClassRef(io.sundr.model.ClassRef) HashMap(java.util.HashMap) TypeRef(io.sundr.model.TypeRef) ArrayList(java.util.ArrayList) VariableElement(javax.lang.model.element.VariableElement) MethodBuilder(io.sundr.model.MethodBuilder) AttributeKey(io.sundr.model.AttributeKey) AnnotationMirror(javax.lang.model.element.AnnotationMirror) TypeMirror(javax.lang.model.type.TypeMirror)

Example 3 with AttributeKey

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

the class ClassToTypeDef method getMethods.

private Set<Method> getMethods(Class item, Set<Class> references) {
    Set<Method> methods = new HashSet<Method>();
    for (java.lang.reflect.Method method : item.getDeclaredMethods()) {
        List<AnnotationRef> annotationRefs = new ArrayList<>();
        List<ClassRef> exceptionRefs = new ArrayList<>();
        List<Property> arguments = new ArrayList<Property>();
        List<TypeParamDef> parameters = new ArrayList<TypeParamDef>();
        processMethod(references, method, annotationRefs, exceptionRefs, arguments, parameters);
        Map<AttributeKey, Object> attributes = new HashMap<>();
        if (method.getDefaultValue() != null) {
            attributes.put(Attributeable.DEFAULT_VALUE, method.getDefaultValue());
        }
        methods.add(new MethodBuilder().withName(method.getName()).withDefaultMethod(method.isDefault()).withModifiers(method.getModifiers()).withReturnType(typeToTypeRef.apply(method.getGenericReturnType())).withArguments(arguments).withParameters(parameters).withExceptions(exceptionRefs).withAnnotations(annotationRefs).withAttributes(attributes).build());
    }
    return methods;
}
Also used : TypeParamDef(io.sundr.model.TypeParamDef) ClassRef(io.sundr.model.ClassRef) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) Method(io.sundr.model.Method) MethodBuilder(io.sundr.model.MethodBuilder) AttributeKey(io.sundr.model.AttributeKey) Property(io.sundr.model.Property) AnnotationRef(io.sundr.model.AnnotationRef) HashSet(java.util.HashSet)

Example 4 with AttributeKey

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

the class ClassTo method getMethods.

private static Set<Method> getMethods(Class item, Set<Class> references) {
    Set<Method> methods = new HashSet<Method>();
    for (java.lang.reflect.Method method : item.getDeclaredMethods()) {
        List<AnnotationRef> annotationRefs = new ArrayList<>();
        List<ClassRef> exceptionRefs = new ArrayList<>();
        List<Property> arguments = new ArrayList<Property>();
        List<TypeParamDef> parameters = new ArrayList<TypeParamDef>();
        processMethod(references, method, annotationRefs, exceptionRefs, arguments, parameters);
        Map<AttributeKey, Object> attributes = new HashMap<>();
        if (method.getDefaultValue() != null) {
            attributes.put(Attributeable.DEFAULT_VALUE, String.valueOf(method.getDefaultValue()));
        }
        methods.add(new MethodBuilder().withName(method.getName()).withDefaultMethod(method.isDefault()).withModifiers(method.getModifiers()).withReturnType(TYPEREF.apply(method.getReturnType())).withArguments(arguments).withParameters(parameters).withExceptions(exceptionRefs).withAnnotations(annotationRefs).withAttributes(attributes).build());
    }
    return methods;
}
Also used : TypeParamDef(io.sundr.model.TypeParamDef) ClassRef(io.sundr.model.ClassRef) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) Method(io.sundr.model.Method) MethodBuilder(io.sundr.model.MethodBuilder) AttributeKey(io.sundr.model.AttributeKey) Property(io.sundr.model.Property) AnnotationRef(io.sundr.model.AnnotationRef) HashSet(java.util.HashSet)

Example 5 with AttributeKey

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

the class TypeDeclarationToTypeDef method apply.

@Override
public TypeDef apply(TypeDeclaration type) {
    if (type instanceof ClassOrInterfaceDeclaration) {
        ClassOrInterfaceDeclaration decl = (ClassOrInterfaceDeclaration) type;
        Kind kind = decl.isInterface() ? Kind.INTERFACE : Kind.CLASS;
        List<TypeParamDef> parameters = new ArrayList<TypeParamDef>();
        List<ClassRef> extendsList = new ArrayList<ClassRef>();
        List<ClassRef> implementsList = new ArrayList<ClassRef>();
        List<Property> properties = new ArrayList<Property>();
        List<Method> methods = new ArrayList<Method>();
        List<Method> constructors = new ArrayList<Method>();
        List<AnnotationRef> annotations = new ArrayList<AnnotationRef>();
        for (AnnotationExpr annotationExpr : decl.getAnnotations()) {
            annotations.add(ANNOTATIONREF.apply(annotationExpr));
        }
        for (TypeParameter typeParameter : decl.getTypeParameters()) {
            parameters.add(typeParameterToTypeParamDef.apply(typeParameter));
        }
        for (ClassOrInterfaceType classOrInterfaceType : decl.getExtends()) {
            extendsList.add((ClassRef) classOrInterfaceToTypeRef.apply(classOrInterfaceType));
        }
        for (ClassOrInterfaceType classOrInterfaceType : decl.getImplements()) {
            implementsList.add((ClassRef) classOrInterfaceToTypeRef.apply(classOrInterfaceType));
        }
        for (BodyDeclaration bodyDeclaration : decl.getMembers()) {
            if (bodyDeclaration instanceof FieldDeclaration) {
                FieldDeclaration fieldDeclaration = (FieldDeclaration) bodyDeclaration;
                for (VariableDeclarator var : fieldDeclaration.getVariables()) {
                    TypeRef fieldDeclRef = typeToTypeRef.apply(fieldDeclaration.getType());
                    TypeRef typeRef = checkAgainstTypeParamRef(fieldDeclRef, parameters);
                    properties.add(new PropertyBuilder().withName(var.getId().getName()).withTypeRef(typeRef).withModifiers(fieldDeclaration.getModifiers()).addToAttributes(Attributeable.INIT, var.getInit() != null ? var.getInit().toStringWithoutComments() : null).build());
                }
            } else if (bodyDeclaration instanceof MethodDeclaration) {
                MethodDeclaration methodDeclaration = (MethodDeclaration) bodyDeclaration;
                List<Property> arguments = new ArrayList<Property>();
                List<ClassRef> exceptions = new ArrayList<ClassRef>();
                List<AnnotationRef> methodAnnotations = new ArrayList<AnnotationRef>();
                for (AnnotationExpr annotationExpr : methodDeclaration.getAnnotations()) {
                    methodAnnotations.add(ANNOTATIONREF.apply(annotationExpr));
                }
                for (ReferenceType referenceType : methodDeclaration.getThrows()) {
                    TypeRef exceptionRef = typeToTypeRef.apply(referenceType.getType());
                    if (exceptionRef instanceof ClassRef) {
                        exceptions.add((ClassRef) exceptionRef);
                    }
                }
                Boolean preferVarArg = false;
                for (Parameter parameter : methodDeclaration.getParameters()) {
                    List<AnnotationRef> paramAnnotations = new ArrayList<AnnotationRef>();
                    for (AnnotationExpr annotationExpr : parameter.getAnnotations()) {
                        paramAnnotations.add(ANNOTATIONREF.apply(annotationExpr));
                    }
                    TypeRef typeRef = typeToTypeRef.apply(parameter.getType());
                    if (parameter.isVarArgs()) {
                        preferVarArg = true;
                        typeRef = typeRef.withDimensions(typeRef.getDimensions() + 1);
                    }
                    arguments.add(new PropertyBuilder().withName(parameter.getId().getName()).withTypeRef(typeRef).withModifiers(parameter.getModifiers()).withAnnotations(paramAnnotations).build());
                }
                List<TypeParamDef> typeParamDefs = new ArrayList<TypeParamDef>();
                for (TypeParameter typeParameter : methodDeclaration.getTypeParameters()) {
                    typeParamDefs.add(typeParameterToTypeParamDef.apply(typeParameter));
                }
                TypeRef returnType = checkAgainstTypeParamRef(typeToTypeRef.apply(methodDeclaration.getType()), parameters);
                methods.add(new MethodBuilder().withName(methodDeclaration.getName()).withDefaultMethod(methodDeclaration.isDefault()).withModifiers(methodDeclaration.getModifiers()).withParameters(typeParamDefs).withVarArgPreferred(preferVarArg).withReturnType(returnType).withExceptions(exceptions).withArguments(arguments).withAnnotations(methodAnnotations).withBlock(BLOCK.apply(methodDeclaration.getBody())).build());
            } else if (bodyDeclaration instanceof ConstructorDeclaration) {
                ConstructorDeclaration constructorDeclaration = (ConstructorDeclaration) bodyDeclaration;
                List<Property> arguments = new ArrayList<Property>();
                List<ClassRef> exceptions = new ArrayList<ClassRef>();
                List<AnnotationRef> ctorAnnotations = new ArrayList<AnnotationRef>();
                for (AnnotationExpr annotationExpr : constructorDeclaration.getAnnotations()) {
                    ctorAnnotations.add(ANNOTATIONREF.apply(annotationExpr));
                }
                for (ReferenceType referenceType : constructorDeclaration.getThrows()) {
                    TypeRef exceptionRef = typeToTypeRef.apply(referenceType.getType());
                    exceptions.add((ClassRef) exceptionRef);
                }
                for (Parameter parameter : constructorDeclaration.getParameters()) {
                    List<AnnotationRef> ctorParamAnnotations = new ArrayList<AnnotationRef>();
                    for (AnnotationExpr annotationExpr : parameter.getAnnotations()) {
                        ctorParamAnnotations.add(ANNOTATIONREF.apply(annotationExpr));
                    }
                    TypeRef typeRef = checkAgainstTypeParamRef(typeToTypeRef.apply(parameter.getType()), parameters);
                    arguments.add(new PropertyBuilder().withName(parameter.getId().getName()).withTypeRef(typeRef).withModifiers(parameter.getModifiers()).withAnnotations(ctorParamAnnotations).build());
                }
                constructors.add(new MethodBuilder().withModifiers(constructorDeclaration.getModifiers()).withExceptions(exceptions).withArguments(arguments).withAnnotations(ctorAnnotations).withBlock(BLOCK.apply(constructorDeclaration.getBlock())).build());
            }
        }
        return context.getDefinitionRepository().register(new TypeDefBuilder().withKind(kind).withPackageName(PACKAGENAME.apply(type)).withName(decl.getName()).withModifiers(type.getModifiers()).withParameters(parameters).withExtendsList(extendsList).withImplementsList(implementsList).withProperties(properties).withMethods(methods).withConstructors(constructors).withAnnotations(annotations).addToAttributes(TypeDef.ALSO_IMPORT, IMPORTS.apply(type)).build());
    }
    if (type instanceof AnnotationDeclaration) {
        AnnotationDeclaration decl = (AnnotationDeclaration) type;
        Kind kind = Kind.ANNOTATION;
        List<Method> methods = new ArrayList<Method>();
        for (BodyDeclaration bodyDeclaration : decl.getMembers()) {
            if (bodyDeclaration instanceof AnnotationMemberDeclaration) {
                Map<AttributeKey, Object> attributes = new HashMap<>();
                AnnotationMemberDeclaration annotationMemberDeclaration = (AnnotationMemberDeclaration) bodyDeclaration;
                if (annotationMemberDeclaration.getDefaultValue() != null) {
                    attributes.put(Attributeable.DEFAULT_VALUE, annotationMemberDeclaration.getDefaultValue().toString());
                }
                TypeRef returnType = typeToTypeRef.apply(annotationMemberDeclaration.getType());
                methods.add(new MethodBuilder().withName(annotationMemberDeclaration.getName()).withModifiers(annotationMemberDeclaration.getModifiers()).withReturnType(returnType).withAttributes(attributes).build());
            }
        }
        List<AnnotationRef> annotations = new ArrayList<AnnotationRef>();
        for (AnnotationExpr annotationExpr : decl.getAnnotations()) {
            annotations.add(ANNOTATIONREF.apply(annotationExpr));
        }
        return context.getDefinitionRepository().register(new TypeDefBuilder().withKind(kind).withPackageName(PACKAGENAME.apply(type)).withName(decl.getName()).withModifiers(type.getModifiers()).withMethods(methods).withAnnotations(annotations).addToAttributes(TypeDef.ALSO_IMPORT, IMPORTS.apply(type)).build());
    }
    throw new IllegalArgumentException("Unsupported TypeDeclaration:[" + type + "].");
}
Also used : TypeParamDef(io.sundr.model.TypeParamDef) TypeParameter(com.github.javaparser.ast.TypeParameter) ClassRef(io.sundr.model.ClassRef) AnnotationExpr(com.github.javaparser.ast.expr.AnnotationExpr) ClassOrInterfaceDeclaration(com.github.javaparser.ast.body.ClassOrInterfaceDeclaration) HashMap(java.util.HashMap) TypeRef(io.sundr.model.TypeRef) ArrayList(java.util.ArrayList) ClassOrInterfaceType(com.github.javaparser.ast.type.ClassOrInterfaceType) TypeDefBuilder(io.sundr.model.TypeDefBuilder) FieldDeclaration(com.github.javaparser.ast.body.FieldDeclaration) ReferenceType(com.github.javaparser.ast.type.ReferenceType) MethodBuilder(io.sundr.model.MethodBuilder) VariableDeclarator(com.github.javaparser.ast.body.VariableDeclarator) ConstructorDeclaration(com.github.javaparser.ast.body.ConstructorDeclaration) Kind(io.sundr.model.Kind) ArrayList(java.util.ArrayList) List(java.util.List) Property(io.sundr.model.Property) AnnotationRef(io.sundr.model.AnnotationRef) PropertyBuilder(io.sundr.model.PropertyBuilder) MethodDeclaration(com.github.javaparser.ast.body.MethodDeclaration) Method(io.sundr.model.Method) AttributeKey(io.sundr.model.AttributeKey) AnnotationDeclaration(com.github.javaparser.ast.body.AnnotationDeclaration) Parameter(com.github.javaparser.ast.body.Parameter) TypeParameter(com.github.javaparser.ast.TypeParameter) BodyDeclaration(com.github.javaparser.ast.body.BodyDeclaration) AnnotationMemberDeclaration(com.github.javaparser.ast.body.AnnotationMemberDeclaration)

Aggregations

AttributeKey (io.sundr.model.AttributeKey)5 ClassRef (io.sundr.model.ClassRef)5 MethodBuilder (io.sundr.model.MethodBuilder)5 ArrayList (java.util.ArrayList)5 HashMap (java.util.HashMap)5 AnnotationRef (io.sundr.model.AnnotationRef)4 Method (io.sundr.model.Method)4 Property (io.sundr.model.Property)4 TypeParamDef (io.sundr.model.TypeParamDef)3 TypeRef (io.sundr.model.TypeRef)3 HashSet (java.util.HashSet)3 PropertyBuilder (io.sundr.model.PropertyBuilder)2 TypeDefBuilder (io.sundr.model.TypeDefBuilder)2 List (java.util.List)2 TypeParameter (com.github.javaparser.ast.TypeParameter)1 AnnotationDeclaration (com.github.javaparser.ast.body.AnnotationDeclaration)1 AnnotationMemberDeclaration (com.github.javaparser.ast.body.AnnotationMemberDeclaration)1 BodyDeclaration (com.github.javaparser.ast.body.BodyDeclaration)1 ClassOrInterfaceDeclaration (com.github.javaparser.ast.body.ClassOrInterfaceDeclaration)1 ConstructorDeclaration (com.github.javaparser.ast.body.ConstructorDeclaration)1