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

io.micronaut.inject.configuration.ConfigurationMetadataBuilder Maven / Gradle / Ivy

There is a newer version: 4.7.5
Show newest version
/*
 * Copyright 2017-2020 original authors
 *
 * 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
 *
 * https://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.micronaut.inject.configuration;

import io.micronaut.context.annotation.ConfigurationReader;
import io.micronaut.core.annotation.AnnotationMetadata;
import io.micronaut.core.naming.NameUtils;
import io.micronaut.core.util.CollectionUtils;
import io.micronaut.core.annotation.NonNull;
import io.micronaut.core.annotation.Nullable;
import io.micronaut.inject.ast.Element;

import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

/**
 * 

A builder for producing metadata for the available {@link io.micronaut.context.annotation.ConfigurationProperties}.

*

*

This data can then be subsequently written to a format readable by IDEs * (like spring-configuration-metadata.json for example).

* * @param The type * @author Graeme Rocher * @since 1.0 */ public abstract class ConfigurationMetadataBuilder { private static ConfigurationMetadataBuilder currentBuilder = null; private final List properties = new ArrayList<>(); private final List configurations = new ArrayList<>(); /** * @return The originating elements for the builder. */ public abstract @NonNull Element[] getOriginatingElements(); /** * @return The properties */ public List getProperties() { return Collections.unmodifiableList(properties); } /** * @return The configurations */ public List getConfigurations() { return Collections.unmodifiableList(configurations); } /** * @return Whether any metadata is present */ public boolean hasMetadata() { return !properties.isEmpty() || !configurations.isEmpty(); } /** * Visit a {@link io.micronaut.context.annotation.ConfigurationProperties} class. * * @param type The type of the {@link io.micronaut.context.annotation.ConfigurationProperties} * @param description A description * @return This {@link ConfigurationMetadata} */ public ConfigurationMetadata visitProperties(T type, @Nullable String description) { AnnotationMetadata annotationMetadata = getAnnotationMetadata(type); return visitProperties(type, description, annotationMetadata); } /** * Visit a {@link io.micronaut.context.annotation.ConfigurationProperties} class. * * @param type The type of the {@link io.micronaut.context.annotation.ConfigurationProperties} * @param description A description * @param annotationMetadata the annotation metadata * @return This {@link ConfigurationMetadata} */ public ConfigurationMetadata visitProperties(T type, @Nullable String description, @NonNull AnnotationMetadata annotationMetadata) { String path = buildTypePath(type, type, annotationMetadata); ConfigurationMetadata configurationMetadata = new ConfigurationMetadata(); configurationMetadata.name = NameUtils.hyphenate(path, true); configurationMetadata.type = getTypeString(type); configurationMetadata.description = description; configurationMetadata.includes = CollectionUtils.setOf(annotationMetadata.stringValues(ConfigurationReader.class, "includes")); configurationMetadata.excludes = CollectionUtils.setOf(annotationMetadata.stringValues(ConfigurationReader.class, "excludes")); this.configurations.add(configurationMetadata); return configurationMetadata; } /** * Visit a configuration property. * * @param owningType The type that owns the property * @param declaringType The declaring type of the property * @param propertyType The property type * @param name The property name * @param description A description for the property * @param defaultValue The default value of the property (only used for constant values such as strings, numbers, * enums etc.) * @return This property metadata */ public PropertyMetadata visitProperty(T owningType, T declaringType, String propertyType, String name, @Nullable String description, @Nullable String defaultValue) { PropertyMetadata metadata = new PropertyMetadata(); metadata.declaringType = getTypeString(declaringType); metadata.name = name; metadata.path = NameUtils.hyphenate(buildPropertyPath(owningType, declaringType, name), true); metadata.type = propertyType; metadata.description = description; metadata.defaultValue = defaultValue; properties.add(metadata); return metadata; } /** * Visit a configuration property on the last declared properties instance. * * @param propertyType The property type * @param name The property name * @param description A description for the property * @param defaultValue The default value of the property (only used for constant values such as strings, numbers, * enums etc.) * @return This property metadata or null if no existing configuration is active */ public PropertyMetadata visitProperty(String propertyType, String name, @Nullable String description, @Nullable String defaultValue) { if (!configurations.isEmpty()) { ConfigurationMetadata last = configurations.get(configurations.size() - 1); PropertyMetadata metadata = new PropertyMetadata(); metadata.declaringType = last.type; metadata.name = name; metadata.path = NameUtils.hyphenate(last.name + "." + name, true); metadata.type = propertyType; metadata.description = description; metadata.defaultValue = defaultValue; properties.add(metadata); return metadata; } return null; } /** *

Build a property path for the given declaring type and property name.

*

*

For {@link io.micronaut.context.annotation.ConfigurationProperties} that path is a property is * established by looking at the value of the {@link io.micronaut.context.annotation.ConfigurationProperties} and * then calculating the path based on the inheritance tree.

*

*

For example consider the following classes:

*

*


     *  {@literal @}ConfigurationProperties("parent")
     *   public class ParentProperties {
     *      String foo;
     *   }
     *
     *  {@literal @}ConfigurationProperties("child")
     *   public class ChildProperties extends ParentProperties {
     *      String bar;
     *   }
     * 
*

*

The path of the property {@code foo} will be "parent.foo" whilst the path of the property {@code bar} will * be "parent.child.bar" factoring in the class hierarchy

*

*

Inner classes hierarchies are also taken into account

* * @param owningType The owning type * @param declaringType The declaring type * @param propertyName The property name * @return The property path */ protected abstract String buildPropertyPath(T owningType, T declaringType, String propertyName); /** * Variation of {@link #buildPropertyPath(Object, Object, String)} for types. * * @param owningType The owning type * @param declaringType The type * @return The type path */ protected abstract String buildTypePath(T owningType, T declaringType); /** * Variation of {@link #buildPropertyPath(Object, Object, String)} for types. * * @param owningType The owning type * @param declaringType The type * @param annotationMetadata The annotation metadata * @return The type path */ protected abstract String buildTypePath(T owningType, T declaringType, AnnotationMetadata annotationMetadata); /** * Convert the given type to a string. * * @param type The type * @return The string */ protected abstract String getTypeString(T type); /** * @param type The type * @return The annotation metadata for the type */ protected abstract AnnotationMetadata getAnnotationMetadata(T type); /** * Obtains the currently active metadata builder. * @return The builder */ public static Optional> getConfigurationMetadataBuilder() { return Optional.ofNullable(currentBuilder); } /** * Sets or clears the current {@link ConfigurationMetadataBuilder}. * @param builder the builder */ public static void setConfigurationMetadataBuilder(@Nullable ConfigurationMetadataBuilder builder) { currentBuilder = builder; } /** * Quote a string. * * @param string The string to quote * @return The quoted string */ @SuppressWarnings("MagicNumber") static String quote(String string) { if (string == null || string.length() == 0) { return "\"\""; } char c = 0; int i; int len = string.length(); StringBuilder sb = new StringBuilder(len + 4); String t; sb.append('"'); for (i = 0; i < len; i += 1) { c = string.charAt(i); switch (c) { case '\\': case '"': sb.append('\\'); sb.append(c); break; case '/': // if (b == '<') { sb.append('\\'); // } sb.append(c); break; case '\b': sb.append("\\b"); break; case '\t': sb.append("\\t"); break; case '\n': sb.append("\\n"); break; case '\f': sb.append("\\f"); break; case '\r': sb.append("\\r"); break; default: if (c < ' ') { t = "000" + Integer.toHexString(c); sb.append("\\u").append(t.substring(t.length() - 4)); } else { sb.append(c); } } } sb.append('"'); return sb.toString(); } /** * Write a quoted attribute with a value to a writer. * * @param out The out writer * @param name The name of the attribute * @param value The value * @throws IOException If an error occurred writing output */ static void writeAttribute(Writer out, String name, String value) throws IOException { out.write('"'); out.write(name); out.write("\":"); out.write(quote(value)); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy