简体   繁体   中英

Jackson JSON and lazy loaded collections

I have a class which lazy loads a collection. Now I have two different Queries, one that loads the data without the collection and another which loads the whole data. When executing the Query which doesn't load the collection I get the following error:

JsonMappingException: failed to lazily initialize a collection of role: Player.goals

I tried to fix that with using the @JsonInclude(JsonInclude.Include.NON_EMPTY) annotation but that didn't help.

How do I produce two different JSON Results based on the same Class?

Update: Updated the structure and added JSONView but the error didn't change.

Model

@Entity
public class User implements Serializable {
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "owner")
    private Collection<Team> teams = new ArrayList<Team>();
}

@Entity
public class Team implements Serializable {
  ...
  @OneToMany(cascade = CascadeType.ALL, mappedBy = "team", targetEntity = Player.class, fetch = FetchType.EAGER)
  @JsonView(UserViews.User.class)
  private Collection<Player> players = new ArrayList<Player>();
  ...
}

@Entity
public class Player implements Serializable {
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "player", targetEntity = Goal.class, fetch = FetchType.LAZY)
    @JsonView(UserViews.UserWithGoals.class)
    private Collection<Goal> goals= new ArrayList<Goal>();
...
}

Queries

@Query("SELECT u FROM User u WHERE u.id = :id")
Team findById(@Param("id") Long id);

Spring Controller

@RequestMapping(headers = "Accept=application/json")
@JsonView(UserViews.User.class)
public @ResponseBody Team getTeam(Authentication authentication) {
    User user = userService.findById(1);

    return team;
}

With this configuration accessing the controller shouldn't load the Goals of the Player class, but that's exactly the mentioned part in the JSONMappingException. Any idea what's wrong?

Maybe you can take a look to Jackson JsonViews : http://wiki.fasterxml.com/JacksonJsonViews .

You will have to define two different views in your entity:

@Entity
public class Team implements Serializable {
    ...
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "team", targetEntity = Player.class, fetch = FetchType.LAZY)
    @JsonView(FullView.class)
    private Collection<Player> players = new ArrayList<Player>();
    ...
}

and activate the view in you caller method (typically you JAX-RS implementation - see http://wiki.fasterxml.com/JacksonJsonViews#Views_with_JAX-RS )

Doing this, the players list will be ignore in the first case and serialized in JSON only if the list is filled.

Syntax should not be correct, sorry, but you got the idea

To prevent lazy you can configure in Spring the OpenEntityManagerInVew filter in xml or in java (don't remember the exact syntax):

<filter>
    <filter-name>openEntityManagerInViewFilter</filter-name>
    <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>        
</filter>

<filter-mapping>
    <filter-name>openEntityManagerInViewFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Hope it helps

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM