Spring Frameworkã使ã£ã¦REST APIãä½ãã¤ã¤ããã®è¿å´å¤ã¨ãã¦JPAã®Entityã使ãã¾ãããã¨ããã¨ããã¨ã©ã¼ã«æ©ã¾ããããã®è§£æ±ºçã«ã¤ãã¦ãæ¥æ¬èªã§æ¸ããã¦ããæ å ±ããªãã£ãã®ã§ãããã«å ±æãã¾ãã
åé¡ãçºçããæ¡ä»¶
- JPAã®Entityãè¿å´å¤ã¨ãã¦ç¨ãã¦ãã
- Entityã®ä¸ã§ãªã¬ã¼ã·ã§ã³ãå®ç¾©ãã¦ãã
ãæ¡ä»¶ã¨ãªãã¾ãã
ã©ã®ãããªåé¡ãçºçããã
JPAã§ãªã¬ã¼ã·ã§ã³ãè¨å®ããéã親ããåã¸ã®ãªã¬ã¼ã·ã§ã³ã ãã§ãªããåãã親ã¸ã®ãªã¬ã¼ã·ã§ã³ãå®ç¾©ããå¿ è¦ãããã¾ãã
å ·ä½çã«ããã¨
/** 親ãã¼ãã« */ @Entity @Table(name = "parent") public class Parent implements Serializable { @Id String id; String name; @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true) List<Child> children; // åã®å®ç¾© // ç¥ @Override public String toString() { return "Parent{" + "id='" + id + '\'' + ", name='" + name + '\'' + ", children=" + children + '}'; } }
/** åãã¼ãã« */ @Entity @Table(name = "child") @IdClass(ChildPk.class) public class Child implements Serializable { private static final long serialVersionUID = 1L; @Id @ManyToOne Parent parent; // 親ã®å®ç¾© @Id String childId; String name; // ç¥ @Override public String toString() { return "Child{" + "parent=" + parent.getId() + ", childId='" + childId + '\'' + ", name='" + name + '\'' + '}'; } }
ã¨ãã£ãå½¢ã«ãªãã¾ãã
ã¤ã¾ãããªãã¸ã§ã¯ãã®å½¢ã¨ãã¦ã¯ã親ã¯åãæã¡ãåã親ãæã£ã¦ããããã§ã循ç°åç §ã®å½¢æ ãã¨ãã¾ãã
ããã
@RequestMapping(value = "") public Parent create() { Parent result = service.getData(); System.out.println(result); return result; }
ã¨ãã¦Parentãæ»ãã¨ãã¦controllerãå¼ã³åºãã¨ãconsoleã§ã¯
Parent{id='1', name='one', children=[Child{parent=1, childId='a', name='1-a'}]}
ã¨è¡¨ç¤ºããã¾ããããã©ã¦ã¶ä¸ã§ã¯å ã»ã©ã®å¾ªç°åç §ã®åé¡ã«ããã
ã¨ãã¦ã°ãç»åçãªè¡¨ç¤ºã«ãªã
2016-03-20 00:27:34.369 ERROR 18687 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: Infinite recursion (StackOverflowError) (through reference chain: com.example.entity.Parent["children"]->org.hibernate.collection.internal.PersistentBag[0]->com.example.entity.Child["parent"]->com.example.entity.Parent["children"]->org.hibernate.collection.internal.PersistentBag[0]->com.example.entity.Child["parent"]->com.example.entity.Parent["children"]->org.hibernate.collection.internal.PersistentBag[0]->com.example.entity.Child["parent"]->ãç¥ãcom.example.entity.Parent["children"])] with root cause java.lang.StackOverflowError: null at java.lang.ClassLoader.defineClass1(Native Method) ~[na:1.8.0_65] ãç¥ã
ã¨StackOverflowErrorãèµ·ããã¦ãã¾ãã¾ãã
解決æ¹æ³
ã«è§£æ±ºæ¹æ³ãããã¾ããã
@JsonIdentityReferenceãæå®ãã¦ãããã ãã§ããJSONã«å¤æããéã«ãæã£ã¦ãããªãã¸ã§ã¯ããå±éããã®ã§ã¯ãªãããã®ãªãã¸ã§ã¯ãã®IDã使ãããã«ãã¦ãããæãã§ããã
å
ã»ã©ã®ä¾ã ã¨Parent parent;
ã«å¯¾ãã¦
@Id @ManyToOne @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") // ãã®ã¢ããã¼ã·ã§ã³ã追å @JsonIdentityReference(alwaysAsId = true) // ãã®ã¢ããã¼ã·ã§ã³ã追å Parent parent;
ã¨ãã¦ããããã¨ã§
ã¨JSONãåºæ¥ä¸ããã¾ããã説æããã¾ã§ããªãããããã¾ãããã@JsonIdentityInfo
ã«ã¦ä½ãå½è©²ãªãã¸ã§ã¯ãã®èå¥åã¨ãã¦å©ç¨ãããæ示ãã@JsonIdentityReference
ã«ã¦ãåç
§å
å±éã®ä»£ããã«èå¥åãå©ç¨ããã¨å½ãã¦ããæãã§ãã
ãªãã@JsonIgnoreProperties
ã¨ããã¢ããã¼ã·ã§ã³ãã¯ã©ã¹ã«æå®ã
@Entity @Table(name = "child") @IdClass(ChildPk.class) @JsonIgnoreProperties({"parent"}) // ãããæå¹åãããã¨ã§ãparentèªä½ãjsonã«å«ããªãæå®ãå¯è½ public class Child implements Serializable { ãç¥ã }
ã¨ãã¦æ¬ä¾ã§ããã¨ããã®childãæã¤parentãJSONã«åºåããªããã¨ãå¯è½ã§ãã
ã½ã¼ã¹ã³ã¼ã
ã¨ãããã¨ã§ãæ¥æ¬èªã§JsonIdentityReferenceã¨ã°ã¼ã°ã«æ¤ç´¢ãã¦ãåºã¦ããªãã£ãã®ã§è¨äºã«ãã¦ã¿ã¾ããã
åãåé¡ã«é·æéã¯ã¾ã人ãï¼äººã§ãæ¸ããã¨ãç¥ã£ã¦ã¾ãï¼RESTãªã¢ããªã±ã¼ã·ã§ã³ä½ãã®ã«ãJavaã£ã¦é¸æè¢ãããããããã¾ãç¡ãã®ããªãã¨ãæã£ãããã¾ããï¼