1 /* 2 * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.tools.internal.xjc.generator.bean.field; 27 28 import java.util.ArrayList; 29 import java.util.List; 30 31 import com.sun.codemodel.internal.JBlock; 32 import com.sun.codemodel.internal.JClass; 33 import com.sun.codemodel.internal.JExpr; 34 import com.sun.codemodel.internal.JExpression; 35 import com.sun.codemodel.internal.JMethod; 36 import com.sun.codemodel.internal.JType; 37 import com.sun.codemodel.internal.JVar; 38 import com.sun.tools.internal.xjc.generator.bean.ClassOutlineImpl; 39 import com.sun.tools.internal.xjc.generator.bean.MethodWriter; 40 import com.sun.tools.internal.xjc.model.CPropertyInfo; 41 import com.sun.tools.internal.xjc.outline.Aspect; 42 import com.sun.xml.internal.bind.api.impl.NameConverter; 43 import java.io.Serializable; 44 45 /** 46 * Realizes a property as an untyped {@link List}. 47 * 48 * <pre> 49 * List getXXX(); 50 * </pre> 51 * 52 * <h2>Default value handling</h2> 53 * <p> 54 * Since unmarshaller just adds new values into the storage, 55 * we can't fill the storage by default values at the time of 56 * instanciation. (or oherwise values found in the document will 57 * be appended to default values, where it should overwrite them.) 58 * <p> 59 * Therefore, when the object is created, the storage will be empty. 60 * When the getXXX method is called, we'll check if the storage is 61 * modified in anyway. If it is modified, it must mean that the values 62 * are found in the document, so we just return it. 63 * 64 * Otherwise we will fill in default values and return it to the user. 65 * 66 * <p> 67 * When a list has default values, its dirty flag is set to true. 68 * Marshaller will check this and treat it appropriately. 69 * 70 * 71 * @author 72 * Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com) 73 */ 74 public class ContentListField extends AbstractListField { 75 76 /** 77 * A concrete class that implements the List interface. 78 * An instance of this class will be used to store data 79 * for this field. 80 */ 81 private final JClass coreList; 82 83 /** List getFIELD() method. */ 84 private JMethod $get; 85 86 /** 87 * @param coreList 88 * A concrete class that implements the List interface. 89 * An instance of this class will be used to store data 90 * for this field. 91 */ 92 protected ContentListField(ClassOutlineImpl context, CPropertyInfo prop, JClass coreList) { 93 // the JAXB runtime picks ArrayList if the signature is List, 94 // so don't do eager allocation if it's ArrayList. 95 // otherwise we need to do eager allocation so that the collection type specified by the user 96 // will be used. 97 super(context, prop, false); 98 this.coreList = coreList; 99 generate(); 100 } 101 102 protected final JClass getCoreListType() { 103 return coreList; 104 } 105 106 @Override 107 public void generateAccessors() { 108 final MethodWriter writer = outline.createMethodWriter(); 109 final Accessor acc = create(JExpr._this()); 110 111 // [RESULT] 112 // List getXXX() { 113 // return <ref>; 114 // } 115 $get = writer.declareMethod(listT,"get"+prop.getName(true)); 116 writer.javadoc().append(prop.javadoc); 117 JBlock block = $get.body(); 118 fixNullRef(block); // avoid using an internal getter 119 block._return(acc.ref(true)); 120 121 String pname = NameConverter.standard.toVariableName(prop.getName(true)); 122 writer.javadoc().append( 123 "Gets the value of the "+pname+" property.\n\n"+ 124 "<p>\n" + 125 "This accessor method returns a reference to the live list,\n" + 126 "not a snapshot. Therefore any modification you make to the\n" + 127 "returned list will be present inside the JAXB object.\n" + 128 "This is why there is not a <CODE>set</CODE> method for the " +pname+ " property.\n" + 129 "\n"+ 130 "<p>\n" + 131 "For example, to add a new item, do as follows:\n"+ 132 "<pre>\n"+ 133 " get"+prop.getName(true)+"().add(newItem);\n"+ 134 "</pre>\n"+ 135 "\n\n" 136 ); 137 138 writer.javadoc().append( 139 "<p>\n" + 140 "Objects of the following type(s) are allowed in the list\n") 141 .append(listPossibleTypes(prop)); 142 } 143 144 public Accessor create(JExpression targetObject) { 145 return new Accessor(targetObject); 146 } 147 148 class Accessor extends AbstractListField.Accessor { 149 protected Accessor( JExpression $target ) { 150 super($target); 151 } 152 153 public void toRawValue(JBlock block, JVar $var) { 154 // [RESULT] 155 // $<var>.addAll(bean.getLIST()); 156 // list.toArray( array ); 157 block.assign($var,JExpr._new(codeModel.ref(ArrayList.class).narrow(exposedType.boxify())).arg( 158 $target.invoke($get) 159 )); 160 } 161 162 public void fromRawValue(JBlock block, String uniqueName, JExpression $var) { 163 // [RESULT] 164 // bean.getLIST().addAll($<var>); 165 JVar $list = block.decl(listT,uniqueName+'l',$target.invoke($get)); 166 block.invoke($list,"addAll").arg($var); 167 } 168 } 169 170 @Override 171 protected JType getType(final Aspect aspect) { 172 if (Aspect.IMPLEMENTATION.equals(aspect)) { 173 return super.getType(aspect); 174 } 175 return codeModel.ref(Serializable.class); 176 } 177 }