0

I have a class User defined as

@Entity
@Table(name = "users")
@JsonIdentityInfo(generator = ObjectIdGenerators.UUIDGenerator.class, property = "jsonUUID")
public class User implements Serializable, UserDetails
{
    private static final long serialVersionUID = -7035881497059422985L;
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    protected Long                 id;
    protected String               firstname;
    protected String               lastname;
    protected String               username;
    protected ProfessionalCategory professional;
    protected String               companyName;
    @Email
    protected String               email;
    protected String               password;
    @ManyToMany(cascade = CascadeType.ALL)
    @JoinTable
        (
            name = "role_user",
            joinColumns = @JoinColumn(name = "user_id"),
            inverseJoinColumns = @JoinColumn(name = "role_id")
        )
    protected Set<Role>            roles;
}

When I perform a GET request on /users/{id} I want Hibernate to fetch the value from all the fields in user and return the "full" object. But when I perform a GET request on /users/ I want to return a list of users containing only firstname and lastname. I do not just want Jackson to ignore certain fields during serialization, I also want Hibernate not to fetch data it does not need (because fetching all the roles for each user can be very costly since I use a join table).

I know I could write my own SQL queries, but then I would loose the benefits of using Hibernate. So is there an elegant way of solving this problem?

Brendan Rius
  • 610
  • 9
  • 18

1 Answers1

0

The most elegant solution is to use Hibernate criteria and specify two different methods inside your DAO. One method will fetch a single user based on their ID, the other will fetch a list of all users with only first name and last name populated by using a ProjectionList.

public List<User> getAllUsers() {
    Criteria query = sessionFactory.getCurrentSession().createCriteria(User.class);
    query.setProjection(Projections.projectionList()
        .add(Projections.property("firstName"), "firstName")
        .add(Projections.property("lastName"), "lastName"))
    .setResultTransformer(Transformers.aliasToBean(User.class));

    return query.list();
}

The above code causes Hibernate to only fetch the firstName and lastName fields from the database, and then map the results back to your User class using the ResultTransformer. This method is less than ideal, because it is confusing that all the fields aren't populated.

The ideal solution would be to lazily load your collection of roles, so that Hibernate only loads it on request. For more information on how you can set this up, refer to my Q&A here.

Community
  • 1
  • 1
JamesENL
  • 6,400
  • 6
  • 39
  • 64