1 // Copyright 2012 Google Inc. All Rights Reserved.
3 package com
.google
.appengine
.api
.datastore
;
5 import static com
.google
.common
.base
.Preconditions
.checkArgument
;
6 import static com
.google
.common
.base
.Preconditions
.checkNotNull
;
8 import com
.google
.appengine
.api
.datastore
.DataTypeTranslator
.Type
;
9 import com
.google
.appengine
.api
.users
.User
;
10 import com
.google
.datastore
.v1beta3
.Value
;
11 import com
.google
.datastore
.v1beta3
.client
.DatastoreHelper
;
12 import com
.google
.storage
.onestore
.v3
.OnestoreEntity
.Property
.Meaning
;
13 import com
.google
.storage
.onestore
.v3
.OnestoreEntity
.PropertyValue
;
15 import java
.io
.IOException
;
16 import java
.io
.Serializable
;
17 import java
.util
.Arrays
;
20 * A raw datastore value.
22 * These are returned by projection queries when a {@link PropertyProjection} does not
25 * @see Query#getProjections()
27 public final class RawValue
implements Serializable
{
28 private static final long serialVersionUID
= 8176992854378814427L;
29 private transient PropertyValue valueV3
= null;
30 private transient Value valueV1
= null;
32 RawValue(PropertyValue propertyValue
) {
33 this.valueV3
= checkNotNull(propertyValue
);
36 RawValue(Value value
) {
37 this.valueV1
= checkNotNull(value
);
41 * Returns an object of the exact type passed in.
43 * @param type the class object for the desired type
44 * @return an object of type T or {@code null}
45 * @throws IllegalArgumentException if the raw value cannot be converted into the given type
47 @SuppressWarnings("unchecked")
48 public <T
> T
asStrictType(Class
<T
> type
) {
49 Object value
= asType(type
);
51 checkArgument(type
.isAssignableFrom(value
.getClass()), "Unsupported type: " + type
);
57 * Returns the object normally returned by the datastore if given type is passed in.
59 * All integer values are returned as {@link Long}.
60 * All floating point values are returned as {@link Double}.
62 * @param type the class object for the desired type
63 * @return an object of type T or {@code null}
64 * @throws IllegalArgumentException if the raw value cannot be converted into the given type
66 public Object
asType(Class
<?
> type
) {
67 Type
<?
> typeAdapter
= DataTypeTranslator
.getTypeMap().get(type
);
68 checkArgument(typeAdapter
!= null, "Unsupported type: " + type
);
70 if (valueV3
!= null) {
71 if (typeAdapter
.hasValue(valueV3
)) {
72 return typeAdapter
.getValue(valueV3
);
74 } else if (valueV1
!= null) {
75 if (typeAdapter
.hasValue(valueV1
)) {
76 return typeAdapter
.getValue(valueV1
);
80 checkArgument(getValue() == null, "Type mismatch.");
85 * Returns the raw value.
87 * @return An object of type {@link Boolean}, {@link Double}, {@link GeoPt}, {@link Key},
88 * {@code byte[]}, {@link User} or {@code null}.
90 public Object
getValue() {
91 if (valueV3
!= null) {
92 if (valueV3
.hasBooleanValue()) {
93 return valueV3
.isBooleanValue();
94 } else if (valueV3
.hasDoubleValue()) {
95 return valueV3
.getDoubleValue();
96 } else if (valueV3
.hasInt64Value()) {
97 return valueV3
.getInt64Value();
98 } else if (valueV3
.hasPointValue()) {
99 return asType(GeoPt
.class);
100 } else if (valueV3
.hasReferenceValue()) {
101 return asType(Key
.class);
102 } else if (valueV3
.hasStringValue()) {
103 return valueV3
.getStringValueAsBytes();
104 } else if (valueV3
.hasUserValue()) {
105 return asType(User
.class);
107 } else if (valueV1
!= null) {
108 switch (valueV1
.getValueTypeCase()) {
110 return valueV1
.getBooleanValue();
112 return valueV1
.getDoubleValue();
114 return valueV1
.getIntegerValue();
116 if (valueV1
.getMeaning() == 20) {
117 return asType(User
.class);
119 throw new IllegalStateException("Raw entity value is not supported.");
121 return asType(Key
.class);
123 return valueV1
.getStringValueBytes().toByteArray();
125 return valueV1
.getBlobValue().toByteArray();
126 case TIMESTAMP_VALUE
:
127 return DatastoreHelper
.getTimestamp(valueV1
);
128 case GEO_POINT_VALUE
:
129 if (valueV1
.getMeaning() == 0 || valueV1
.getMeaning() == Meaning
.INDEX_VALUE
.getValue()) {
130 return asType(GeoPt
.class);
134 throw new IllegalStateException("Raw array value is not supported.");
143 private void writeObject(java
.io
.ObjectOutputStream out
) throws IOException
{
144 if (valueV3
!= null) {
146 valueV3
.writeTo(out
);
149 valueV1
.writeTo(out
);
151 out
.defaultWriteObject();
154 private void readObject(java
.io
.ObjectInputStream in
) throws IOException
, ClassNotFoundException
{
155 int version
= in
.read();
157 valueV3
= new PropertyValue();
158 valueV3
.parseFrom(in
);
159 } else if (version
== 2) {
160 valueV1
= Value
.PARSER
.parseFrom(in
);
162 checkArgument(false, "unknown RawValue format");
164 in
.defaultReadObject();
168 public int hashCode() {
169 Object value
= getValue();
170 return value
== null ?
0 : value
.hashCode();
174 public boolean equals(Object obj
) {
175 if (this == obj
) return true;
176 if (obj
== null) return false;
177 if (getClass() != obj
.getClass()) return false;
178 RawValue other
= (RawValue
) obj
;
179 Object value
= getValue();
180 Object otherValue
= other
.getValue();
182 if (otherValue
!= null) {
183 if (value
instanceof byte[]) {
184 if (otherValue
instanceof byte[]) {
185 return Arrays
.equals((byte[]) value
, (byte[]) otherValue
);
188 return value
.equals(otherValue
);
191 } else if (otherValue
== null) {
198 public String
toString() {
199 return "RawValue [value=" + getValue() + "]";