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.bean; 018 019import static java.lang.annotation.ElementType.*; 020import static java.lang.annotation.RetentionPolicy.*; 021 022import java.lang.annotation.*; 023import java.util.*; 024import java.util.stream.*; 025 026import org.apache.juneau.commons.function.*; 027import org.apache.juneau.commons.inject.*; 028 029/** 030 * Annotation that can be applied to bean fields, getter/setter methods, and constructor parameters 031 * to control bean introspection and property modeling. 032 * 033 * <p> 034 * The bean-modeling sibling of {@code @MarshalledProp}. 035 * Where {@code @MarshalledProp} (in <c>juneau-marshall</c>) carries the marshalling-only attributes 036 * (such as {@code dictionary}, {@code format}, and {@code properties}), this annotation carries the 037 * attributes that describe the bean property itself — its name, accessibility (read/write only), 038 * concrete type, generic type parameters, element type, and the bean factory used to instantiate 039 * its value. 040 * 041 * <p> 042 * Splitting the annotations lets a property participate in the bean model (for example, to declare 043 * its name or read-only semantics) without dragging in any marshalling concerns, and lets the 044 * bean-modeling layer live in <c>juneau-commons</c> independent of <c>juneau-marshall</c>. 045 * 046 * <p> 047 * Can be used in the following locations: 048 * <ul> 049 * <li>Bean fields, getter methods, and setter methods. 050 * <li>Constructor parameters. 051 * </ul> 052 * 053 * <h5 class='section'>See Also:</h5><ul> 054 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/BeanPropAnnotation">@BeanProp Annotation</a> 055 * </ul> 056 */ 057@Documented 058@Target({ FIELD, METHOD, PARAMETER }) 059@Retention(RUNTIME) 060@Inherited 061public @interface BeanProp { 062 063 /** 064 * Optional description for the exposed API. 065 * 066 * @return The annotation value. 067 * @since 9.2.0 068 */ 069 String[] description() default {}; 070 071 /** 072 * Short, concise summary of the exposed API. 073 * 074 * <p> 075 * Intended as a brief, single-line description suitable for AI/LLM consumption, compact documentation, 076 * or any context where brevity matters. See {@link org.apache.juneau.commons.Schema#summary()} 077 * for the canonical definition; this field is the bean-property-level counterpart. 078 * 079 * @return The annotation value. 080 * @since 10.0.0 081 */ 082 String summary() default ""; 083 084 /** 085 * Element type for streaming/consuming bean properties. 086 * 087 * <p> 088 * Specifies the element type for properties of type {@link Stream}, 089 * {@link BeanSupplier}, 090 * {@link BeanConsumer}, or 091 * {@link BeanChannel} when type erasure prevents 092 * the framework from inferring the generic type argument at runtime. 093 * 094 * <p> 095 * This attribute also supports: 096 * <ul> 097 * <li><b>Narrowing</b> - Specify a more specific subtype than the declared type 098 * <li><b>Concrete implementation</b> - Specify a concrete class for an abstract/interface element type 099 * </ul> 100 * 101 * <h5 class='section'>Example:</h5> 102 * <p class='bjava'> 103 * <jk>public class</jk> OrderCollection { 104 * <jc>// Stream property - element type cannot be inferred at runtime due to erasure</jc> 105 * <ja>@BeanProp</ja>(elementType=Order.<jk>class</jk>) 106 * <jk>public</jk> Stream<Order> getOrders() { ... } 107 * 108 * <jc>// BeanChannel with concrete impl specified instead of abstract element type</jc> 109 * <ja>@BeanProp</ja>(elementType=ConcreteItem.<jk>class</jk>) 110 * <jk>public</jk> BeanChannel<AbstractItem> getItems() { ... } 111 * } 112 * </p> 113 * 114 * <h5 class='section'>See Also:</h5><ul> 115 * <li class='jc'>{@link BeanSupplier} 116 * <li class='jc'>{@link BeanConsumer} 117 * <li class='jc'>{@link BeanChannel} 118 * </ul> 119 * 120 * @return The annotation value. 121 */ 122 Class<?> elementType() default void.class; 123 124 /** 125 * Bean factory class for this property's value. 126 * 127 * <p> 128 * Specifies a {@link BeanFactory} class to use when instantiating 129 * the value of this specific bean property, overriding the class-level {@link BeanType#factory()} if present. 130 * 131 * <p> 132 * When a factory class is specified, the framework resolves it in the following order: 133 * <ol> 134 * <li>Look up the factory class in the configured {@link BeanStore} 135 * <li>Attempt direct instantiation via no-arg constructor or {@code getInstance()} static method 136 * <li>Throw {@link IllegalArgumentException} if both fail 137 * </ol> 138 * 139 * <h5 class='section'>Example:</h5> 140 * <p class='bjava'> 141 * <jk>public class</jk> MyBean { 142 * <ja>@BeanProp</ja>(factory=ItemChannelFactory.<jk>class</jk>, elementType=Item.<jk>class</jk>) 143 * <jk>public</jk> BeanChannel<Item> getItems() { ... } 144 * } 145 * </p> 146 * 147 * <h5 class='section'>See Also:</h5><ul> 148 * <li class='jc'>{@link BeanFactory} 149 * <li class='ja'>{@link BeanType#factory()} 150 * </ul> 151 * 152 * @return The annotation value. 153 */ 154 @SuppressWarnings({ 155 "rawtypes" // Raw BeanFactory type required for annotation attribute declaration 156 }) 157 Class<? extends BeanFactory> factory() default BeanFactory.Void.class; 158 159 /** 160 * Identifies the name of the property. 161 * 162 * <p> 163 * Normally, this is automatically inferred from the field name or getter method name of the property. 164 * However, this property can be used to assign a different property name from the automatically inferred value. 165 * 166 * <h5 class='topic'>Dynamic beans</h5> 167 * <p> 168 * On a <strong>field</strong> whose type is not a {@link Map}, <js>"*"</js> does not create a dynamic property: 169 * the property name is the field name (same as omitting {@code name}/{@code value}), while other attributes on 170 * this annotation still apply. 171 * </p> 172 * <p> 173 * The bean property named <js>"*"</js> is the designated "dynamic property" which allows for "extra" bean 174 * properties not otherwise defined. 175 * 176 * <p> 177 * The following examples show how to define dynamic bean properties. 178 * <p class='bjava'> 179 * <jc>// Option #1 - A simple public Map field. 180 * // The field name can be anything.</jc> 181 * <jk>public class</jk> BeanWithDynaField { 182 * 183 * <ja>@BeanProp</ja>(name=<js>"*"</js>) 184 * <jk>public</jk> Map<String,Object> <jf>extraStuff</jf> = <jk>new</jk> LinkedHashMap<>(); 185 * } 186 * 187 * <jc>// Option #2 - Getters and setters. 188 * // Method names can be anything. 189 * // Getter must return a Map with String keys. 190 * // Setter must take in two arguments.</jc> 191 * <jk>public class</jk> BeanWithDynaMethods { 192 * 193 * <ja>@BeanProp</ja>(name=<js>"*"</js>) 194 * <jk>public</jk> Map<String,Object> getMyExtraStuff() { 195 * ... 196 * } 197 * 198 * <ja>@BeanProp</ja>(name=<js>"*"</js>) 199 * <jk>public void</jk> setAnExtraField(String <jv>name</jv>, Object <jv>value</jv>) { 200 * ... 201 * } 202 * } 203 * </p> 204 * 205 * <div class='info'> 206 * Note that the {@link Name @Name} annotation can also be used for identifying a property name. 207 * </div> 208 * 209 * @return The annotation value. 210 */ 211 String name() default ""; 212 213 /** 214 * For bean properties of maps and collections, this annotation can be used to identify the class types of the 215 * contents of the bean property object when the generic parameter types are interfaces or abstract classes. 216 * 217 * <h5 class='section'>Example:</h5> 218 * <p class='bjava'> 219 * <jk>public class</jk> MyBean { 220 * 221 * <jc>// Identify concrete map type with String keys and Integer values.</jc> 222 * <ja>@BeanProp</ja>(type=HashMap.<jk>class</jk>, params={String.<jk>class</jk>,Integer.<jk>class</jk>}) 223 * <jk>public</jk> Map <jf>p1</jf>; 224 * } 225 * </p> 226 * 227 * @return The annotation value. 228 */ 229 Class<?>[] params() default {}; 230 231 /** 232 * Marks this property as required on input. 233 * 234 * <p> 235 * When <jk>true</jk>, parsers (and {@code Map}-to-bean conversion) throw a 236 * {@code org.apache.juneau.marshall.parser.MissingRequiredPropertyException} if the input does not contain this 237 * property. The check runs once per bean, before the bean is constructed, so records and constructor-argument 238 * beans get a clear error instead of a constructor failure. 239 * 240 * <p> 241 * "Present" means the key appears in the input. An explicit <jk>null</jk> value counts as present; use your own 242 * validation (or a compact record constructor) to reject null values. 243 * 244 * <p> 245 * The flag is OR-merged across the field, getter and setter: annotating any one of them makes the property required. 246 * Wrapping an existing object (for example {@code MarshallingSession.toBeanMap(Object)}) never checks. 247 * 248 * <p> 249 * This attribute is independent of {@code @Schema(required)}, which only affects generated schema documentation and 250 * HTTP part validation. 251 * 252 * <h5 class='section'>Example:</h5> 253 * <p class='bjava'> 254 * <jk>public record</jk> Person(<ja>@BeanProp</ja>(required=<jk>true</jk>) String <jv>name</jv>, Integer <jv>age</jv>) {} 255 * 256 * <jc>// Throws MissingRequiredPropertyException: 257 * // Missing required properties on bean class 'Person': [name]</jc> 258 * JsonParser.<jsf>DEFAULT</jsf>.read(<js>"{\"age\":30}"</js>, Person.<jk>class</jk>); 259 * 260 * <jc>// OK: explicit null counts as present.</jc> 261 * JsonParser.<jsf>DEFAULT</jsf>.read(<js>"{\"name\":null}"</js>, Person.<jk>class</jk>); 262 * </p> 263 * 264 * <h5 class='section'>Notes:</h5><ul> 265 * <li class='note'> 266 * A required property must be writable (a field, setter or constructor argument). Marking a read-only 267 * property required fails when the bean metadata is built. 268 * <li class='note'> 269 * For builder-based beans, put the annotation on the builder's setter. 270 * <li class='note'> 271 * On a non-record bean, put the annotation on the field or getter; it is not read from constructor parameters. 272 * <li class='note'> 273 * In REST methods, a missing required property in an {@code @Content} body produces <c>400 Bad Request</c>. 274 * </ul> 275 * 276 * @return <jk>true</jk> if this property must be present in the input. 277 */ 278 boolean required() default false; 279 280 /** 281 * Identifies a property as read-only. 282 * 283 * <p> 284 * Serializers will serialize such properties as usual, but parsers will silently ignore them. 285 * 286 * <h5 class='section'>Example:</h5> 287 * <p class='bjava'> 288 * <jk>public class</jk> MyBean { 289 * <ja>@BeanProp</ja>(ro=<js>"true"</js>) 290 * <jk>public float</jk> <jf>price</jf>; 291 * } 292 * </p> 293 * 294 * <h5 class='section'>Notes:</h5><ul> 295 * <li class='note'> 296 * <b>Java Records:</b> Marking record components as read-only is not supported during parsing. 297 * Because records are immutable, all components must be provided to the canonical constructor. 298 * Read-only components will be serialized as usual, but the parser will be unable to instantiate the 299 * record if the read-only component values are missing from the input. 300 * </ul> 301 * 302 * @return The annotation value. 303 */ 304 String ro() default ""; 305 306 /** 307 * Identifies a specialized class type for the property. 308 * 309 * <p> 310 * Normally this can be inferred through reflection of the field type or getter return type. 311 * However, you'll want to specify this value if you're parsing beans where the bean property class is an interface 312 * or abstract class to identify the bean type to instantiate. 313 * Otherwise, you may cause an {@link InstantiationException} when trying to set these fields. 314 * 315 * <p> 316 * This property must denote a concrete bean class with a no-arg constructor. 317 * 318 * <h5 class='section'>Example:</h5> 319 * <p class='bjava'> 320 * <jk>public class</jk> MyBean { 321 * 322 * <jc>// Identify concrete map type.</jc> 323 * <ja>@BeanProp</ja>(type=HashMap.<jk>class</jk>) 324 * <jk>public</jk> Map <jf>p1</jf>; 325 * } 326 * </p> 327 * 328 * @return The annotation value. 329 */ 330 Class<?> type() default void.class; 331 332 /** 333 * A synonym for {@link #name()}. 334 * 335 * <p> 336 * The following annotations are equivalent: 337 * 338 * <p class='bjava'> 339 * <ja>@BeanProp</ja>(name=<js>"foo"</js>) 340 * 341 * <ja>@BeanProp</ja>(<js>"foo"</js>) 342 * </p> 343 * 344 * @return The annotation value. 345 */ 346 String value() default ""; 347 348 /** 349 * Identifies a property as write-only. 350 * 351 * <p> 352 * Parsers will parse such properties as usual, but serializers will silently ignore them. 353 * 354 * <h5 class='section'>Example:</h5> 355 * <p class='bjava'> 356 * <jk>public class</jk> MyBean { 357 * <ja>@BeanProp</ja>(wo=<js>"true"</js>) 358 * <jk>public float</jk> <jf>price</jf>; 359 * } 360 * </p> 361 * 362 * @return The annotation value. 363 */ 364 String wo() default ""; 365}