|
3 | 3 | import static com.google.common.base.Preconditions.checkNotNull; |
4 | 4 | import static java.nio.charset.StandardCharsets.UTF_8; |
5 | 5 |
|
| 6 | +import com.google.api.services.datastore.DatastoreV1; |
| 7 | +import com.google.api.services.datastore.DatastoreV1.Value; |
6 | 8 | import com.google.common.base.MoreObjects; |
7 | 9 | import com.google.common.base.MoreObjects.ToStringHelper; |
8 | 10 | import com.google.protobuf.ByteString; |
| 11 | +import com.google.protobuf.InvalidProtocolBufferException; |
9 | 12 |
|
10 | | -import java.io.Serializable; |
11 | 13 | import java.io.UnsupportedEncodingException; |
12 | 14 | import java.net.URLDecoder; |
13 | 15 | import java.net.URLEncoder; |
14 | | -import java.util.Arrays; |
15 | 16 |
|
16 | 17 | /** |
17 | 18 | * A Google Cloud Datastore cursor. |
18 | 19 | * The cursor can be used to as a starting point or an ending point for a {@link Query} |
19 | 20 | */ |
20 | | -public final class Cursor implements Serializable { |
| 21 | +public final class Cursor extends Serializable<DatastoreV1.Value> { |
21 | 22 |
|
22 | 23 | private static final long serialVersionUID = -1423744878777486541L; |
23 | 24 |
|
24 | | - private final byte[] bytes; |
| 25 | + private final transient ByteString byteString; |
25 | 26 |
|
26 | | - public Cursor(byte[] bytes) { |
27 | | - this.bytes = checkNotNull(bytes); |
| 27 | + Cursor(ByteString byteString) { |
| 28 | + this.byteString = byteString; |
28 | 29 | } |
29 | 30 |
|
30 | 31 | @Override |
31 | 32 | public int hashCode() { |
32 | | - return Arrays.hashCode(bytes); |
| 33 | + return byteString.hashCode(); |
33 | 34 | } |
34 | 35 |
|
35 | 36 | @Override |
36 | 37 | public boolean equals(Object obj) { |
| 38 | + if (obj == this) { |
| 39 | + return true; |
| 40 | + } |
37 | 41 | if (!(obj instanceof Cursor)) { |
38 | 42 | return false; |
39 | 43 | } |
40 | | - |
41 | | - return Arrays.equals(bytes, ((Cursor) obj).bytes); |
| 44 | + return byteString.equals(((Cursor) obj).byteString); |
42 | 45 | } |
43 | 46 |
|
44 | 47 | @Override |
45 | 48 | public String toString() { |
46 | 49 | ToStringHelper toStringHelper = MoreObjects.toStringHelper(this); |
47 | 50 | StringBuilder stBuilder = new StringBuilder(); |
48 | | - for (byte b : bytes) { |
49 | | - stBuilder.append(String.format("%02x", b)); |
| 51 | + for (int i = 0; i < byteString.size(); i++) { |
| 52 | + stBuilder.append(String.format("%02x", byteString.byteAt(i))); |
50 | 53 | } |
51 | 54 | return toStringHelper.add("bytes", stBuilder.toString()).toString(); |
52 | 55 | } |
53 | 56 |
|
| 57 | + ByteString byteString() { |
| 58 | + return byteString; |
| 59 | + } |
| 60 | + |
54 | 61 | /** |
55 | 62 | * Returns the cursor in an encoded form that can be used as part of a URL. |
56 | 63 | */ |
57 | 64 | public String toUrlSafe() { |
58 | 65 | try { |
59 | | - return URLEncoder.encode(toString(), UTF_8.name()); |
| 66 | + return URLEncoder.encode(toPb().toString(), UTF_8.name()); |
60 | 67 | } catch (UnsupportedEncodingException e) { |
61 | 68 | throw new RuntimeException("Unxpeced encoding exception", e); |
62 | 69 | } |
63 | 70 | } |
64 | 71 |
|
65 | | - ByteString toPb() { |
66 | | - return ByteString.copyFrom(bytes); |
67 | | - } |
68 | | - |
69 | 72 | /** |
70 | 73 | * Create a {@code Cursor} given its URL safe encoded form. |
71 | 74 | */ |
72 | 75 | public static Cursor fromUrlSafe(String urlSafe) { |
73 | 76 | try { |
74 | 77 | String utf8Str = URLDecoder.decode(urlSafe, UTF_8.name()); |
75 | | - ByteString byteString = ByteString.copyFromUtf8(utf8Str); |
76 | | - return fromPb(byteString); |
77 | | - } catch (UnsupportedEncodingException e) { |
| 78 | + return fromPb(DatastoreV1.Value.parseFrom(utf8Str.getBytes())); |
| 79 | + } catch (UnsupportedEncodingException | InvalidProtocolBufferException e) { |
78 | 80 | throw new RuntimeException("Unxpeced decoding exception", e); |
79 | 81 | } |
80 | 82 | } |
81 | 83 |
|
82 | | - private static Cursor fromPb(ByteString byteString) { |
83 | | - return new Cursor(byteString.toByteArray()); |
| 84 | + public static Cursor copyFrom(byte[] bytes) { |
| 85 | + return new Cursor(ByteString.copyFrom(checkNotNull(bytes))); |
| 86 | + } |
| 87 | + |
| 88 | + @Override |
| 89 | + protected Value toPb() { |
| 90 | + return DatastoreV1.Value.newBuilder().setBlobValue(byteString).build(); |
| 91 | + } |
| 92 | + |
| 93 | + @Override |
| 94 | + protected Object fromPb(byte[] bytesPb) throws InvalidProtocolBufferException { |
| 95 | + return fromPb(DatastoreV1.Value.parseFrom(bytesPb)); |
| 96 | + } |
| 97 | + |
| 98 | + static Cursor fromPb(DatastoreV1.Value valuePb) { |
| 99 | + return new Cursor(valuePb.getBlobValue()); |
84 | 100 | } |
85 | 101 | } |
0 commit comments