Revision created by MOE tool push_codebase.
[gae.git] / java / src / main / com / google / appengine / api / datastore / RawValue.java
blob28ab834438dcd1dd47929313288ee2cab9e861b0
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;
19 /**
20 * A raw datastore value.
22 * These are returned by projection queries when a {@link PropertyProjection} does not
23 * specify a type.
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);
40 /**
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);
50 if (value != null) {
51 checkArgument(type.isAssignableFrom(value.getClass()), "Unsupported type: " + type);
53 return (T) value;
56 /**
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.");
81 return null;
84 /**
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()) {
109 case BOOLEAN_VALUE:
110 return valueV1.getBooleanValue();
111 case DOUBLE_VALUE:
112 return valueV1.getDoubleValue();
113 case INTEGER_VALUE:
114 return valueV1.getIntegerValue();
115 case ENTITY_VALUE:
116 if (valueV1.getMeaning() == 20) {
117 return asType(User.class);
119 throw new IllegalStateException("Raw entity value is not supported.");
120 case KEY_VALUE:
121 return asType(Key.class);
122 case STRING_VALUE:
123 return valueV1.getStringValueBytes().toByteArray();
124 case BLOB_VALUE:
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);
132 break;
133 case ARRAY_VALUE:
134 throw new IllegalStateException("Raw array value is not supported.");
135 case NULL_VALUE:
136 default:
137 return null;
140 return null;
143 private void writeObject(java.io.ObjectOutputStream out) throws IOException {
144 if (valueV3 != null) {
145 out.write(1);
146 valueV3.writeTo(out);
147 } else {
148 out.write(2);
149 valueV1.writeTo(out);
151 out.defaultWriteObject();
154 private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
155 int version = in.read();
156 if (version == 1) {
157 valueV3 = new PropertyValue();
158 valueV3.parseFrom(in);
159 } else if (version == 2) {
160 valueV1 = Value.PARSER.parseFrom(in);
161 } else {
162 checkArgument(false, "unknown RawValue format");
164 in.defaultReadObject();
167 @Override
168 public int hashCode() {
169 Object value = getValue();
170 return value == null ? 0 : value.hashCode();
173 @Override
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();
181 if (value != null) {
182 if (otherValue != null) {
183 if (value instanceof byte[]) {
184 if (otherValue instanceof byte[]) {
185 return Arrays.equals((byte[]) value, (byte[]) otherValue);
187 } else {
188 return value.equals(otherValue);
191 } else if (otherValue == null) {
192 return true;
194 return false;
197 @Override
198 public String toString() {
199 return "RawValue [value=" + getValue() + "]";