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
.blobstore
.BlobKey
;
9 import com
.google
.appengine
.api
.datastore
.DataTypeTranslator
.Type
;
10 import com
.google
.appengine
.api
.users
.User
;
11 import com
.google
.apphosting
.datastore
.EntityV4
;
12 import com
.google
.storage
.onestore
.v3
.OnestoreEntity
.PropertyValue
;
14 import java
.io
.IOException
;
15 import java
.io
.Serializable
;
16 import java
.util
.Arrays
;
19 * A raw datastore value.
21 * These are returned by projection queries when a {@link PropertyProjection} does not
24 * @see Query#getProjections()
26 public final class RawValue
implements Serializable
{
27 private static final long serialVersionUID
= 8176992854378814427L;
28 private transient PropertyValue valueV3
= null;
29 private transient EntityV4
.Value valueV4
= null;
31 RawValue(PropertyValue propertyValue
) {
32 this.valueV3
= checkNotNull(propertyValue
);
35 RawValue(EntityV4
.Value propertyValue
) {
36 this.valueV4
= checkNotNull(propertyValue
);
40 * Returns an object of the exact type passed in.
42 * @param type the class object for the desired type
43 * @return an object of type T or {@code null}
44 * @throws IllegalArgumentException if the raw value cannot be converted into the given type
46 @SuppressWarnings("unchecked")
47 public <T
> T
asStrictType(Class
<T
> type
) {
48 Object value
= asType(type
);
50 checkArgument(type
.isAssignableFrom(value
.getClass()), "Unsupported type: " + type
);
56 * Returns the object normally returned by the datastore if given type is passed in.
58 * All integer values are returned as {@link Long}.
59 * All floating point values are returned as {@link Double}.
61 * @param type the class object for the desired type
62 * @return an object of type T or {@code null}
63 * @throws IllegalArgumentException if the raw value cannot be converted into the given type
65 public Object
asType(Class
<?
> type
) {
66 Type
<?
> typeAdapter
= DataTypeTranslator
.getTypeMap().get(type
);
67 checkArgument(typeAdapter
!= null, "Unsupported type: " + type
);
69 if (valueV3
!= null) {
70 if (typeAdapter
.hasValue(valueV3
)) {
71 return typeAdapter
.getValue(valueV3
);
73 } else if (valueV4
!= null) {
74 if (typeAdapter
.hasValue(valueV4
)) {
75 return typeAdapter
.getValue(valueV4
);
79 checkArgument(getValue() == null, "Type mismatch.");
84 * Returns the raw value.
86 * @return An object of type {@link Boolean}, {@link Double}, {@link GeoPt}, {@link Key},
87 * {@code byte[]}, {@link User} or {@code null}.
89 public Object
getValue() {
90 if (valueV3
!= null) {
91 if (valueV3
.hasBooleanValue()) {
92 return valueV3
.isBooleanValue();
93 } else if (valueV3
.hasDoubleValue()) {
94 return valueV3
.getDoubleValue();
95 } else if (valueV3
.hasInt64Value()) {
96 return valueV3
.getInt64Value();
97 } else if (valueV3
.hasPointValue()) {
98 return asType(GeoPt
.class);
99 } else if (valueV3
.hasReferenceValue()) {
100 return asType(Key
.class);
101 } else if (valueV3
.hasStringValue()) {
102 return valueV3
.getStringValueAsBytes();
103 } else if (valueV3
.hasUserValue()) {
104 return asType(User
.class);
106 } else if (valueV4
!= null) {
107 if (valueV4
.hasBooleanValue()) {
108 return valueV4
.getBooleanValue();
109 } else if (valueV4
.hasDoubleValue()) {
110 return valueV4
.getDoubleValue();
111 } else if (valueV4
.hasIntegerValue()) {
112 return valueV4
.getIntegerValue();
113 } else if (valueV4
.hasEntityValue()) {
114 if (valueV4
.getMeaning() == 20) {
115 return asType(User
.class);
117 return asType(GeoPt
.class);
118 } else if (valueV4
.hasKeyValue()) {
119 return asType(Key
.class);
120 } else if (valueV4
.hasStringValue()) {
121 return valueV4
.getStringValueBytes().toByteArray();
122 } else if (valueV4
.hasBlobKeyValue()) {
123 return asType(BlobKey
.class);
124 } else if (valueV4
.hasBlobValue()) {
125 return valueV4
.getBlobValue().toByteArray();
126 } else if (valueV4
.hasTimestampMicrosecondsValue()) {
127 return valueV4
.getTimestampMicrosecondsValue();
128 } else if (valueV4
.hasGeoPointValue()) {
129 return asType(GeoPt
.class);
135 private void writeObject(java
.io
.ObjectOutputStream out
) throws IOException
{
136 if (valueV3
!= null) {
138 valueV3
.writeTo(out
);
141 valueV4
.writeTo(out
);
143 out
.defaultWriteObject();
146 private void readObject(java
.io
.ObjectInputStream in
) throws IOException
, ClassNotFoundException
{
147 int version
= in
.read();
149 valueV3
= new PropertyValue();
150 valueV3
.parseFrom(in
);
151 } else if (version
== 2) {
152 valueV4
= EntityV4
.Value
.PARSER
.parseFrom(in
);
154 checkArgument(false, "unknown RawValue format");
156 in
.defaultReadObject();
160 public int hashCode() {
161 Object value
= getValue();
162 return value
== null ?
0 : value
.hashCode();
166 public boolean equals(Object obj
) {
167 if (this == obj
) return true;
168 if (obj
== null) return false;
169 if (getClass() != obj
.getClass()) return false;
170 RawValue other
= (RawValue
) obj
;
171 Object value
= getValue();
172 Object otherValue
= other
.getValue();
174 if (otherValue
!= null) {
175 if (value
instanceof byte[]) {
176 if (otherValue
instanceof byte[]) {
177 return Arrays
.equals((byte[]) value
, (byte[]) otherValue
);
180 return value
.equals(otherValue
);
183 } else if (otherValue
== null) {
190 public String
toString() {
191 return "RawValue [value=" + getValue() + "]";