5

I want to load an UserReference object from the database, but from the verifier attribute I want to load only the id, firstName and lastName, so that the userReference would look something like this:

{
  "id": 1,
  "company": "company1",
  "companyContactName": "some name",
  "companyPosition": "programmer",
  "referenceDate": "02/04/2005",
  "verifier": {
        "id":1
        "firstName": "Jane",
        "lastName": "Smith"
        "email":null,
        "username":null,
        "office:null,
        "department":null
  }
}

I used an entity graph for the UserReference class, but the one I used loads all the information that the user has, including the email, username, office and department. Is there any way to specify something like EntityGraphType.FETCH to the subgraph, so that it will load only the id, firstName and lastName for the verifier?

This is my UserReferenceRepository:

public interface UserReferenceRepository extends JpaRepository<UserReference, Long>{

    @EntityGraph(value = "userReferenceGraph" ,  type = EntityGraphType.FETCH )
    UserReference findOne(Long id);
}

The UserReference class:

@Getter
@Setter
@EqualsAndHashCode (exclude = {"id", "verifier"})
@ToString(exclude = {"id"})
@Entity
@NamedEntityGraphs({
    @NamedEntityGraph(
        name = "userReferenceGraph",      
        attributeNodes = {
            @NamedAttributeNode(value = "verifier", subgraph = "verifierGraph")
    },
    subgraphs = {
        @NamedSubgraph( 
            name = "verifierGraph",
            type = User.class,
            attributeNodes = {
                @NamedAttributeNode(value = "id"),
                @NamedAttributeNode(value = "firstName"),
                @NamedAttributeNode(value = "lastName")})})
})

public class UserReference {

    @Id
    @GeneratedValue
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id", referencedColumnName = "user_id", foreignKey = @ForeignKey (name = "FK_UserReference_UserHRDetails_user_id"))
    @JsonIgnore
    private UserHRDetails hrDetails;

    private String company;
    private String companyContactName;
    private String companyPosition;
    private Date referenceDate;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "verifier_id")
    private User verifier;
}

and User:

@Getter @Setter
@EqualsAndHashCode(exclude = {"id", "department", "company", "authorities", "hrDetails"})
@ToString(exclude = {"password"})
@Entity
@AllArgsConstructor
@Builder
public class User implements Serializable{

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Access(value = AccessType.PROPERTY)
    private Long id;  

    @Size(max = 50)
    @Column(name = "first_name", length = 50)
    private String firstName;

    @Size(max = 50)
    @Column(name = "last_name", length = 50)
    private String lastName;

    @Column(length = 100, unique = true, nullable = false)
    private String email;

    @Column(length = 50, unique = true, nullable = false)
    private String username;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "department_id")
    private Department department;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "office_id")
    private Office office;
}
Neil Stockton
  • 11,383
  • 3
  • 34
  • 29
dd1714
  • 139
  • 1
  • 6

2 Answers2

3

I suppose you are using Jackson for generating JSON. In this case this is a battle Jackson vs. Entity Graph and former has no chance to win this battle. Entity Graph is just a hint for building SQL query and you can only tell Hibernate to not load some attributes. Hibernate still does not support Entity Graphs when it loads basic Entity fields, see https://hibernate.atlassian.net/browse/HHH-9270. But main problem is that Jackson will call every getter in your Entity during JSON generation and Hibernate will lazy load them not taking into consideration your Entity Graph. I can propose only @JsonIgnore usage, but that may be not as flexible as you need.

Evgeny M
  • 417
  • 7
  • 15
1

I've met the same problem, and i see 2 ways to solve it:

FAST: You can make some @PostLoad action in your entity and nullate that field you don't need.

@PostLoad
private void postLoad() {
    if (verifier != null) {
        verifier.email = null;
        verifier.office = null;
        verifier.department = null;
    }
}

CORRECT: Another way is to protect your entities with converting them to DTOs. Create separate POJOs and convert your User and UserReference to that DTO POJO classes. There you definitely will have more control over your response.

Yura Galavay
  • 426
  • 6
  • 10