Imaginez le Diagramme UML suivant :
![[Post]+1-*>[Comment]](http://yuml.me/diagram/scruffy/class/[Post]+1-*%3E[Comment])
Qui pourrait parfaitement représenter les Objets d’un Blog, mais pas que.
Imaginez que vous souhaitiez réaliser un API, compatible REST, qui vous permette de récupérer vos Posts et Comments au format JSon.
Nos Objets Métiers
Commençons tout d’abord par écrire nos objets Model :
app/models/Post.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
package models; import java.util.List; import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.OneToMany; import play.data.validation.Required; import play.db.jpa.Model; @Entity public class Post extends Model { @Required public String author; @Required public String title; @OneToMany(mappedBy = "post", cascade = CascadeType.ALL) public List<Comment> comments; } |
app/models/Comment.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
package models; import javax.persistence.Entity; import javax.persistence.Lob; import javax.persistence.ManyToOne; import play.data.validation.MaxSize; import play.data.validation.Required; import play.db.jpa.Model; @Entity public class Comment extends Model { @Required public String author; @Lob @Required @MaxSize(10000) public String content; @ManyToOne @Required public Post post; } |
Données de référence & Configuration
Pour nous simplifier la vie, Play! prévoit un mécanisme très pratique d’import de données, basé sur l’utilisation d’un fichier au format YAML
conf/initial-data.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
Post(post1): author: moi title: Post 1 Post(post2): author: moi title: Post 2 Comment(c1): author: moi content: du Contenu post: post1 Comment(c2): author: moi content: du Contenu post: post1 Comment(c3): author: moi content: du Contenu post: post2 |
conf/application.conf
Bootstrap Job & Controller
Le Bootstrap Job va nous permettre d’importer nos données de référence sans effort, et notre contrôleur devra réaliser notre besoin initial, à savoir nous retourner la liste des Posts
app/controllers/Bootstrap.java
|
|
package controllers; import models.Post; import play.jobs.Job; import play.jobs.OnApplicationStart; import play.test.Fixtures; @OnApplicationStart public class Bootstrap extends Job { public void doJob() { if (Post.count() == 0) { Fixtures.loadModels("initial-data.yml"); } } } |
app/controllers/Application.java
|
|
package controllers; import java.util.List; import models.Post; import play.mvc.Controller; public class Application extends Controller { public static void index() { List<Post> posts = Post.findAll(); renderJSON(posts); } } |
Premier résultat
Après avoir accédé via votre navigateur à l’adresse http://localhost:9000, vous devriez avoir l’erreur suivante :

Et dans votre console :
|
|
@67jf5njpa Internal Server Error (500) for request GET / Execution exception (In /app/controllers/Application.java around line 12) IllegalStateException occured : circular reference error Offending field: post Offending object: preserveType: false, type: class models.Post, obj: Post[1] |
Corrections
La méthode renderJSON prévoit l’utilisation de vos propre JSonSerializer. Ce que nous allons faire pour nos Objets Post et Comment.
app/models/serializer/PostJSonSerializer.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
|
package models.serializer; import java.lang.reflect.Type; import models.Post; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; public class PostJSonSerializer implements JsonSerializer<Post> { public static PostJSonSerializer instance; private PostJSonSerializer() { } public static PostJSonSerializer get() { if (instance == null) { instance = new PostJSonSerializer(); } return instance; } public JsonElement serialize(Post post, Type type, JsonSerializationContext jsonSerializationContext) { JsonObject obj = new JsonObject(); obj.addProperty("author", post.author); obj.addProperty("title", post.title); obj.add("comments", jsonSerializationContext.serialize(post.comments)); return obj; } } |
app/models/serializer/CommentJSonSerializer.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
|
package models.serializer; import java.lang.reflect.Type; import models.Comment; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; public class CommentJSonSerializer implements JsonSerializer<Comment> { public static CommentJSonSerializer instance; private CommentJSonSerializer() { } public static CommentJSonSerializer get() { if (instance == null) { instance = new CommentJSonSerializer(); } return instance; } public JsonElement serialize(Comment comment, Type type, JsonSerializationContext jsonSerializationContext) { JsonObject obj = new JsonObject(); obj.addProperty("author", comment.author); obj.addProperty("content", comment.content); return obj; } } |
On modifie par la suite l’appel à la méthode renderJSon dans le fichier app/controllers/Application.java:
|
|
... public static void index() { List<Post> posts = Post.findAll(); renderJSON(posts, PostJSonSerializer.get(), CommentJSonSerializer.get()); } ... |
Résultat final
Rafraîchissez l’adresse http://localhost:9000 pour obtenir le résultat suivant :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
|
[ { "author":"moi", "title":"Post 1", "comments":[ { "author":"moi", "content":"du Contenu" }, { "author":"moi", "content":"du Contenu" } ] }, { "author":"moi", "title":"Post 2", "comments":[ { "author":"moi", "content":"du Contenu" } ] } ] |
ps: Je vous livre ici mes observations sur le fonctionnement des JSonSerializer. Si vous voyez une façon de mieux les écrire, ou de mieux faire n’hésitez pas à commenter ce billet.