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.marshall; 018 019import static java.lang.annotation.ElementType.*; 020import static java.lang.annotation.RetentionPolicy.*; 021 022import java.lang.annotation.*; 023 024/** 025 * Identifies a setter method or field for adding a parent reference to a child object. 026 * 027 * <p> 028 * This annotation is used by parsers to automatically establish parent-child relationships when parsing 029 * nested objects. When a child object is created within a parent object (e.g., in a list or as a property), 030 * the parser automatically sets the parent reference on the child. 031 * 032 * <h5 class='section'>Requirements:</h5> 033 * <ul class='spaced-list'> 034 * <li>Must be an <strong>instance</strong> method or field (not static) 035 * <li>For methods: Must accept exactly one parameter (the parent object type) 036 * <li>For fields: Can be any type (typically the parent object type) 037 * <li>The method or field does not need to be public (will be made accessible automatically) 038 * </ul> 039 * 040 * <p> 041 * Can be used in the following locations: 042 * <ul> 043 * <li>Bean setter methods or fields 044 * <li><ja>@Rest</ja>-annotated classes and <ja>@RestOp</ja>-annotated methods when used with {@link ParentPropertyApply @ParentPropertyApply} 045 * </ul> 046 * 047 * <h5 class='section'>Example:</h5> 048 * <p class='bjava'> 049 * <jk>public class</jk> AddressBook { 050 * <jk>public</jk> List<Person> people; 051 * } 052 * 053 * <jk>public class</jk> Person { 054 * <ja>@ParentProperty</ja> 055 * <jk>public</jk> AddressBook addressBook; <jc>// Automatically set to the enclosing AddressBook (the intervening List is skipped).</jc> 056 * 057 * <jk>public</jk> String name; 058 * <jk>public</jk> <jk>char</jk> sex; 059 * } 060 * 061 * <jc>// Or using a setter method:</jc> 062 * <jk>public class</jk> Person { 063 * <jk>private</jk> AddressBook parent; 064 * 065 * <ja>@ParentProperty</ja> 066 * <jk>protected void</jk> setParent(AddressBook <jv>parent</jv>) { 067 * <jk>this</jk>.parent = <jv>parent</jv>; 068 * } 069 * 070 * <jk>public</jk> String name; 071 * <jk>public</jk> <jk>char</jk> sex; 072 * } 073 * </p> 074 * 075 * <h5 class='section'>When It's Called:</h5> 076 * <ul class='spaced-list'> 077 * <li>During parsing when a child object is created within a parent object 078 * <li>The parser automatically calls the setter or sets the field with a reference to the parent object 079 * <li>This allows child objects to navigate back to their parent if needed 080 * </ul> 081 * 082 * <h5 class='section'>Parent resolution through collections and maps:</h5> 083 * <ul class='spaced-list'> 084 * <li>A collection/map element's <ja>@ParentProperty</ja> is set to the nearest enclosing bean, skipping any 085 * intervening collections, maps, or arrays. In the example above, each <c>Person</c> lives inside a 086 * <c>List<Person></c>, yet its <c>addressBook</c> back-reference receives the enclosing <c>AddressBook</c> 087 * bean, not the <c>List</c>. The same holds through arbitrarily deep nesting 088 * (e.g. <c>List<List<Person>></c>, <c>Map<String,List<Person>></c>). 089 * <li>A bean at the document root (or directly inside a top-level collection) has no enclosing bean, so its 090 * <ja>@ParentProperty</ja> is left <jk>null</jk>. 091 * </ul> 092 * 093 * <h5 class='section'>Cyclic graphs and serialization:</h5> 094 * <ul class='spaced-list'> 095 * <li>When a <ja>@ParentProperty</ja> back-reference is also a normally-visible bean property (e.g. a <jk>public</jk> 096 * field or getter, as in the example above), it forms a parent-to-child/child-to-parent <b>cycle</b>. Unlike 097 * Jackson's <c>@JsonBackReference</c>, Juneau does <b>not</b> auto-omit the <ja>@ParentProperty</ja> member on the 098 * write (serialize) side — the annotation is a parse-time convenience only. This is intentional. 099 * <li>Under the <b>default</b> serializer configuration (<c>detectRecursions=<jk>false</jk></c>, 100 * <c>ignoreRecursions=<jk>false</jk></c>), serializing such a cyclic graph produces <b>finite but 101 * semantically-incomplete</b> output: the traversal is silently truncated at 102 * {@link MarshallingTraverseContext.Builder#maxDepth(int) maxDepth} (default <c>100</c>). No exception is thrown — 103 * <c>maxDepth</c> is a size guard, not a cycle detector. 104 * <li>To fail-fast on cycles with a clear error, enable 105 * {@link MarshallingTraverseContext.Builder#detectRecursions() detectRecursions} — a 106 * {@link MarshallingRecursionException} (surfaced as a serialize exception) is thrown. 107 * <li>To omit the back-reference and round-trip cleanly, enable 108 * {@link MarshallingTraverseContext.Builder#ignoreRecursions() ignoreRecursions} — the repeated node is emitted as 109 * <jk>null</jk>, and parsing re-injects the parent via this annotation. 110 * </ul> 111 * 112 * <p> 113 * Putting it together, the <c>AddressBook</c>/<c>List<Person></c> graph above round-trips cleanly when the 114 * back-reference is omitted on serialize and re-injected on parse: 115 * <p class='bjava'> 116 * Serializer <jv>serializer</jv> = JsonSerializer.<jsm>create</jsm>().ignoreRecursions().build(); 117 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jv>addressBook</jv>); 118 * AddressBook <jv>parsed</jv> = JsonParser.<jsf>DEFAULT</jsf>.parse(<jv>json</jv>, AddressBook.<jk>class</jk>); 119 * Person <jv>person</jv> = <jv>parsed</jv>.people.get(0); 120 * <jsm>assertTrue</jsm>(<jv>person</jv>.addressBook == <jv>parsed</jv>); <jc>// Parent re-injected through the List.</jc> 121 * </p> 122 * 123 * <h5 class='section'>See Also:</h5><ul> 124 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/ParentPropertyAnnotation">@ParentProperty Annotation</a> 125 126 * </ul> 127 */ 128@Target({ METHOD, FIELD }) 129@Retention(RUNTIME) 130@Inherited 131public @interface ParentProperty { 132 133 /** 134 * Optional description for the exposed API. 135 * 136 * @return The annotation value. 137 * @since 9.2.0 138 */ 139 String[] description() default {}; 140 141}