Ben R
Ben R

Reputation: 168

Marshalling Spring JPA one to many objects into JSON

I am trying to marshal 3 JPA objects into a JSON string. The Game object holds a list of players, and each player holds a list of frames. The JPA part seems to be working fine. However, the JSON output is empty.

Game.java

package com.bowling.bowlingapp.game;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

/**
 * A single bowling game
 *
 */
@Entity
@Table( name = "games")
public class Game {

     @Id @GeneratedValue
     @JsonIgnore
     private Long id;

     @OneToMany(cascade = CascadeType.ALL,
             fetch = FetchType.LAZY,
             mappedBy = "game")
     @JsonManagedReference
     List<Player> players;

     public List<Player> getPlayers() {
          return players;
     }

     public void setPlayers(List<Player> players) {
          this.players = players;
     }

     public void addPlayer(Player player) {
          if (this.players == null) {
               players = new ArrayList<>();
          }
          this.players = players;
     }
}

Player.java

package com.bowling.bowlingapp.game;

import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import javax.persistence.*;
import java.util.List;

/**
 * A bowler
 *
 */
@Entity
@Table(name = "players")
public class Player {

    @Id
    @GeneratedValue
    @JsonIgnore
    private Long id;

    @Column
    private String name;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "game_id", nullable = false)
    @JsonBackReference
    private Game game;

    @OneToMany(cascade = CascadeType.ALL,
            fetch = FetchType.LAZY,
            mappedBy = "player")
    @JsonManagedReference
    List<Frame> frames;

    public Player(String name) {
        this.name = name;
    }

    public void setFrames(List<Frame> frames) {
        this.frames = frames;
    }
}

Frame.java

package com.bowling.bowlingapp.game;

import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;
import javax.persistence.*;

/**
 * an object representing a frame.
 * Each value will be -1 until set
 *
 */
@Entity
@Table(name = "frames")
public class Frame {

    @Id
    @GeneratedValue
    private Long id;

    @Column
    private int firstRoll = -1;
    @Column
    private int secondRoll = -1;
    //3rd roll for tenth frame
    @Column
    private int thirdRoll = -1;
    @Column
    private int score = -1;

    @JsonIgnore
    private final static int NUMBER_OF_PINS=10;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "player_id", nullable = false)
    @OnDelete(action = OnDeleteAction.CASCADE)
    @JsonBackReference
    private Player player;
   
    public void setScore(int score) {
        this.score = score;
    }

}

I am trying to marashall it with this code:

public String makeGame() {

        Player bob = new Player("Bob");
        Player joe = new Player("Joe");
        Frame frameOne = new Frame();
        frameOne.setScore(12);
        Frame frameTwo = new Frame();
        frameTwo.setScore(15);
        List<Frame> frames = new ArrayList<>();
        bob.setFrames(frames);
        joe.setFrames(frames);

        List<Player> players = new ArrayList<>();
        players.add(bob);
        players.add(joe);
        Game game = new Game();
        game.setPlayers(players);

        ObjectMapper mapper = new JsonMapper();
        String result = "temp";
        try {
            result = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(game);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

        return result;

    }

however my output looks like this:

{
"players" : [
    { 
      "frames" : [ ] 
    }, 
    { "frames" : [ ] 
    } 
    ]
}

As you can see it is empty. What am I doing wrong?

EDIT: Now I added getters and setters for every private attribute, and the output looks like this:

{
"players" : [ {
"name" : "Bob",
"frames" : [ ]
}, {
"name" : "Joe",
"frames" : [ ]
} ]

EDIT: I forgot to add frames.add(frameOne); frames.add(frameTwo); to my builder code. Now it works. Thank you!

Upvotes: 1

Views: 1040

Answers (1)

Girija Sankar Panda
Girija Sankar Panda

Reputation: 318

Object Mapper behind the scene uses the getter method of all property. Please declare the getter methods in all 3 classes.

Upvotes: 2

Related Questions