001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.commons.inject; 018 019import static java.lang.annotation.ElementType.*; 020import static java.lang.annotation.RetentionPolicy.*; 021 022import java.lang.annotation.*; 023 024/** 025 * Declares a class as a prefix-scoped, whole-object config binding target — Juneau's analog of 026 * Spring's {@code @ConfigurationProperties}. 027 * 028 * <p> 029 * When a {@code @ConfigProperties}-annotated class is materialized through {@link BeanInstantiator}, 030 * its fields are populated from the {@link org.apache.juneau.commons.settings.Settings Settings} chain 031 * under {@link #prefix()} via {@link ConfigPropertiesBinder}, and the bound instance is auto-registered 032 * into the current {@link BeanStore}. 033 * 034 * <h5 class='section'>Binding order and lifecycle</h5> 035 * <p> 036 * The whole-object config bind runs <b>after</b> {@code @Value}/{@code @Inject} field-and-method injection and 037 * <b>before</b> any {@link PostConstruct @PostConstruct} method — so a 038 * {@code @PostConstruct} method observes the fully-bound config fields. Fields that are themselves annotated with 039 * {@code @Value} or {@code @Inject} are left to the injection engine and are never overwritten by config binding, 040 * even when a matching {@code prefix.fieldName} key exists. 041 * 042 * <h5 class='section'>Caller-scoped sources</h5> 043 * <p> 044 * The bind consults any {@link org.apache.juneau.commons.settings.PropertySource PropertySource}-typed beans in the 045 * active {@link BeanStore} <b>ahead of</b> the global {@link org.apache.juneau.commons.settings.Settings Settings} 046 * chain, so a caller can layer overriding or supplementary sources without mutating the shared 047 * {@code Settings.get()} singleton. 048 * 049 * <h5 class='section'>Not inherited</h5> 050 * <p> 051 * This annotation is <b>not</b> {@link java.lang.annotation.Inherited @Inherited}: the {@link BeanInstantiator} 052 * trigger fires only when the <i>exact declared type</i> being instantiated carries the annotation — a subclass or 053 * interface implementor of an annotated type does not itself trigger binding or auto-registration. 054 * 055 * <p> 056 * This is distinct from the {@link ConfigPropertiesBinder} <b>nested-field</b> detection, which <i>is</i> 057 * inheritance-aware: a field whose <i>declared type</i> is a subclass of an {@code @ConfigProperties}-annotated 058 * type still triggers nested binding under the enclosing type's prefix, since the annotation lookup there walks the 059 * declared field type's class hierarchy rather than requiring an exact-type match. 060 * 061 * <h5 class='section'>Example:</h5> 062 * <p class='bjava'> 063 * <ja>@ConfigProperties</ja>(prefix = <js>"MyService"</js>) 064 * <jk>public class</jk> MyServiceProperties { 065 * <jk>public</jk> String <jv>host</jv> = <js>"localhost"</js>; 066 * <jk>public int</jk> <jv>port</jv> = 8080; 067 * } 068 * </p> 069 * 070 * <p> 071 * {@code @ConfigProperties} and {@link Value @Value} coexist: {@code @Value} 072 * resolves a single value; {@code @ConfigProperties} resolves a whole object. A class can use 073 * {@code @Value} fields internally and separately be the target of another class's nested 074 * {@code @ConfigProperties} bind. 075 * 076 * <h5 class='section'>See Also:</h5><ul> 077 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/ConfigProperties">@ConfigProperties Annotation Basics</a> 078 * </ul> 079 * 080 * @since 10.0.0 081 */ 082@Documented 083@Target(TYPE) 084@Retention(RUNTIME) 085public @interface ConfigProperties { 086 087 /** 088 * The property-key prefix (no trailing dot). 089 * 090 * <p> 091 * Ignored when the annotated type appears as a nested field of another {@code @ConfigProperties} type — the 092 * enclosing type's prefix (extended with the field name) wins for the nested bind. 093 * 094 * @return The prefix. 095 */ 096 String prefix(); 097 098 /** 099 * Whether relaxed (camelCase / kebab-case / dotted / {@code SCREAMING_SNAKE_CASE}) key matching is enabled. 100 * 101 * <p> 102 * Ignored when the annotated type appears as a nested field of another {@code @ConfigProperties} type — the 103 * enclosing type's {@code relaxed} flag wins for the nested bind. 104 * 105 * @return <jk>true</jk> if relaxed matching is enabled. Defaults to <jk>true</jk>. 106 */ 107 boolean relaxed() default true; 108}