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.annotation; 018 019import static java.lang.annotation.ElementType.*; 020import static java.lang.annotation.RetentionPolicy.*; 021 022import java.lang.annotation.*; 023 024import org.apache.juneau.*; 025 026/** 027 * Maps constructor arguments to property names on beans with read-only properties. 028 * 029 * <p> 030 * Can be used in the following locations: 031 * <ul> 032 * <li>Bean constructors. 033 * <li><ja>@Rest</ja>-annotated classes and <ja>@RestOp</ja>-annotated methods when an {@link #on()} value is specified. 034 * </ul> 035 036 * <p> 037 * This annotation can be used in the case of beans with properties whose values can only be set by passing them in 038 * through a constructor on the class. 039 * <br>Since method parameter names are lost during compilation, this annotation essentially redefines them so that they 040 * are available at runtime. 041 * 042 * <p> 043 * This annotation can only be applied to constructors and can only be applied to one constructor per class. 044 * 045 * <p> 046 * When present, bean instantiation is delayed until the call to {@link BeanMap#getBean()}. 047 * Until then, bean property values are stored in a local cache until <c>getBean()</c> is called. 048 * Because of this additional caching step, parsing into read-only beans tends to be slower and use more memory than 049 * parsing into beans with writable properties. 050 * 051 * <p> 052 * Attempting to call {@link BeanMap#put(String,Object)} on a read-only property after calling {@link BeanMap#getBean()} 053 * will result in a {@link BeanRuntimeException} being thrown. 054 * Multiple calls to {@link BeanMap#getBean()} will return the same bean instance. 055 * 056 * <h5 class='section'>See Also:</h5><ul> 057 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/BeancAnnotation">@Beanc Annotation</a> 058 * </ul> 059 */ 060@Documented 061@Target({METHOD,TYPE,CONSTRUCTOR}) 062@Retention(RUNTIME) 063@Inherited 064@Repeatable(BeancAnnotation.Array.class) 065@ContextApply(BeancAnnotation.Applier.class) 066public @interface Beanc { 067 068 /** 069 * Optional description for the exposed API. 070 * 071 * @return The annotation value. 072 * @since 9.2.0 073 */ 074 String[] description() default {}; 075 076 /** 077 * Dynamically apply this annotation to the specified constructors. 078 * 079 * <p> 080 * Used in conjunction with {@link org.apache.juneau.BeanContext.Builder#applyAnnotations(Class...)} to dynamically apply an annotation to an existing constructor. 081 * It is ignored when the annotation is applied directly to constructors. 082 * 083 * <p> 084 * The following example shows this annotation in use: 085 * <p class='bjava'> 086 * <jc>// Our read-only bean.</jc> 087 * <jk>public class</jk> Person { 088 * <jk>private final</jk> String <jf>name</jf>; 089 * <jk>private final int</jk> <jf>age</jf>; 090 * 091 * <jk>public</jk> Person(String <jv>name</jv>, <jk>int</jk> <jv>age</jv>) { 092 * <jk>this</jk>.<jf>name</jf> = <jv>name</jv>; 093 * <jk>this</jk>.<jf>age</jf> = <jv>age</jv>; 094 * } 095 * 096 * <jc>// Read only properties.</jc> 097 * <jc>// Getters, but no setters.</jc> 098 * 099 * <jk>public</jk> String getName() { 100 * <jk>return</jk> <jf>name</jf>; 101 * } 102 * 103 * <jk>public int</jk> getAge() { 104 * <jk>return</jk> <jf>age</jf>; 105 * } 106 * } 107 * 108 * <ja>@BeanConfig</ja> 109 * <ja>@Beanc</ja>(on=<js>"Person(String,int)"</js>, properties=<js>"name,age"</js>)) 110 * <jk>public static class</jk> MyConfig {} 111 * </p> 112 * <p class='bjava'> 113 * <jc>// Parsing into a read-only bean.</jc> 114 * String <jv>json</jv> = <js>"{name:'John Smith',age:45}"</js>; 115 * Person <jv>person</jv> = JsonParser.<jsf>DEFAULT</jsf>.copy().applyAnnotations(MyConfig.<jk>class</jk>).build().parse(<jv>json</jv>); 116 * String <jv>name</jv> = <jv>person</jv>.getName(); <jc>// "John Smith"</jc> 117 * <jk>int</jk> <jv>age</jv> = <jv>person</jv>.getAge(); <jc>// 45</jc> 118 * </p> 119 * 120 * <h5 class='section'>Valid patterns:</h5> 121 * <ul class='spaced-list'> 122 * <li>Constructors: 123 * <ul> 124 * <li>Fully qualified with args: 125 * <ul> 126 * <li><js>"com.foo.MyClass(String,int)"</js> 127 * <li><js>"com.foo.MyClass(java.lang.String,int)"</js> 128 * <li><js>"com.foo.MyClass()"</js> 129 * </ul> 130 * <li>Simple with args: 131 * <ul> 132 * <li><js>"MyClass(String,int)"</js> 133 * <li><js>"MyClass(java.lang.String,int)"</js> 134 * <li><js>"MyClass()"</js> 135 * </ul> 136 * <li>Simple inner class: 137 * <ul> 138 * <li><js>"MyClass$Inner1$Inner2()"</js> 139 * <li><js>"Inner1$Inner2()"</js> 140 * <li><js>"Inner2()"</js> 141 * </ul> 142 * </ul> 143 * <li>A comma-delimited list of anything on this list. 144 * </ul> 145 * 146 * <h5 class='section'>See Also:</h5><ul> 147 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/DynamicallyAppliedAnnotations">Dynamically Applied Annotations</a> 148 * </ul> 149 * 150 * @return The annotation value. 151 */ 152 String[] on() default {}; 153 154 /** 155 * The names of the properties of the constructor arguments. 156 * 157 * <p> 158 * The {@link org.apache.juneau.annotation.Beanc @Beanc} annotation is used to map constructor arguments to property 159 * names on bean with read-only properties. 160 * <br>Since method parameter names are lost during compilation, this annotation essentially redefines them so that 161 * they are available at runtime. 162 * 163 * <p> 164 * The definition of a read-only bean is a bean with properties with only getters, like shown below: 165 * <p class='bjava'> 166 * <jc>// Our read-only bean.</jc> 167 * <jk>public class</jk> Person { 168 * <jk>private final</jk> String <jf>name</jf>; 169 * <jk>private final int</jk> <jf>age</jf>; 170 * 171 * <ja>@Beanc</ja>(properties=<js>"name,age"</js>) 172 * <jk>public</jk> Person(String <jv>name</jv>, <jk>int</jk> <jv>age</jv>) { 173 * <jk>this</jk>.<jf>name</jf> = <jv>name</jv>; 174 * <jk>this</jk>.<jf>age</jf> = <jv>age</jv>; 175 * } 176 * 177 * <jc>// Read only properties.</jc> 178 * <jc>// Getters, but no setters.</jc> 179 * 180 * <jk>public</jk> String getName() { 181 * <jk>return</jk> <jf>name</jf>; 182 * } 183 * 184 * <jk>public int</jk> getAge() { 185 * <jk>return</jk> <jf>age</jf>; 186 * } 187 * } 188 * </p> 189 * <p class='bjava'> 190 * <jc>// Parsing into a read-only bean.</jc> 191 * String <jv>json</jv> = <js>"{name:'John Smith',age:45}"</js>; 192 * Person <jv>person</jv> = JsonParser.<jsf>DEFAULT</jsf>.parse(<jv>json</jv>); 193 * String <jv>name</jv> = <jv>person</jv>.getName(); <jc>// "John Smith"</jc> 194 * <jk>int</jk> <jv>age</jv> = <jv>person</jv>.getAge(); <jc>// 45</jc> 195 * </p> 196 * <p> 197 * Note that the {@link Name @Name} annotation can also be used to identify bean property names on constructor 198 * arguments. If neither this annotation or {@link Name @Name} is used, then we try to get the property names 199 * from the parameter names if they are available in the bytecode. 200 * </p> 201 * 202 * @return The annotation value. 203 */ 204 String properties() default ""; 205}