Dan Vega
Dan Vega

Reputation: 1107

Spring Boot REST Controller issues

I am having a very strange issue with a Rest Controller. I have a very basic rest controller.

package com.therealdanvega.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.therealdanvega.domain.Post;
import com.therealdanvega.service.PostService;

@RestController
public class PostController {

    private PostService postService;

    @Autowired
    public PostController(PostService postService){
        this.postService = postService;
    }

    @RequestMapping("posts/test")
    public String test(){
        return "test...";
    }

    @RequestMapping( name="/posts/", method=RequestMethod.GET )
    public Iterable<Post> list(){
        return postService.list();
    }


}

That calls a service

package com.therealdanvega.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.therealdanvega.domain.Post;
import com.therealdanvega.repository.PostRepository;

@Service
public class PostService {

    private PostRepository postRepository;

    @Autowired
    public PostService(PostRepository postRepository){
        this.postRepository = postRepository;
    }

    public Iterable<Post> list(){
        return postRepository.findAll();
    }

}

That calls a repository to fetch the data.

package com.therealdanvega.repository;

import java.util.List;

import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

import com.therealdanvega.domain.Post;

@Repository
public interface PostRepository extends CrudRepository<Post, Long> {

    Post findFirstByOrderByPostedOnDesc();

    List<Post> findAllByOrderByPostedOnDesc();

    Post findBySlug(String slug);

}

I am using an H2 in memory database and I only have a single Post record in there and can confirm so by going to the H2 console and running a select again the Post table.

If I visit the /test URL I get exactly what I am expecting which is the string "test..." printed to the browser. If I try and list all of the posts (which again is only 1) the browser starts looping over and over and continue to print out a JSON representing of the 1 post so many times that the application crashes and I see this in the console

2015-11-07 17:58:42.959 ERROR 5546 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet dispatcherServlet threw exception java.lang.IllegalStateException: getOutputStream() has already been called for this response

This is what my browser looks like when I visit /posts which should only list 1

enter image description here

Post Domain Class

package com.therealdanvega.domain;

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import org.springframework.data.annotation.CreatedDate;


@Entity
public class Post {

    @Id @GeneratedValue
    private Long id;
    private String title;

    @Column(columnDefinition = "TEXT")
    private String body;

    @Column(columnDefinition = "TEXT")
    private String teaser;

    private String slug;

    @CreatedDate 
    @Temporal(TemporalType.TIMESTAMP)
    private Date postedOn;

    @ManyToOne
    private Author author;

    @SuppressWarnings("unused")
    private Post(){
    }

    public Post(String title){
        this.setTitle(title);
    }

    // getters & setters
}

Does anyone know what I am doing wrong or missing here? Why isn't it just display the 1 record in JSON format?

Upvotes: 0

Views: 763

Answers (2)

Jean-Philippe Bond
Jean-Philippe Bond

Reputation: 10649

It seems that your Post object has a circular reference. The Author object in your Post object has a list of Posts objects and so on. Try putting the @JsonIgnore annotation on the author attribute of your post object.

You can also use the @JsonBackReference and @JsonManagedReference to solve the problem.

From the Jackson documentation :

Object references, identity

@JsonManagedReference, @JsonBackReference: pair of annotations used to indicate and handle parent/child relationships expressed with pair of matching properties @JsonIdentityInfo: class/property annotation used to indicate that Object Identity is to be used when serializing/deserializing values, such that multiple references to a single Java Object can be properly deserialized. This can be used to properly deal with cyclic object graphs and directed-acyclic graphs.

Upvotes: 3

Zoran Regvart
Zoran Regvart

Reputation: 4690

I believe your Posts domain object contains Author domain object, that in turn in it's posts field contains all the posts by that author, which in turn contains author that contains posts... you see where I'm going with this.

It's probably best that you use fetch or load graphs to optimize your query's fetch strategy.

Upvotes: 1

Related Questions