1616
1717package com .google .gcloud .bigquery ;
1818
19+ import static com .google .common .base .Preconditions .checkNotNull ;
1920import static com .google .common .base .Preconditions .checkState ;
2021
2122import com .google .api .client .util .Data ;
2223import com .google .api .client .util .Lists ;
24+ import com .google .common .base .Function ;
2325import com .google .common .base .MoreObjects ;
2426
2527import java .io .Serializable ;
3436 */
3537public class FieldValue implements Serializable {
3638
39+ static final Function <Object , FieldValue > FROM_PB_FUNCTION = new Function <Object , FieldValue >() {
40+ @ Override
41+ public FieldValue apply (Object pb ) {
42+ return FieldValue .fromPb (pb );
43+ }
44+ };
3745 private static final int MICROSECONDS = 1000000 ;
3846 private static final long serialVersionUID = 469098630191710061L ;
3947
40- private final Kind kind ;
48+ private final Attribute attribute ;
4149 private final Object value ;
4250
4351 /**
44- * The field value's kind , giving information on the field's content type.
52+ * The field value's attribute , giving information on the field's content type.
4553 */
46- public enum Kind {
54+ public enum Attribute {
4755 /**
48- * A primitive field value. A {@code FieldValue} has type {@link #PRIMITIVE} when the
49- * corresponding field has type {@link Field.Type#bool()}, {@link Field.Type#string()}
56+ * A primitive field value. A {@code FieldValue} is primitive when the corresponding field has
57+ * type {@link Field.Type#bool()}, {@link Field.Type#string()},
5058 * {@link Field.Type#floatingPoint()}, {@link Field.Type#integer()},
5159 * {@link Field.Type#timestamp()} or the value is set to {@code null}.
5260 */
@@ -63,100 +71,116 @@ public enum Kind {
6371 RECORD
6472 }
6573
66- FieldValue (Kind kind , Object value ) {
67- this .kind = kind ;
74+ FieldValue (Attribute attribute , Object value ) {
75+ this .attribute = attribute ;
6876 this .value = value ;
6977 }
7078
7179 /**
72- * Returns the kind of this Field Value.
80+ * Returns the attribute of this Field Value.
7381 *
74- * @return {@link Kind#PRIMITIVE} if the value is of primitive type ({@link Field.Type#bool()},
75- * {@link Field.Type#string()}, {@link Field.Type#floatingPoint()},
76- * {@link Field.Type#integer()}, {@link Field.Type#timestamp()}) or is {@code null}. Returns
77- * {@link Kind#REPEATED} if the corresponding field has ({@link Field.Mode#REPEATED}) mode.
78- * Returns {@link Kind#RECORD} if the corresponding field has
82+ * @return {@link Attribute#PRIMITIVE} if the field is a primitive type
83+ * ({@link Field.Type#bool()}, {@link Field.Type#string()},
84+ * {@link Field.Type#floatingPoint()}, {@link Field.Type#integer()},
85+ * {@link Field.Type#timestamp()}) or is {@code null}. Returns {@link Attribute#REPEATED} if
86+ * the corresponding field has ({@link Field.Mode#REPEATED}) mode. Returns
87+ * {@link Attribute#RECORD} if the corresponding field is a
7988 * {@link Field.Type#record(Field...)} type.
8089 */
81- public Kind kind () {
82- return kind ;
90+ public Attribute attribute () {
91+ return attribute ;
92+ }
93+
94+ /**
95+ * Returns {@code true} if this field's value is {@code null}, {@code false} otherwise.
96+ */
97+ public boolean isNull () {
98+ return value == null ;
8399 }
84100
85101 /**
86- * Return this field's value as an {@link Object}.
102+ * Returns this field's value as an {@link Object}.
87103 */
88104 public Object value () {
89105 return value ;
90106 }
91107
92108 /**
93- * Return this field's value as a {@link String}. This method should only be used if the
109+ * Returns this field's value as a {@link String}. This method should only be used if the
94110 * corresponding field has primitive type ({@link Field.Type#bool()}, {@link Field.Type#string()},
95111 * {@link Field.Type#floatingPoint()}, {@link Field.Type#integer()},
96112 * {@link Field.Type#timestamp()}).
97113 *
98- * @throws ClassCastException if the field has not primitive type
114+ * @throws ClassCastException if the field is not a primitive type
99115 */
100116 @ SuppressWarnings ("unchecked" )
101117 public String stringValue () {
102118 return (String ) value ;
103119 }
104120
105121 /**
106- * Returns this field's value as a {@link Long }. This method should only be used if the
122+ * Returns this field's value as a {@code long }. This method should only be used if the
107123 * corresponding field has {@link Field.Type#integer()} type.
108124 *
109- * @throws ClassCastException if the field has not primitive type
125+ * @throws ClassCastException if the field is not a primitive type
110126 * @throws NumberFormatException if the field's value could not be converted to {@link Integer}
127+ * @throws NullPointerException if {@link #isNull()} returns {@code true}
111128 */
112129 @ SuppressWarnings ("unchecked" )
113130 public long longValue () {
114- return Long .valueOf (stringValue ());
131+ return Long .parseLong (stringValue ());
115132 }
116133
117134 /**
118135 * Returns this field's value as a {@link Double}. This method should only be used if the
119136 * corresponding field has {@link Field.Type#floatingPoint()} type.
120137 *
121- * @throws ClassCastException if the field has not primitive type
138+ * @throws ClassCastException if the field is not a primitive type
122139 * @throws NumberFormatException if the field's value could not be converted to {@link Double}
140+ * @throws NullPointerException if {@link #isNull()} returns {@code true}
123141 */
124142 @ SuppressWarnings ("unchecked" )
125143 public double doubleValue () {
126- return Double .valueOf (stringValue ());
144+ return Double .parseDouble (stringValue ());
127145 }
128146
129147 /**
130148 * Returns this field's value as a {@link Boolean}. This method should only be used if the
131149 * corresponding field has {@link Field.Type#bool()} type.
132150 *
133- * @throws ClassCastException if the field has not primitive type
151+ * @throws ClassCastException if the field is not a primitive type
134152 * @throws IllegalStateException if the field's value could not be converted to {@link Boolean}
153+ * @throws NullPointerException if {@link #isNull()} returns {@code true}
135154 */
136155 @ SuppressWarnings ("unchecked" )
137156 public boolean booleanValue () {
138157 String stringValue = stringValue ();
158+ checkNotNull (stringValue );
139159 checkState (stringValue .equalsIgnoreCase ("true" ) || stringValue .equalsIgnoreCase ("false" ),
140160 "Field value is not of boolean type" );
141161 return Boolean .parseBoolean (stringValue );
142162 }
143163
144164 /**
145- * Returns this field's value as a {@link Long}, representing a timestamp in microseconds. This
146- * method should only be used if the corresponding field has {@link Field.Type#timestamp()} type.
165+ * Returns this field's value as a {@code long}, representing a timestamp in microseconds since
166+ * epoch (UNIX time). This method should only be used if the corresponding field has
167+ * {@link Field.Type#timestamp()} type.
147168 *
148- * @throws ClassCastException if the field has not primitive type
169+ * @throws ClassCastException if the field is not a primitive type
149170 * @throws NumberFormatException if the field's value could not be converted to {@link Long}
171+ * @throws NullPointerException if {@link #isNull()} returns {@code true}
150172 */
151173 @ SuppressWarnings ("unchecked" )
152174 public long timestampValue () {
175+ // timestamps are encoded in the format 1408452095.22 where the integer part is seconds since
176+ // epoch (e.g. 1408452095.22 == 2014-08-19 07:41:35.220 -05:00)
153177 return new Double (((Double .valueOf (stringValue ())) * MICROSECONDS )).longValue ();
154178 }
155179
156180 /**
157181 * Returns this field's value as a list of {@link FieldValue}. This method should only be used if
158- * the corresponding field has {@link Field.Mode#REPEATED} mode (i.e. {@link #kind ()} is
159- * {@link Kind #REPEATED}).
182+ * the corresponding field has {@link Field.Mode#REPEATED} mode (i.e. {@link #attribute ()} is
183+ * {@link Attribute #REPEATED}).
160184 *
161185 * @throws ClassCastException if the field has not {@link Field.Mode#REPEATED} mode
162186 */
@@ -167,10 +191,10 @@ public List<FieldValue> repeatedValue() {
167191
168192 /**
169193 * Returns this field's value as a list of {@link FieldValue}. This method should only be used if
170- * the corresponding field has {@link Field.Type#record(Field...)} type (i.e. {@link #kind ()} is
171- * {@link Kind #RECORD}).
194+ * the corresponding field has {@link Field.Type#record(Field...)} type (i.e. {@link #attribute ()}
195+ * is {@link Attribute #RECORD}).
172196 *
173- * @throws ClassCastException if the field has not {@link Field.Type#record(Field...)} type
197+ * @throws ClassCastException if the field is not a {@link Field.Type#record(Field...)} type
174198 */
175199 @ SuppressWarnings ("unchecked" )
176200 public List <FieldValue > recordValue () {
@@ -180,14 +204,14 @@ public List<FieldValue> recordValue() {
180204 @ Override
181205 public String toString () {
182206 return MoreObjects .toStringHelper (this )
183- .add ("kind " , kind )
207+ .add ("attribute " , attribute )
184208 .add ("value" , value )
185209 .toString ();
186210 }
187211
188212 @ Override
189213 public int hashCode () {
190- return Objects .hash (kind , value );
214+ return Objects .hash (attribute , value );
191215 }
192216
193217 @ Override
@@ -196,24 +220,24 @@ public boolean equals(Object obj) {
196220 return false ;
197221 }
198222 FieldValue other = (FieldValue ) obj ;
199- return kind == other .kind && Objects .equals (value , other .value );
223+ return attribute == other .attribute && Objects .equals (value , other .value );
200224 }
201225
202226 @ SuppressWarnings ("unchecked" )
203227 static FieldValue fromPb (Object cellPb ) {
204228 if (Data .isNull (cellPb )) {
205- return new FieldValue (Kind .PRIMITIVE , null );
229+ return new FieldValue (Attribute .PRIMITIVE , null );
206230 }
207231 if (cellPb instanceof String ) {
208- return new FieldValue (Kind .PRIMITIVE , cellPb );
232+ return new FieldValue (Attribute .PRIMITIVE , cellPb );
209233 }
210234 if (cellPb instanceof List ) {
211235 List <Object > cellsListPb = (List <Object >) cellPb ;
212236 List <FieldValue > repeatedCells = Lists .newArrayListWithCapacity (cellsListPb .size ());
213237 for (Object repeatedCellPb : cellsListPb ) {
214238 repeatedCells .add (FieldValue .fromPb (repeatedCellPb ));
215239 }
216- return new FieldValue (Kind .REPEATED , repeatedCells );
240+ return new FieldValue (Attribute .REPEATED , repeatedCells );
217241 }
218242 if (cellPb instanceof Map ) {
219243 Map <String , Object > cellMapPb = (Map <String , Object >) cellPb ;
@@ -223,7 +247,7 @@ static FieldValue fromPb(Object cellPb) {
223247 for (Object repeatedCellPb : cellsListPb ) {
224248 recordCells .add (FieldValue .fromPb (repeatedCellPb ));
225249 }
226- return new FieldValue (Kind .RECORD , recordCells );
250+ return new FieldValue (Attribute .RECORD , recordCells );
227251 }
228252 // This should never be the case when we are processing a first level table field (i.e. a
229253 // row's field, not a record sub-field)
0 commit comments