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 }