Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring REST Controller returns empty JSON. Iterable data structure. Why?

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>[email protected]</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; 
  }


}
like image 912
ElectronicBlacksmith Avatar asked Mar 05 '18 18:03

ElectronicBlacksmith


3 Answers

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.

like image 76
ElectronicBlacksmith Avatar answered Nov 09 '22 19:11

ElectronicBlacksmith


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

Making them public fixed the issue for me.

like image 30
TheCommonEngineer Avatar answered Nov 09 '22 21:11

TheCommonEngineer


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!

like image 37
Sasi Avatar answered Nov 09 '22 21:11

Sasi