Skip to content

Commit c1e5bdd

Browse files
committed
load() operations now return LoadResult<?> instead of Ref<?>
1 parent e534ef8 commit c1e5bdd

71 files changed

Lines changed: 377 additions & 459 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package com.googlecode.objectify;
2+
3+
4+
5+
/**
6+
* <p>Enhances the basic Result<?> with some additional methods useful when loading data.</p>
7+
*
8+
* @author Jeff Schnitzer <jeff@infohazard.org>
9+
*/
10+
public class LoadResult<T> implements Result<T>
11+
{
12+
private final Key<T> key;
13+
private final Result<T> result;
14+
15+
public LoadResult(Key<T> key, Result<T> result) {
16+
this.key = key;
17+
this.result = result;
18+
}
19+
20+
/**
21+
* Obtain the loaded value now.
22+
*/
23+
@Override
24+
public T now() {
25+
return result.now();
26+
}
27+
28+
/**
29+
* Like now(), but throws NotFoundException instead of returning null.
30+
* @throws NotFoundException if the loaded value was not found
31+
*/
32+
public final T safe() throws NotFoundException {
33+
T t = now();
34+
if (t == null)
35+
throw new NotFoundException(key);
36+
else
37+
return t;
38+
}
39+
40+
/**
41+
* Use now() instead.
42+
*/
43+
@Deprecated
44+
public final T get() {
45+
return now();
46+
}
47+
48+
/**
49+
* Use safe() instead.
50+
*/
51+
@Deprecated
52+
public final T safeGet() {
53+
return safe();
54+
}
55+
}

src/main/java/com/googlecode/objectify/NotFoundException.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,12 @@ public class NotFoundException extends RuntimeException
1515

1616
/** Thrown when there is no key context (eg, query.first() on an empty result set) */
1717
public NotFoundException() {
18-
super("No entity was found");
19-
//key = null;
18+
this(null);
2019
}
2120

2221
/** Thrown when we at least know what we are looking for! */
2322
public NotFoundException(Key<?> key) {
24-
super("No entity was found matching the key: " + key);
23+
super(key == null ? "No entity was found" : "No entity was found matching the key: " + key);
2524
this.key = key;
2625
}
2726

src/main/java/com/googlecode/objectify/Ref.java

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import java.io.Serializable;
44

5-
import com.googlecode.objectify.impl.ref.StdRef;
5+
import com.googlecode.objectify.impl.ref.LiveRef;
66

77

88
/**
@@ -23,7 +23,7 @@ public static <T> Ref<T> create(Key<T> key) {
2323
if (key == null)
2424
throw new NullPointerException("Cannot create a Ref from a null key");
2525

26-
return new StdRef<T>(key);
26+
return new LiveRef<T>(key);
2727
}
2828

2929
/** Creates a Ref from a registered pojo entity */
@@ -32,10 +32,28 @@ public static <T> Ref<T> create(T value) {
3232
return create(key);
3333
}
3434

35+
/** The key associated with this ref */
36+
protected Key<T> key;
37+
38+
/** For GWT serialization */
39+
protected Ref() {}
40+
41+
/**
42+
* Create a Ref based on the key, with the specified session
43+
*/
44+
protected Ref(Key<T> key) {
45+
if (key == null)
46+
throw new NullPointerException("Cannot create a Ref for a null key");
47+
48+
this.key = key;
49+
}
50+
3551
/**
3652
* @return the key associated with this Ref
3753
*/
38-
abstract public Key<T> key();
54+
public Key<T> key() {
55+
return key;
56+
}
3957

4058
/**
4159
* Obtain the entity value associated with the key. Will pull from session if present, otherwise will
@@ -73,35 +91,28 @@ final public Key<T> getKey() {
7391
return key();
7492
}
7593

76-
/**
77-
* Obtain the key if it has been found, throwing an exception if no value was found. The exception is
78-
* only possible for Ref<?>s that are returned by Query.first().
79-
*
80-
* @return the key referenced
81-
* @throws NotFoundException if the specified entity was not found
82-
*/
83-
final public Key<T> safeKey() {
84-
Key<T> k = this.key();
85-
if (k == null)
86-
throw new NotFoundException();
87-
else
88-
return k;
89-
}
90-
9194
/**
9295
* Obtain the entity value, throwing an exception if the entity was not found.
9396
*
9497
* @return the entity referenced. Never returns null.
9598
* @throws NotFoundException if the specified entity was not found
9699
*/
97-
final public T safeGet() {
100+
final public T safe() throws NotFoundException {
98101
T t = this.get();
99102
if (t == null)
100103
throw new NotFoundException(key());
101104
else
102105
return t;
103106
}
104107

108+
/**
109+
* Use safe() instead.
110+
*/
111+
@Deprecated
112+
final public T safeGet() throws NotFoundException {
113+
return safe();
114+
}
115+
105116
/** Comparison is based on key */
106117
@Override
107118
public int compareTo(Ref<T> o) {

src/main/java/com/googlecode/objectify/cache/KeyMemcacheService.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
import com.google.appengine.api.datastore.Key;
88
import com.google.appengine.api.datastore.KeyFactory;
9-
import com.google.appengine.api.memcache.ErrorHandler;
109
import com.google.appengine.api.memcache.MemcacheService;
1110
import com.google.appengine.api.memcache.MemcacheService.CasValues;
1211
import com.google.appengine.api.memcache.MemcacheService.IdentifiableValue;
@@ -90,7 +89,8 @@ public void deleteAll(Collection<Key> keys) {
9089
service.deleteAll(stringify(keys));
9190
}
9291

93-
public void setErrorHandler(ErrorHandler handler) {
92+
@SuppressWarnings("deprecation")
93+
public void setErrorHandler(com.google.appengine.api.memcache.ErrorHandler handler) {
9494
service.setErrorHandler(handler);
9595
}
9696
}

src/main/java/com/googlecode/objectify/cmd/LoadIds.java

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,55 +2,55 @@
22

33
import java.util.Map;
44

5-
import com.googlecode.objectify.Ref;
5+
import com.googlecode.objectify.LoadResult;
66

77

88
/**
99
* <p>Terminator methods for a fetch-by-key command chain which constructs the key implicitly from
1010
* type, id, and (optionally) parent.</p>
11-
*
11+
*
1212
* <p>All command objects are immutable.</p>
13-
*
13+
*
1414
* @author Jeff Schnitzer <jeff@infohazard.org>
1515
*/
1616
public interface LoadIds<T>
1717
{
1818
/**
1919
* <p>Specify the numeric id of an entity and start asynchronous fetch.</p>
20-
*
21-
* @param id - the id of the entity to fetch. Note that numeric ids and String ids are not equivalent; 123 and "123" are different ids.
22-
* @return a Ref that wraps the asynchronous Result of the fetch.
20+
*
21+
* @param id - the id of the entity to fetch. Note that numeric ids and String ids are not equivalent; 123 and "123" are different ids.
22+
* @return an asynchronous result that can materialize the entity
2323
*/
24-
Ref<T> id(long id);
24+
LoadResult<T> id(long id);
2525

2626
/**
2727
* <p>Specify the String id of an entity and start asynchronous fetch.</p>
28-
*
29-
* @param id - the id of the entity to fetch. Note that numeric ids and String ids are not equivalent; 123 and "123" are different ids.
30-
* @return a Ref that wraps the asynchronous Result of the fetch.
28+
*
29+
* @param id - the id of the entity to fetch. Note that numeric ids and String ids are not equivalent; 123 and "123" are different ids.
30+
* @return an asynchronous result that can materialize the entity
3131
*/
32-
Ref<T> id(String id);
32+
LoadResult<T> id(String id);
3333

3434
/**
3535
* <p>Specify the numeric ids of multiple entities and start asynchronous fetch.</p>
36-
*
37-
* @param ids - the ids of the entity to fetch. Note that numeric ids and String ids are not equivalent; 123 and "123" are different ids.
36+
*
37+
* @param ids - the ids of the entity to fetch. Note that numeric ids and String ids are not equivalent; 123 and "123" are different ids.
3838
* @return a Map of the asynchronous result. The first method call on the Map will synchronously finish the call.
3939
*/
4040
Map<Long, T> ids(Long... ids);
4141

4242
/**
4343
* <p>Specify the String ids of multiple entities and start asynchronous fetch.</p>
44-
*
45-
* @param ids - the ids of the entity to fetch. Note that numeric ids and String ids are not equivalent; 123 and "123" are different ids.
44+
*
45+
* @param ids - the ids of the entity to fetch. Note that numeric ids and String ids are not equivalent; 123 and "123" are different ids.
4646
* @return a Map of the asynchronous result. The first method call on the Map will synchronously finish the call.
4747
*/
4848
Map<String, T> ids(String... ids);
4949

5050
/**
5151
* <p>Specify the ids of multiple entities and start asynchronous fetch.</p>
52-
*
53-
* @param ids - the ids of the entities to fetch. The Iterator must provide Long or String. Note that numeric ids and String ids are not equivalent; 123 and "123" are different ids.
52+
*
53+
* @param ids - the ids of the entities to fetch. The Iterator must provide Long or String. Note that numeric ids and String ids are not equivalent; 123 and "123" are different ids.
5454
* @return a Map of the asynchronous result. The first method call on the Map will synchronously finish the call.
5555
*/
5656
<S> Map<S, T> ids(Iterable<S> ids);

src/main/java/com/googlecode/objectify/cmd/Loader.java

Lines changed: 19 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import java.util.Set;
55

66
import com.googlecode.objectify.Key;
7+
import com.googlecode.objectify.LoadResult;
78
import com.googlecode.objectify.Objectify;
89
import com.googlecode.objectify.Ref;
910

@@ -46,25 +47,25 @@ public interface Loader extends SimpleQuery<Object>
4647
<E> LoadType<E> type(Class<E> type);
4748

4849
/**
49-
* <p>Load a single entity ref. This starts an asynchronous fetch operation which will be available as ref.get().</p>
50+
* <p>Load a single entity ref. This starts an asynchronous fetch operation.</p>
5051
*
5152
* <p>Since fetching is asynchronous,
5253
* <a href="http://code.google.com/appengine/articles/handling_datastore_errors.html">datastore exceptions</a>
5354
* ({@code DatastoreTimeoutException}, {@code ConcurrentModificationException}, {@code DatastoreFailureException})
54-
* will be thrown from {@code Ref<?>.get()}.</p>
55+
* can be thrown from {@code Result} operations.</p>
5556
*
5657
* @param ref holds the key to fetch and will receive the asynchronous result.
57-
* @return the exact ref passed in
58+
* @return a result which can materialize the entity.
5859
*/
59-
<E> Ref<E> ref(Ref<E> ref);
60+
<E> LoadResult<E> ref(Ref<E> ref);
6061

6162
/**
6263
* <p>Load multiple refs in a batch operation. This starts an asynchronous fetch.</p>
6364
*
6465
* <p>Since fetching is asynchronous,
6566
* <a href="http://code.google.com/appengine/articles/handling_datastore_errors.html">datastore exceptions</a>
6667
* ({@code DatastoreTimeoutException}, {@code ConcurrentModificationException}, {@code DatastoreFailureException})
67-
* will be thrown from {@code Ref<?>.get()}.</p>
68+
* can be thrown from the map operations.</p>
6869
*
6970
* @param refs provide the keys to fetch and will receive the asynchronous result.
7071
* @return as an alternative to accessing the Refs directly, a Map of the asynchronous result.
@@ -82,12 +83,12 @@ public interface Loader extends SimpleQuery<Object>
8283
* <p>Since fetching is asynchronous,
8384
* <a href="http://code.google.com/appengine/articles/handling_datastore_errors.html">datastore exceptions</a>
8485
* ({@code DatastoreTimeoutException}, {@code ConcurrentModificationException}, {@code DatastoreFailureException})
85-
* will be thrown from {@code Ref<?>.get()}.</p>
86+
* can be thrown from {@code Result} operations.</p>
8687
*
8788
* @param key defines the entity to fetch
88-
* @return a Ref<?> which holds the asynchronous result
89+
* @return a result which can materialize the entity
8990
*/
90-
<E> Ref<E> key(Key<E> key);
91+
<E> LoadResult<E> key(Key<E> key);
9192

9293
/**
9394
* <p>Load multiple entities by key from the datastore in a batch. This starts an asynchronous fetch.</p>
@@ -110,29 +111,25 @@ public interface Loader extends SimpleQuery<Object>
110111
/**
111112
* <p>Load a single entity which has the same id/parent as the specified entity. This starts an asynchronous fetch.</p>
112113
*
113-
* <p>This is typically used to retrieve "unfetched" entities which have been returned as fields in other entities.
114-
* These unfetched entities will have their key fields (id/parent) filled but otherwise be uninitialized.</p>
114+
* <p>This is a shortcut for {@code key(Key.create(entity))}.</p>
115115
*
116116
* <p>Since fetching is asynchronous,
117117
* <a href="http://code.google.com/appengine/articles/handling_datastore_errors.html">datastore exceptions</a>
118118
* ({@code DatastoreTimeoutException}, {@code ConcurrentModificationException}, {@code DatastoreFailureException})
119-
* will be thrown from {@code Ref<?>.get()}.</p>
119+
* may be thrown from {@code Result} operations.</p>
120120
*
121121
* @param entity defines the entity to fetch; it must be of a registered entity type and have valid id/parent fields.
122-
* @return a Ref<?> which holds the asynchronous result
122+
* @return a result which can materialize the entity
123123
*/
124-
<E> Ref<E> entity(E entity);
124+
<E> LoadResult<E> entity(E entity);
125125

126126
/**
127127
* <p>Load multiple entities from the datastore in a batch. This starts an asynchronous fetch.</p>
128128
*
129-
* <p>This is typically used to retrieve "unfetched" entities which have been returned as fields in other entities.
130-
* These unfetched entities will have their key fields (id/parent) filled but otherwise be uninitialized.</p>
131-
*
132129
* <p>Since fetching is asynchronous,
133130
* <a href="http://code.google.com/appengine/articles/handling_datastore_errors.html">datastore exceptions</a>
134131
* ({@code DatastoreTimeoutException}, {@code ConcurrentModificationException}, {@code DatastoreFailureException})
135-
* will be thrown when the Map is accessed.</p>
132+
* may be thrown when the Map is accessed.</p>
136133
*
137134
* @param entities must be a list of objects which belong to registered entity types, and must have id & parent fields
138135
* properly set.
@@ -154,20 +151,18 @@ public interface Loader extends SimpleQuery<Object>
154151
* <li>Standard Objectify Key<?> objects.</li>
155152
* <li>Native datastore Key objects.</li>
156153
* <li>Ref<?> objects.</li>
157-
* <li>Registered entity instances which have id and parent fields populated. This is typically used to retrieve "unfetched"
158-
* entities which have been returned as fields in other entities. These unfetched entities will have their key fields
159-
* (id/parent) filled but otherwise be uninitialized.</li>
154+
* <li>Registered entity instances which have id and parent fields populated.</li>
160155
* </ul>
161156
*
162157
* <p>Since fetching is asynchronous,
163158
* <a href="http://code.google.com/appengine/articles/handling_datastore_errors.html">datastore exceptions</a>
164159
* ({@code DatastoreTimeoutException}, {@code ConcurrentModificationException}, {@code DatastoreFailureException})
165-
* will be thrown from {@code Ref<?>.get()}.</p>
160+
* may be thrown from {@code Result} operations.</p>
166161
*
167162
* @param key defines the entity to fetch; can be anything that represents a key structure
168163
* @return a Ref<?> which holds the asynchronous result
169164
*/
170-
<E> Ref<E> value(Object key);
165+
<E> LoadResult<E> value(Object key);
171166

172167
/**
173168
* <p>Fetch multiple entities from the datastore in a batch. This starts an asynchronous fetch.</p>
@@ -178,15 +173,13 @@ public interface Loader extends SimpleQuery<Object>
178173
* <li>Standard Objectify Key<?> objects.</li>
179174
* <li>Native datastore Key objects.</li>
180175
* <li>Ref<?> objects.</li>
181-
* <li>Registered entity instances which have id and parent fields populated. This is typically used to retrieve "unfetched"
182-
* entities which have been returned as fields in other entities. These unfetched entities will have their key fields
183-
* (id/parent) filled but otherwise be uninitialized.</li>
176+
* <li>Registered entity instances which have id and parent fields populated.</li>
184177
* </ul>
185178
*
186179
* <p>Since fetching is asynchronous,
187180
* <a href="http://code.google.com/appengine/articles/handling_datastore_errors.html">datastore exceptions</a>
188181
* ({@code DatastoreTimeoutException}, {@code ConcurrentModificationException}, {@code DatastoreFailureException})
189-
* will be thrown when the Map is accessed.</p>
182+
* may be thrown when the Map is accessed.</p>
190183
*
191184
* @param keysOrEntities defines a possibly heterogeneous mixture of Key<?>, Ref<?>, native datastore Key, or registered
192185
* entity instances with valid id/parent fields.

0 commit comments

Comments
 (0)