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 com.sun.codemodel.internal.JAssignmentTarget; 29 import java.util.List; 30 import com.sun.codemodel.internal.JBlock; 31 import com.sun.codemodel.internal.JClass; 32 import com.sun.codemodel.internal.JExpr; 33 import com.sun.codemodel.internal.JExpression; 34 import com.sun.codemodel.internal.JForLoop; 35 import com.sun.codemodel.internal.JMethod; 36 import com.sun.codemodel.internal.JMod; 37 import com.sun.codemodel.internal.JOp; 38 import com.sun.codemodel.internal.JType; 39 import com.sun.codemodel.internal.JVar; 40 import com.sun.tools.internal.xjc.generator.bean.ClassOutlineImpl; 41 import com.sun.tools.internal.xjc.generator.bean.MethodWriter; 42 import com.sun.tools.internal.xjc.model.CPropertyInfo; 43 44 /** 45 * Realizes a property as an "indexed property" 46 * as specified in the JAXB spec. 47 * 48 * <p> 49 * We will generate the following set of methods: 50 * <pre> 51 * T[] getX(); 52 * T getX( int idx ); 53 * void setX(T[] values); 54 * void setX( int idx, T value ); 55 * </pre> 56 * 57 * We still use List as our back storage. 58 * This renderer also handles boxing/unboxing if 59 * T is a boxed type. 60 * 61 * @author 62 * Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com) 63 */ 64 final class ArrayField extends AbstractListField { 65 66 class Accessor extends AbstractListField.Accessor { 67 protected Accessor( JExpression $target ) { 68 super($target); 69 } 70 71 public void toRawValue(JBlock block, JVar $var) { 72 block.assign($var,$target.invoke($getAll)); 73 } 74 75 public void fromRawValue(JBlock block, String uniqueName, JExpression $var) { 76 block.invoke($target,$setAll).arg($var); 77 } 78 79 @Override 80 public JExpression hasSetValue() { 81 return field.ne(JExpr._null()).cand(field.ref("length").gt(JExpr.lit(0))); 82 } 83 84 } 85 86 private JMethod $setAll; 87 88 private JMethod $getAll; 89 90 ArrayField(ClassOutlineImpl context, CPropertyInfo prop) { 91 super(context,prop,false); 92 generateArray(); 93 } 94 95 protected final void generateArray() { 96 field = outline.implClass.field( JMod.PROTECTED, getCoreListType(), prop.getName(false) ); 97 annotate(field); 98 99 // generate the rest of accessors 100 generateAccessors(); 101 } 102 103 public void generateAccessors() { 104 105 MethodWriter writer = outline.createMethodWriter(); 106 Accessor acc = create(JExpr._this()); 107 JVar $idx,$value; JBlock body; 108 109 // [RESULT] T[] getX() { 110 // if( <var>==null ) return new T[0]; 111 // T[] retVal = new T[this._return.length] ; 112 // System.arraycopy(this._return, 0, "retVal", 0, this._return.length); 113 // return (retVal); 114 // } 115 $getAll = writer.declareMethod( exposedType.array(),"get"+prop.getName(true)); 116 writer.javadoc().append(prop.javadoc); 117 body = $getAll.body(); 118 119 body._if( acc.ref(true).eq(JExpr._null()) )._then() 120 ._return(JExpr.newArray(exposedType,0)); 121 JVar var = body.decl(exposedType.array(), "retVal", JExpr.newArray(implType,acc.ref(true).ref("length"))); 122 body.add(codeModel.ref(System.class).staticInvoke("arraycopy") 123 .arg(acc.ref(true)).arg(JExpr.lit(0)) 124 .arg(var) 125 .arg(JExpr.lit(0)).arg(acc.ref(true).ref("length"))); 126 body._return(JExpr.direct("retVal")); 127 128 List<Object> returnTypes = listPossibleTypes(prop); 129 writer.javadoc().addReturn().append("array of\n").append(returnTypes); 130 131 // [RESULT] 132 // ET getX(int idx) { 133 // if( <var>==null ) throw new IndexOutOfBoundsException(); 134 // return unbox(<var>.get(idx)); 135 // } 136 JMethod $get = writer.declareMethod(exposedType,"get"+prop.getName(true)); 137 $idx = writer.addParameter(codeModel.INT,"idx"); 138 139 $get.body()._if(acc.ref(true).eq(JExpr._null()))._then() 140 ._throw(JExpr._new(codeModel.ref(IndexOutOfBoundsException.class))); 141 142 writer.javadoc().append(prop.javadoc); 143 $get.body()._return(acc.ref(true).component($idx)); 144 145 writer.javadoc().addReturn().append("one of\n").append(returnTypes); 146 147 // [RESULT] int getXLength() { 148 // if( <var>==null ) throw new IndexOutOfBoundsException(); 149 // return <ref>.length; 150 // } 151 JMethod $getLength = writer.declareMethod(codeModel.INT,"get"+prop.getName(true)+"Length"); 152 $getLength.body()._if(acc.ref(true).eq(JExpr._null()))._then() 153 ._return(JExpr.lit(0)); 154 $getLength.body()._return(acc.ref(true).ref("length")); 155 156 // [RESULT] void setX(ET[] values) { 157 // int len = values.length; 158 // for( int i=0; i<len; i++ ) 159 // <ref>[i] = values[i]; 160 // } 161 $setAll = writer.declareMethod( 162 codeModel.VOID, 163 "set"+prop.getName(true)); 164 165 writer.javadoc().append(prop.javadoc); 166 $value = writer.addParameter(exposedType.array(),"values"); 167 JVar $len = $setAll.body().decl(codeModel.INT,"len", $value.ref("length")); 168 169 $setAll.body().assign( 170 (JAssignmentTarget) acc.ref(true), 171 castToImplTypeArray(JExpr.newArray( 172 codeModel.ref(exposedType.erasure().fullName()), 173 $len))); 174 175 JForLoop _for = $setAll.body()._for(); 176 JVar $i = _for.init( codeModel.INT, "i", JExpr.lit(0) ); 177 _for.test( JOp.lt($i,$len) ); 178 _for.update( $i.incr() ); 179 _for.body().assign(acc.ref(true).component($i), castToImplType(acc.box($value.component($i)))); 180 181 writer.javadoc().addParam($value) 182 .append("allowed objects are\n") 183 .append(returnTypes); 184 185 // [RESULT] ET setX(int idx, ET value) 186 // <ref>[idx] = value 187 JMethod $set = writer.declareMethod( 188 exposedType, 189 "set"+prop.getName(true)); 190 $idx = writer.addParameter( codeModel.INT, "idx" ); 191 $value = writer.addParameter( exposedType, "value" ); 192 193 writer.javadoc().append(prop.javadoc); 194 195 body = $set.body(); 196 body._return( JExpr.assign(acc.ref(true).component($idx), 197 castToImplType(acc.box($value)))); 198 199 writer.javadoc().addParam($value) 200 .append("allowed object is\n") 201 .append(returnTypes); 202 203 } 204 205 @Override 206 public JType getRawType() { 207 return exposedType.array(); 208 } 209 210 protected JClass getCoreListType() { 211 return exposedType.array(); 212 } 213 214 public Accessor create(JExpression targetObject) { 215 return new Accessor(targetObject); 216 } 217 218 /** 219 * Case from {@link #exposedType} to array of {@link #implType} . 220 */ 221 protected final JExpression castToImplTypeArray( JExpression exp ) { 222 return JExpr.cast(implType.array(), exp); 223 } 224 225 }