1

I'm currently trying to setup a database – using Java only. Given this simple class that might appear in the average social network app:

@Entity
class User {
    @Id
    private String email;
    private String name;
    private String otherInfo;

    @ManyToMany
    private List<User> contacts;
}

When the user logs in, he should receive the basic information and the list of contacts with their basic info, but not their contacts. To reduce the amount of boiler-plate code, I want to use a standard solution like Gson. However, even with lazy fetch the whole user is loaded on gson.toJson(user).

Therefore I thought of extracting the basic infos into a base class BasicUser and changing the contacts to List<BasicUser>. Now I only need to somehow circumwent the discriminator column when I fetch the contacts – of course they are all saved as complete users on the server. Unfortunately, I don't know how to archieve that. Any ideas?

Albjenow
  • 369
  • 2
  • 12

3 Answers3

1

If you need to get only part of the entity you can use projections. In your case it can be, for example, like this:

public interface BaseUser {
    String getEmail();
    String getName();
    String getOtherInfo();
}

public interface UserRepo extends JpaRepository <User, String> {
    List<BaseUser> findAllBy();
}
Cepr0
  • 28,144
  • 8
  • 75
  • 101
1

You shouldn't have to modify your domain model just to accomodate a serialization library.

If you only want certain fields of a collection to be exposed to JSON, you could use Jackson with @JsonView (see here: How to serialize using @Jsonview with nested objects) not sure if Gson provides a similar feature as I have never used it extensively.

crizzis
  • 9,978
  • 2
  • 28
  • 47
  • I agree that a separation of persistence and serialisation for network com is preferable. With your towards Jackson I managed to solve my problem although `JsonView`? doesn't do the trick since I can't switch the view based on the depth of the entity graph. On the first layer (the logged in user), I want to serialize the `contacts` attribute, but on the second one (contacts of the user) it should be ommitted. – Albjenow Apr 11 '18 at 21:12
  • 1
    Sorry, just realized that I had linked to the wrong question. I meant this approach specifically: https://stackoverflow.com/a/34416577/1092818. You just need to skip `User.contacts` in the `@JsonView` that will be passed to the `JsonSerializer` (your problem is exactly the same as in the question I linked to, except that `A` and `B` are the same) – crizzis Apr 12 '18 at 00:25
1

Using Jackson for serialization, the problem can be solved without writing custom serialization code. BasicUser contains the getters of the attributes, I want to serialize:

public interface BasicUser {
    String getEmail();
    String getFirstName();
    String getLastName();
}

With a single annotation the contacts attribute is interpreted as a list of BasicUsers:

@Entity
public class User implements BasicUser {    
    @Id
    private String email;
    private String firstName;   
    private String lastName;

    @ManyToMany
    @JsonSerialize(contentAs = BasicUser.class)
    private List<User> contacts = new ArrayList<>();    

    // ... implemented getters
}
Albjenow
  • 369
  • 2
  • 12