Home > Mobile >  JPA Returning Empty Set When Should Be Empty Optional<>
JPA Returning Empty Set When Should Be Empty Optional<>

Time:12-19

I have the following two entities:

@Entity
@Table(name = "organization")
@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
public class Organization {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    Long id;

    @Column(name = "name")
    String name;

    @OneToMany(mappedBy = "organization")
    Set<Team> teams;
    
}
@Entity
@Table(name = "team")
@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
public class Team {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    Long id;

    @Column(name = "name")
    String name;

    @Column(name = "description")
    String description;

    @ManyToOne
    @JoinColumn(name="organization_id", nullable=false)
    Organization organization;
    
}

And the following two repositories for those entities

@Repository
public interface OrganizationRepo extends CrudRepository<Organization, Long> {
    
}
@Repository
public interface TeamRepo extends CrudRepository<Team, Long> {

    Optional<Set<Team>> findByOrganizationId(Long organizationId);

    Optional<Team> findByOrganizationIdAndTeamId(Long organizationId, Long teamId);
    
}

I then try to use the findByOrganizationId(..) method with an organizationId which does not exist, and want it to return an empty optional, but instead I get a HashSet<> with 0 items? Is there a way that I can accomplish this functionality with a JPA method?

    @Autowired
    TeamRepo repository;

    @ResponseBody
    @GetMapping(value = "/api/v1/organization/{organizationId}/team")
    ResponseEntity<Iterable<Team>> index(@PathVariable Long organizationId) {

        Optional<Set<Team>> result = repository.findByOrganizationId(organizationId);

        if(result.isPresent()) {

            return new ResponseEntity<>(result.get(), HttpStatus.OK);

        } else {

            return new ResponseEntity<>(HttpStatus.NOT_FOUND);

        }

    }

Edit: As Organization to Teams is a OneToMany relationship, it is reasonable that if there is no Organization, it should return an empty Optional<>, but if there is an Organization with 0 or more teams, it should return an Optional<> with a Set<> of zero or more teams.

CodePudding user response:

When you use collections as results you don't need to wrap it in Optional, you can check the collection directly with isEmpty() method:

@Repository
public interface TeamRepo extends CrudRepository<Team, Long> {

    Set<Team> findByOrganizationId(Long organizationId);

    Optional<Team> findByOrganizationIdAndTeamId(Long organizationId, Long teamId);
    
}




@Autowired
TeamRepo repository;

@ResponseBody
@GetMapping(value = "/api/v1/organization/{organizationId}/team")
ResponseEntity<Iterable<Team>> index(@PathVariable Long organizationId) {

    Set<Team> result = repository.findByOrganizationId(organizationId);

    if(!result.isEmpty()) {

        return new ResponseEntity<>(result, HttpStatus.OK);

    } else {

        return new ResponseEntity<>(HttpStatus.NOT_FOUND);

    }

}

Effective Java book states that: Container types, including collections, maps, streams, arrays, and optionals should not be wrapped in optionals.

  • Related