This tutorial demonstrates using Objectify to read/write data from the Google App Engine DataStore.
The example used in this tutorial is three end points:
POST /posts {"message":"Message to post"} to create a post GET /posts/{id} to obtain a particular postGET /posts to obtain all postsThe REST endpoints are configured as follows:
savePost: class: net.officefloor.tutorial.objectifyhttpserver.ObjectifyLogic method: savePost
retrieveAllPosts: class: net.officefloor.tutorial.objectifyhttpserver.ObjectifyLogic method: retrieveAllPosts
retrievePost: class: net.officefloor.tutorial.objectifyhttpserver.ObjectifyLogic method: retrievePost
With the implementation as follows:
public class ObjectifyLogic {
public void savePost(Post post, Objectify objectify) {
objectify.save().entities(post).now();
}
public void retrievePost(@HttpPathParameter("id") String identifier, Objectify objectify,
ObjectResponse<Post> response) {
Post post = objectify.load().type(Post.class).id(Long.parseLong(identifier)).now();
response.send(post);
}
public void retrieveAllPosts(Objectify objectify, ObjectResponse<List<Post>> response) {
List<Post> posts = objectify.load().type(Post.class).list();
response.send(posts);
}
}
Note: the passed in Objectify will always obtain the appropriate context (regardless of being in a transaction or not).
The Objectify entity is as follows:
@Entity
@HttpObject
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Post {
@Id
private Long id;
private String message;
}
Objectify is configured in officefloor/suppliers/Objectify.yml as follows:
source: net.officefloor.nosql.objectify.ObjectifySupplierSource properties: objectify.entity.locators: net.officefloor.tutorial.objectifyhttpserver.ObjectifyEntities
For performance reasons, the entities are not dynamically discovered. As Google App Engine allows scaling to zero instances, the application must be brought up quickly to service the first request. Having to inspect all jars and classes for entities is typically too slow. Therefore, Objectify requires registering all entities with it manually.
Therefore, to make the entities available to Objectify, the following is the above configured class:
public class ObjectifyEntities implements ObjectifyEntityLocator {
@Override
public Class<?>[] locateEntities() throws Exception {
return new Class[] { Post.class };
}
}
Note: for third party libraries requiring to store data, it is also possible to register entities via a ObjectifyEntityLocatorServiceFactory. This allows the entities to be automatically registered when the library is added to the class path.
To make local testing easier, the following unit tests demonstrate automatically setting up a local data store for testing.
@Order(1)
@RegisterExtension
public final ObjectifyExtension objectify = new ObjectifyExtension();
@Order(2)
@RegisterExtension
public final MockWoofServerExtension server = new MockWoofServerExtension();
@Test
public void ensureCreatePost() throws Exception {
// Have server create the post
Post post = new Post(null, "TEST");
MockWoofResponse response = this.server.send(MockWoofServer.mockJsonRequest(HttpMethod.POST, "/posts", post));
response.assertResponse(204, "");
// Ensure post created
Post created = this.objectify.get(Post.class);
assertEquals("TEST", created.getMessage(), "Incorrect post");
}
JUnit 4 example:
private final ObjectifyRule objectify = new ObjectifyRule();
private final MockWoofServerRule server = new MockWoofServerRule();
@Rule
public final RuleChain ordered = RuleChain.outerRule(this.objectify).around(this.server);
@Test
public void ensureCreatePost() throws Exception {
// Have server create the post
Post post = new Post(null, "TEST");
MockWoofResponse response = this.server.send(MockWoofServer.mockJsonRequest(HttpMethod.POST, "/posts", post));
response.assertResponse(204, "");
// Ensure post created
Post created = this.objectify.get(Post.class);
assertEquals("Incorrect post", "TEST", created.getMessage());
}
Return to the tutorials index.