9

I realize a very similar question was asked and closed because it wasn't specific enough and didn't specify outcomes. Closed Off Topic

Problem: JSON being returned from REST controller is empty. Verified data exists and is in the Iterable.

Expected Outcome: A JSON Array containing objects would be returned.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.codeexcursion</groupId>
  <organization>
    <name>Chris Lynch</name>
  </organization>
  <version>1.00.000</version>
  <artifactId>work-tracking</artifactId>
  <packaging>jar</packaging>

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.10.RELEASE</version>
  </parent>

  <properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>


  <name>Work Tracking</name>

  <inceptionYear>2017</inceptionYear>

  <developers>
    <developer>
      <id />
      <name>Chris Lynch</name>
      <email>chrislynch42@yahoo.com</email>
      <timezone>-4</timezone>
      <roles>
        <role>Chief cook and bottle washer.</role>
      </roles>
    </developer>
  </developers>

  <dependencies>
    <dependency>
      <groupId>org.mockito</groupId>
      <artifactId>mockito-all</artifactId>
      <version>1.10.19</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
      <version>1.5.10.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <version>1.5.10.RELEASE</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-jpa</artifactId>
      <version>1.5.10.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-rest</artifactId>
      <version>1.5.10.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.apache.derby</groupId>
      <artifactId>derby</artifactId>
      <version>10.13.1.1</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>


  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <configuration>
          <mainClass>com.codeexcursion.Application</mainClass>
        </configuration>
      </plugin>
    </plugins>
  </build>

</project>

Entity

//Package and import Omitted

@Entity
public class Category {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;

  private Long parentId;

  private String title;

  private String description;

  protected Category() {
  }

  public Category(final String title, String description) {
    this(0L, title, description);
  }

  public Category(Long parentId, final String title, String description) {
    if (parentId == null) {
      parentId = 0L;
    }
    if (title == null || title.trim().isEmpty()) {
      throw new IllegalArgumentException("Title may not be null or empty.");
    }
    if (description == null) {
      description = "";
    }
    this.parentId = parentId;
    this.title = title;
    this.description = description;
  }

  @Override
  public String toString() {
    return "id = " + id + "; parentId=" + parentId + "; title=" + title + "; description=" + description;
  }


}

Resource

//Package and import Omitted

@Repository
public interface CategoryCRUD  extends CrudRepository<Category, Long> {
  List<Category> findByTitle(String title);
}

Rest Controller

//Package and import Omitted

@RestController
@RequestMapping("/categories")
public class CategoryController {

  @Autowired
  private CategoryCRUD categoryCRUD;  


  @RequestMapping(value = "", method = RequestMethod.GET)
  public @ResponseBody Iterable<Category> list() {
    System.out.println("findAll");
    categoryCRUD.findAll().forEach((category) -> {
      System.out.println("category=" + category);
    });    
    return categoryCRUD.findAll();
  }

  private List<Category> findAll() {
    final Iterable<Category> data = categoryCRUD.findAll();
    List<Category> returnList = new ArrayList<>();
    data.forEach(returnList::add);
    return returnList; 
  }


}
Michael Petch
  • 46,082
  • 8
  • 107
  • 198

3 Answers3

21

I found an answer that was hinted on the closed post but wasn't detailed. I needed to add getters to my entity. I expected JPA/Spring to automagically add the getters and setters. The below fixed my problem.

Entity

//Package and imports omitted
@Entity
public class Category {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;

  private Long parentId;

  private String title;

  private String description;

  protected Category() {
  }

  public Category(final String title, String description) {
    this(0L, title, description);
  }

  public Category(Long parentId, final String title, String description) {
    if (parentId == null) {
      parentId = 0L;
    }
    if (title == null || title.trim().isEmpty()) {
      throw new IllegalArgumentException("Title may not be null or empty.");
    }
    if (description == null) {
      description = "";
    }
    this.parentId = parentId;
    this.title = title;
    this.description = description;
  }

  @Override
  public String toString() {
    return "id = " + id + "; parentId=" + parentId + "; title=" + title + "; description=" + description;
  }

  public Long getId() {
    return id;
  }

  public Long getParentId() {
    return parentId;
  }

  public String getTitle() {
    return title;
  }

  public String getDescription() {
    return description;
  }

}

Better answers are welcome.

  • 1
    If you want getters/setters to be generated automatically, you might want to have a look at project lombok: https://projectlombok.org/ – blurfus Mar 05 '18 at 19:09
  • Mate thank you so much ! Worked like a charm. just added getters to my model and that did the trick. so silly to have forgotten! – MrHunchoJack Apr 30 '21 at 15:01
14

In my case, the getters to the fields of the entity were not public.

Making them public fixed the issue for me.

2

You have to include the lombok dependency in your pom.xml file and you have to setup the lombok jar in the IDE you are using (Can be Intellij or Eclipse). if you want to use the annotations @Data, it automatically generates the getters, setters and toString() method inside a Java Bean or Pojo class.

You can use @Getter, @Setter, @AllArgsConstructor, @NoArgsConstructor javadoc annotation from lombok will generate the getters and setters and constructors for your fields.

Please have a look at this http://www.baeldung.com/intro-to-project-lombok for more information.

Thanks!

Sasi
  • 140
  • 1
  • 8
  • 1
    Am I correct in the understanding that Lombok isn't part of Spring but is a 3rd party library that provides getter and setter annotations? – ElectronicBlacksmith Mar 05 '18 at 20:17
  • Yes, its a thirt party dependency, which is predominantly used in many projects. And if you are using spring boot, you can include it in http://start.spring.io (spring project initializer). Yes it is not a part of Spring framework. – Sasi Mar 05 '18 at 20:21