All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.helidon.codegen.classmodel.Annotation Maven / Gradle / Ivy

Go to download

Class model generator designed to be used by code generating components (annotation processors, maven plugins)

The newest version!
/*
 * Copyright (c) 2023, 2024 Oracle and/or its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.helidon.codegen.classmodel;

import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer;

import io.helidon.common.types.TypeName;

/**
 * Model of the annotation.
 */
public final class Annotation extends CommonComponent {

    private final List parameters;

    private Annotation(Builder builder) {
        super(builder);
        this.parameters = List.copyOf(builder.parameters.values());
    }

    /**
     * New {@link Builder} instance.
     *
     * @return new builder instance
     */
    public static Builder builder() {
        return new Builder();
    }

    /**
     * New {@link Annotation} instance based on the type.
     *
     * @param type class type
     * @return new annotation instance
     */
    public static Annotation create(Class type) {
        return builder().type(type).build();
    }

    /**
     * Parse new Annotation object out of the String.
     *
     * @param annotationDefinition annotation definition
     * @return new annotation instance
     */
    public static Annotation parse(String annotationDefinition) {
        int annotationBodyStart = annotationDefinition.indexOf("(");
        int annotationBodyEnd = annotationDefinition.indexOf(")");
        String annotationName = annotationBodyStart > 0
                ? annotationDefinition.substring(0, annotationBodyStart)
                : annotationDefinition;
        Annotation.Builder builder = Annotation.builder()
                .type(annotationName);
        if (annotationBodyStart > 0) {
            //TODO this needs to be improved in cases where chars , or = are part of the String value
            String[] valuePairs = annotationDefinition.substring(annotationBodyStart + 1, annotationBodyEnd).split(",");
            for (String valuePair : valuePairs) {
                String[] keyValue = valuePair.split("=");
                if (keyValue.length == 1 && valuePairs.length != 1) {
                    throw new IllegalStateException("Invalid custom annotation specified: " + annotationDefinition);
                }
                String key = keyValue[0].trim();
                String value = keyValue[1].trim();
                builder.addParameter(paramBuilder -> paramBuilder.name(key)
                        .type(value.startsWith("\"") ? String.class : Object.class)
                        .value(value));
            }
        }
        return builder.build();
    }

    @Override
    void writeComponent(ModelWriter writer, Set declaredTokens, ImportOrganizer imports, ClassType classType)
            throws IOException {
        writer.write("@" + imports.typeName(type(), includeImport()));
        if (!parameters.isEmpty()) {
            writer.write("(");
            if (parameters.size() == 1) {
                AnnotationParameter parameter = parameters.get(0);
                if (parameter.name().equals("value")) {
                    parameter.writeValue(writer, imports);
                } else {
                    parameter.writeComponent(writer, declaredTokens, imports, classType);
                }
            } else {
                boolean first = true;
                for (AnnotationParameter parameter : parameters) {
                    if (first) {
                        first = false;
                    } else {
                        writer.write(", ");
                    }
                    parameter.writeComponent(writer, declaredTokens, imports, classType);
                }
            }
            writer.write(")");
        }
    }

    @Override
    void addImports(ImportOrganizer.Builder imports) {
        super.addImports(imports);
        parameters.forEach(parameter -> parameter.addImports(imports));
    }

    /**
     * Fluent API builder for {@link Annotation}.
     */
    public static final class Builder extends CommonComponent.Builder {

        private final Map parameters = new LinkedHashMap<>();

        private Builder() {
        }

        @Override
        public Annotation build() {
            if (type() == null) {
                throw new ClassModelException("Annotation type needs to be set");
            }
            return new Annotation(this);
        }

        @Override
        public Builder type(TypeName type) {
            return super.type(type);
        }

        @Override
        public Builder type(String type) {
            return super.type(type);
        }

        @Override
        public Builder type(Class type) {
            return super.type(type);
        }

        /**
         * Adds annotation parameter.
         *
         * @param name  annotation parameter name
         * @param value parameter value
         * @return updated builder instance
         */
        public Builder addParameter(String name, Object value) {
            Objects.requireNonNull(value);

            Class paramType = value instanceof TypeName
                    ? Class.class
                    : value.getClass();

            return addParameter(builder -> builder.name(name)
                    .type(paramType)
                    .value(value));
        }

        /**
         * Adds annotation parameter.
         *
         * @param consumer annotation parameter builder consumer
         * @return updated builder instance
         */
        public Builder addParameter(Consumer consumer) {
            Objects.requireNonNull(consumer);
            AnnotationParameter.Builder builder = AnnotationParameter.builder();
            consumer.accept(builder);
            return addParameter(builder.build());
        }

        /**
         * Adds annotation parameter.
         *
         * @param builder annotation parameter builder
         * @return updated builder instance
         */
        public Builder addParameter(AnnotationParameter.Builder builder) {
            Objects.requireNonNull(builder);
            return addParameter(builder.build());
        }

        /**
         * Adds annotation parameter.
         *
         * @param parameter annotation parameter
         * @return updated builder instance
         */
        public Builder addParameter(AnnotationParameter parameter) {
            Objects.requireNonNull(parameter);
            parameters.put(parameter.name(), parameter);
            return this;
        }

    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy