title: Persisting OneToMany with Embeddable Id in JPA
body: <p>An authorisation service is based upon <a href="http://www.svlada.com/jwt-token-authentication-with-spring-boot/" rel="nofollow noreferrer">http://www.svlada.com/jwt-token-authentication-with-spring-boot/</a> (sadly it doesn't provide a registration example)</p>
  
  <p>I have the following Entities and Service:</p>
  
  <p><strong>User.java</strong></p>
  
  <pre><code>package com.test.entity;
  
  import javax.persistence.*;
  import java.io.Serializable;
  import java.sql.Timestamp;
  import java.time.LocalDateTime;
  import java.util.ArrayList;
  import java.util.List;
  
  @Entity
  @Table(name = "user")
  public class User implements Serializable {
    private static final long serialVersionUID = 1322120000551624359L;
  
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
  
    @Column(name = "username")
    private String username;
  
    @Column(name = "password")
    private String password;
  
    @Column(name = "first_name")
    private String firstName;
  
    @Column(name = "last_name")
    private String lastName;
  
    @Column(name = "activated")
    private Boolean activated;
  
    @Column(name = "activation_token")
    private String activationToken;
  
    @Column(name = "activation_token_exp")
    private Timestamp activationTokenExpirationDate;
  
    @Column(name = "reset_token")
    private String resetToken;
  
    @Column(name = "reset_token_exp")
    private Timestamp resetTokenExpirationDate;
  
    @Column(name = "created")
    private LocalDateTime created;
  
    @Column(name = "updated")
    private LocalDateTime updated;
  
    @OneToMany(cascade = CascadeType.ALL)
    @JoinColumn(name = "user_id", referencedColumnName = "id")
    private List&lt;UserRole&gt; roles = new ArrayList&lt;&gt;(0);
  
    public User() { }
  
    // getters and setters
  }
  </code></pre>
  
  <p><strong>UserRole.java</strong></p>
  
  <pre><code>@Entity
  @Table(name = "user_role")
  public class UserRole implements Serializable {
    @Embeddable
    public static class Id implements Serializable {
      private static final long serialVersionUID = 1322120000551624359L;
  
      @Column(name = "user_id")
      protected Long userId;
  
      @Enumerated(EnumType.STRING)
      @Column(name = "role")
      protected Role role;
  
      public Id() { }
  
      public Id(Long userId, Role role) {
        this.userId = userId;
        this.role = role;
      }
  
      @Override
      public boolean equals(Object o) {
        if (this == o)
          return true;
        if (o == null || getClass() != o.getClass())
          return false;
  
        Id id = (Id) o;
  
        if (! userId.equals(id.userId))
          return false;
        return role == id.role;
      }
  
      @Override
      public int hashCode() {
        int result = userId.hashCode();
        result = 31 * result + role.hashCode();
        return result;
      }
    }
  
    @EmbeddedId
    Id id = new Id();
  
    @Enumerated(EnumType.STRING)
    @Column(name = "role", insertable = false, updatable = false)
    protected Role role;
  
    public UserRole() {
    }
  
    public UserRole(Role role) {
      this.role = role;
    }
  
    public Role getRole() {
      return role;
    }
  
    public void setRole(Role role) {
      this.role = role;
    }
  }
  </code></pre>
  
  <p><strong>UserService.java</strong></p>
  
  <pre><code>@Override
    public User registerUser(UserDTO userDto) {
      Optional&lt;User&gt; existingUser = this.getByUsername(userDto.getUsername());
      if (existingUser.isPresent()) {
        throw new RegistrationException("User is already taken");
      }
  
      User newUser = new User();
      newUser.setUsername(userDto.getUsername());
      newUser.setPassword(encoder.encode(userDto.getPassword()));
      newUser.setFirstName(userDto.getFirstName());
      newUser.setLastName(userDto.getLastName());
      newUser.setActivated(Boolean.FALSE);
      newUser.setActivationToken(RandomUtil.generateActivationKey());
      newUser.setActivationTokenExpirationDate(Timestamp.valueOf(LocalDateTime.now().plusSeconds(ACTIVATION_TOKEN_TTL)));
      newUser.setCreated(LocalDateTime.now());
  
      newUser.addRole(new UserRole(Role.MEMBER));
  
      return userRepository.save(newUser);
    }
  </code></pre>
  
  <p>This line  <code>return userRepository.save(newUser);</code> however throws an exception as is not able to persist the relation. I can't set the UserRole ID (userId + role) manually as I don't yet have them (the user is to be persisted)</p>
  
  <pre><code>com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Column 'role' cannot be null
      at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
      at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
      at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
      at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
      at com.mysql.jdbc.Util.handleNewInstance(Util.java:404)
      at com.mysql.jdbc.Util.getInstance(Util.java:387)
      at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:934)
      at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3966)
      at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3902)
      at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2526)
      ...
      ...
  </code></pre>
  
  <p>Is this the correct way to persist this kind of relation while having an composite primary key as Embeddable?</p>
  
  <p>If I avoid setting the realation with UserRole, the user gets persisted correctly (with no roles)</p>
  
  <p><strong>DB</strong></p>
  
  <pre><code>CREATE TABLE `user` (
    `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
    `username` varchar(50) NOT NULL,
    `password` varchar(64) NOT NULL,
    `first_name` varchar(20) DEFAULT NULL,
    `last_name` varchar(20) DEFAULT NULL,
    `activated` tinyint(1) NOT NULL DEFAULT '0',
    `activation_token` varchar(50) DEFAULT NULL,
    `activation_token_exp` timestamp NULL DEFAULT NULL,
    `reset_token` varchar(50) DEFAULT NULL,
    `reset_token_exp` timestamp NULL DEFAULT NULL,
    `created` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
    `updated` timestamp NULL DEFAULT NULL,
    PRIMARY KEY (`id`)
  ) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8;
  
  CREATE TABLE `user_role` (
    `user_id` bigint(20) unsigned NOT NULL,
    `role` varchar(50) NOT NULL DEFAULT '',
    PRIMARY KEY (`user_id`,`role`)
  ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  </code></pre>