1 /* 2 * Copyright (c) 1997, 2012, 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.JVar; 37 import com.sun.tools.internal.xjc.generator.bean.ClassOutlineImpl; 38 import com.sun.tools.internal.xjc.generator.bean.MethodWriter; 39 import com.sun.tools.internal.xjc.model.CPropertyInfo; 40 import com.sun.xml.internal.bind.api.impl.NameConverter; 41 42 /** 43 * Realizes a property as an untyped {@link List}. 44 * 45 * <pre> 46 * List getXXX(); 47 * </pre> 48 * 49 * <h2>Default value handling</h2> 50 * <p> 51 * Since unmarshaller just adds new values into the storage, 52 * we can't fill the storage by default values at the time of 53 * instanciation. (or oherwise values found in the document will 54 * be appended to default values, where it should overwrite them.) 55 * <p> 56 * Therefore, when the object is created, the storage will be empty. 57 * When the getXXX method is called, we'll check if the storage is 58 * modified in anyway. If it is modified, it must mean that the values 59 * are found in the document, so we just return it. 60 * 61 * Otherwise we will fill in default values and return it to the user. 62 * 63 * <p> 64 * When a list has default values, its dirty flag is set to true. 65 * Marshaller will check this and treat it appropriately. 66 * 67 * 68 * @author 69 * Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com) 70 */ 71 public class UntypedListField extends AbstractListField { 72 73 /** 74 * A concrete class that implements the List interface. 75 * An instance of this class will be used to store data 76 * for this field. 77 */ 78 private final JClass coreList; 79 80 81 /** List getFIELD() method. */ 82 private JMethod $get; 83 84 /** 85 * @param coreList 86 * A concrete class that implements the List interface. 87 * An instance of this class will be used to store data 88 * for this field. 89 */ 90 protected UntypedListField(ClassOutlineImpl context, CPropertyInfo prop, JClass coreList) { 91 // the JAXB runtime picks ArrayList if the signature is List, 92 // so don't do eager allocation if it's ArrayList. 93 // otherwise we need to do eager allocation so that the collection type specified by the user 94 // will be used. 95 super(context, prop, !coreList.fullName().equals("java.util.ArrayList")); 96 this.coreList = coreList.narrow(exposedType.boxify()); 97 generate(); 98 } 99 100 protected final JClass getCoreListType() { 101 return coreList; 102 } 103 104 @Override 105 public void generateAccessors() { 106 final MethodWriter writer = outline.createMethodWriter(); 107 final Accessor acc = create(JExpr._this()); 108 109 // [RESULT] 110 // List getXXX() { 111 // return <ref>; 112 // } 113 $get = writer.declareMethod(listT,"get"+prop.getName(true)); 114 writer.javadoc().append(prop.javadoc); 115 JBlock block = $get.body(); 116 fixNullRef(block); // avoid using an internal getter 117 block._return(acc.ref(true)); 118 119 String pname = NameConverter.standard.toVariableName(prop.getName(true)); 120 writer.javadoc().append( 121 "Gets the value of the "+pname+" property.\n\n"+ 122 "<p>\n" + 123 "This accessor method returns a reference to the live list,\n" + 124 "not a snapshot. Therefore any modification you make to the\n" + 125 "returned list will be present inside the JAXB object.\n" + 126 "This is why there is not a <CODE>set</CODE> method for the " +pname+ " property.\n" + 127 "\n"+ 128 "<p>\n" + 129 "For example, to add a new item, do as follows:\n"+ 130 "<pre>\n"+ 131 " get"+prop.getName(true)+"().add(newItem);\n"+ 132 "</pre>\n"+ 133 "\n\n" 134 ); 135 136 writer.javadoc().append( 137 "<p>\n" + 138 "Objects of the following type(s) are allowed in the list\n") 139 .append(listPossibleTypes(prop)); 140 } 141 142 public Accessor create(JExpression targetObject) { 143 return new Accessor(targetObject); 144 } 145 146 class Accessor extends AbstractListField.Accessor { 147 protected Accessor( JExpression $target ) { 148 super($target); 149 } 150 151 public void toRawValue(JBlock block, JVar $var) { 152 // [RESULT] 153 // $<var>.addAll(bean.getLIST()); 154 // list.toArray( array ); 155 block.assign($var,JExpr._new(codeModel.ref(ArrayList.class).narrow(exposedType.boxify())).arg( 156 $target.invoke($get) 157 )); 158 } 159 160 public void fromRawValue(JBlock block, String uniqueName, JExpression $var) { 161 // [RESULT] 162 // bean.getLIST().addAll($<var>); 163 JVar $list = block.decl(listT,uniqueName+'l',$target.invoke($get)); 164 block.invoke($list,"addAll").arg($var); 165 } 166 } 167 }