Spring JpaRepository using EntityGraph returns null instead of Optional - spring

Calling this method:
#EntityGraph(attributePaths = "permissionGroups")
Optional<User> findOneWithPermissionGroupsByLogin(String login);
With non-exsisting user login returns null instead of Optional.of(null).
I would like to figure out what should I add in order to get an Optional resault?
more complete code:
Repository
public interface UserRepository extends JpaRepository<User, Long>
{
Optional<User> findOneByLogin(String login);
#EntityGraph(attributePaths = "permissionGroups")
Optional<User> findOneWithPermissionGroupsByLogin(String login);
}
User Entity
this is relevant user entity code
#Entity
#Table(name = "jhi_user")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class User extends AbstractAuditingEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
private Long id;
#NotNull
#Pattern(regexp = Constants.LOGIN_REGEX)
#Size(min = 1, max = 50)
#Column(length = 50, unique = true, nullable = false)
private String login;
#JsonIgnore
#ManyToMany
#JoinTable(
name = "jhi_user_authority",
joinColumns = {#JoinColumn(name = "user_id", referencedColumnName = "id")},
inverseJoinColumns = {#JoinColumn(name = "authority_name", referencedColumnName = "name")})
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
#BatchSize(size = 20)
private Set<Authority> authorities = new HashSet<>();
#ManyToMany
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
#JoinTable(name = "euser_permission_group",
joinColumns = #JoinColumn(name="eusers_id", referencedColumnName="id"),
inverseJoinColumns = #JoinColumn(name="permission_groups_id", referencedColumnName="id"))
private Set<PermissionGroup> permissionGroups = new HashSet<>();
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getLogin() {
return login;
}
//Lowercase the login before saving it in database
public void setLogin(String login) {
this.login = login.toLowerCase(Locale.ENGLISH);
}
public Set<Authority> getAuthorities() {
return authorities;
}
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
User user = (User) o;
return login.equals(user.login);
}
#Override
public int hashCode() {
return login.hashCode();
}

Related

mapstruct issue with nested entities when mapping

Hello I have the Following mapstruct mapping description.
#Mapper(componentModel = "spring", uses = {
GroupResolver.class }, unmappedTargetPolicy = ReportingPolicy.IGNORE, unmappedSourcePolicy = ReportingPolicy.IGNORE)
public abstract class GroupMapper {
#Autowired
private UserMapper userMapper;
#Autowired
private ChainMapper chainMapper;
#Mapping(target = "id", source = "id")
#Mapping(target = "name", source = "name")
#Mapping(target = "chains", expression = "java(mapChain(group))")
#Mapping(target = "users", expression = "java(mapUsers(group))")
public abstract GroupResp toModel(final Group group);
public Set<ChainResp> mapChain(final Group group) {
return chainMapper.toModelSet(group.getChains());
}
public Set<UserResp> mapUsers(final Group group) {
return userMapper.toModelSet(group.getUsers());
}
#Mapping(target = "id", source = "id")
#Mapping(target = "name", source = "name")
#Mapping(target = "chains", ignore = true)
#Mapping(target = "users", ignore = true)
#Mapping(target = "users.chainUnixPaths" , ignore = true )
public abstract Group toEntity(final GroupResp groupeResp);
public Set<Chain> mapChains(final GroupResp groupeResp) {
return chainMapper.toEntitySet(groupeResp.getChains());
}
public Set<User> mapUsers(final GroupResp groupeResp) {
return userMapper.toEntitySet(groupeResp.getUsers());
}
}
I m facing a compile time error stating that :
No target bean properties found: can't map Collection element "UnixPathResp users[].chainUnixPaths" to "UnixPath users[].chainUnixPaths". Consider to declare/implement a mapping method: "UnixPath map(UnixPathResp value)".
AND
No target bean properties found: can't map property "ServerResp users[].server" to "Server users[].server". Consider to declare/implement a mapping method: "Server map(ServerResp value)".
I assume that my Ignores are not Working Or my resolver is somehow fuzy.
Here is all related classes
#Entity
#Table(name = "groups")
public class Group implements Serializable {
private static final long serialVersionUID = 6980925916410978160L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_GROUPS")
#SequenceGenerator(name = "SEQ_GROUPS", sequenceName = "SEQ_GROUPS")
#Column(name = "GROUP_ID")
private Long id;
#Column(name = "GROUP_NAME", length = 256, nullable = false)
private String name;
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "CHAIN_GROUP", joinColumns = #JoinColumn(name = "GROUP_ID"), inverseJoinColumns = #JoinColumn(name = "CHAIN_ID"))
private Set<Chain> chains = new HashSet<>();
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "USER_GROUP", joinColumns = #JoinColumn(name = "GROUP_ID"), inverseJoinColumns = #JoinColumn(name = "USER_ID"))
private Set<User> users = new HashSet<>();
AND
public class GroupResp implements Serializable{
/**
*
*/
private static final long serialVersionUID = 7184268214689299357L;
#JsonProperty("GROUP_ID")
private Long id;
#NotBlank
#JsonProperty("GROUP_NAME")
private String name;
#JsonProperty("CHAIN_GROUP")
private Set<ChainResp> chains = new HashSet<>();
#JsonProperty("USER_GROUP")
private Set<UserResp> users = new HashSet<>();
Then my Generic Resolver
#Component
public class GroupResolver extends GenericPFResolveContract<GroupResp, Group, Long> {
#Override
public Long getIdof(GroupResp s) {
return s.getId();
}
#Override
#ObjectFactory
public Group resolve(GroupResp s,#TargetType Class<Group> ts) throws InstantiationException, IllegalAccessException {
return super.resolve(s, ts);
}
}
With
#Component
public abstract class GenericPFResolveContract<S,T,K> implements PFResolveContract<T, S> {
#Autowired
protected JpaRepository<T, K> sourceRepository;
#Override
#ObjectFactory
#Transactional
public T resolve(S s,#TargetType Class<T> ts) throws InstantiationException, IllegalAccessException {
if(s == null || getIdof(s) == null) {
return ts.newInstance();
}
return sourceRepository.findById(getIdof(s)).orElseGet(()-> {
T newInstance = null;
try {
newInstance = ts.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
return newInstance;
} );
}
public abstract K getIdof(S s);
}

Spring Jpa - Records deleted and re-inserted upon addition/deletion in join table

I have 3 entities user, role and user_roles.
User and Role entity have a one-to-many relationship with the UserRoles entity which is a join table. I have added user_roles as a entity because we plan to have additional properties in future as part of the join table.
User Entity
#Entity
#Table(name = "users")
public class User
{
#Id
#Column(name = "user_id")
#GeneratedValue(generator = RandomIdGenerator.GENERATOR_NAME)
#GenericGenerator(name = RandomIdGenerator.GENERATOR_NAME, strategy = "com.cs.util.RandomIdGenerator")
private Long id;
#Column(name = "email", nullable = false)
private String email;
#Column(name = "first_name", nullable = false)
private String firstName;
#Column(name = "last_name", nullable = false)
private String lastName;
#OneToMany(cascade = CascadeType.ALL,fetch = FetchType.EAGER,mappedBy = "user", orphanRemoval = true)
private List<UserRole> userRoles = new ArrayList<UserRole> ();
#JsonSerialize(using = ToStringSerializer.class)
public Long getId ()
{
return id;
}
public void setId (Long id)
{
this.id = id;
}
public String getEmail()
{
return email;
}
public void setEmail (String email)
{
this.email = email;
}
public String getFirstName()
{
return firstName;
}
public void setFirstName(String firstName)
{
this.firstName = firstName;
}
public String getLastName()
{
return lastName;
}
public void setLastName(String lastName)
{
this.lastName = lastName;
}
#Transient
public Set<Role> getRoles()
{
Set<Role> roles = new HashSet<Role> ();
for (UserRole userRole : this.userRoles)
{
roles.add (userRole.getRole ());
}
return roles;
}
#JsonIgnore
public List<UserRole> getUserRoles()
{
return userRoles;
}
}
Role Entity
#Entity
#Table(name="roles")
public class Role {
#Id
#Column(name = "role_id")
#GeneratedValue(generator = RandomIdGenerator.GENERATOR_NAME)
#GenericGenerator(name = RandomIdGenerator.GENERATOR_NAME, strategy = "com.cs.util.RandomIdGenerator")
private Long id;
#Column(name="name", nullable = false)
private String name;
#Column(name="description", nullable = true)
private String description;
#Column(name = "suspend_flag")
private int suspendFlag;
#ManyToMany(fetch=FetchType.EAGER)
#JoinTable(name = "roles_permission",
joinColumns = #JoinColumn(name = "role_id"),
inverseJoinColumns = #JoinColumn(name = "permission_id"))
private Set<Permission> permissions= new HashSet<>();
#OneToMany(mappedBy = "role")
private List<UserRole> userRoles = new ArrayList<UserRole>();
#JsonSerialize(using=ToStringSerializer.class)
public Long getId ()
{
return id;
}
public void setId (Long id)
{
this.id = id;
}
public String getName ()
{
return name;
}
public void setName (String name)
{
this.name = name;
}
public String getDescription ()
{
return description;
}
public void setDescription (String description)
{
this.description = description;
}
public Set<Permission> getPermissions ()
{
return permissions;
}
public int getSuspendFlag ()
{
return suspendFlag;
}
public void setSuspendFlag (int suspendFlag)
{
this.suspendFlag = suspendFlag;
}
}
UserRole Entity
#Entity
#Table(name = "user_roles")
public class UserRole
{
public UserRole ()
{
}
public UserRole (User user, Role role)
{
this.user = user;
this.role = role;
}
#Id
#Column(name = "user_role_id")
#GeneratedValue(generator = RandomIdGenerator.GENERATOR_NAME)
#GenericGenerator(name = RandomIdGenerator.GENERATOR_NAME, strategy = "com.cs.util.RandomIdGenerator")
private Long id;
#ManyToOne
#JoinColumn(name = "user_id", referencedColumnName = "user_id")
private User user;
#ManyToOne
#JoinColumn(name = "role_id", referencedColumnName = "role_id")
private Role role;
public Long getId ()
{
return id;
}
public void setId (Long id)
{
this.id = id;
}
#JsonIgnore
public User getUser ()
{
return user;
}
public void setUser (User user)
{
this.user = user;
}
public Role getRole ()
{
return role;
}
public void setRole (Role role)
{
this.role = role;
}
}
With above code everything works fine but whenever I insert or delete a user_role all the records in the user_role table are deleted and re-inserted again.
For instance when I associate a new user_role to a user the existing user_role is deleted first and then it is re-associated again along with the new user role.
Hibernate: delete from user_roles where user_role_id=?
Hibernate: insert into user_roles (role_id, user_id, user_role_id) values (?, ?, ?)
Hibernate: insert into user_roles (role_id, user_id, user_role_id) values (?, ?, ?)
This is how I add a user role to the user entity.
UserRole userRole = new UserRole(user,role);
user.getUserRoles ().add (userRole);
m_userRepository.save (_user)
And then delete the user role from user like below
List<UserRole> uRolesTobeRemoved = new ArrayList<UserRole> ();
for(Role role : userRoles)
{
UserRole uRole = user.getUserRoles ().stream ().filter (userRole ->
userRole.getRole ().getId () == role.getId ()).collect (Collectors.toList ()).get (0);
uRolesTobeRemoved.add (uRole);
}
user.getUserRoles ().removeAll (uRolesTobeRemoved);
I'm not sure what is missing.
It looks like you see this behaviour due to so called "collection recreation".
Try to replace List<UserRole> userRoles to Set<UserRole> userRoles.
More detailed explanation you can find here.

#Id Not Mapped For Specific Entity In A Spring-Boot Controller

I have two entities Employee and Department and each have a Spring Web #RestController annotated class with update methods i.e. Http PUT.
For some strange reason (and likely a blindingly obvious solution) whenever the PUT is called for the Employee class, the ID in the JSON payload is NOT mapped to the id class of the Employee entity but it works perfectly for the Department entity.
Employee class:
Entity
#Table(name = "EMPLOYEE")
public class Employee implements Serializable, Identity<Long>, Deleted
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "NAME")
private String name;
#ManyToOne
#Where(clause = "is_deleted = false")
private Department department;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "EMP_QUAL", joinColumns = #JoinColumn(name = "EMPLOYEE_ID"), inverseJoinColumns = #JoinColumn(name = "QUALIFICATION_ID"))
#WhereJoinTable(clause = "IS_DELETED = false")
#SQLDelete(sql = "UPDATE `EMP_QUAL` SET IS_DELETED = true where EMPLOYEE_ID = ? and QUALIFICATION_ID = ? and IS_DELETED = False")
private Set<Qualification> qualifications;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "EMP_PROJ", joinColumns = #JoinColumn(name = "emp_id"), inverseJoinColumns = #JoinColumn(name = "proj_id"))
#Where(clause = "is_deleted = false")
private Set<Project> projects;
#JsonIgnore
#Column(name = "is_deleted", nullable = false)
private Boolean isDeleted = false;
#Override
public Long getId()
{
return this.id;
}
#Override
public void setId(final Long id)
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName(final String name)
{
this.name = name;
}
public Set<Project> getProjects()
{
return projects;
}
public void setProjects(final Set<Project> projects)
{
this.projects = projects;
}
public Department getDepartment()
{
return department;
}
public void setDepartment(final Department department)
{
this.department = department;
}
public Set<Qualification> getQualifications()
{
return qualifications;
}
public void setQualifications(final Set<Qualification> qualifications)
{
this.qualifications = qualifications;
}
public Boolean isDeleted()
{
return isDeleted;
}
public void setDeleted(final Boolean deleted)
{
isDeleted = deleted;
}
}
Department class:
#Entity
#Table(name = "DEPARTMENT")
public class Department implements Serializable, Identity<Long>, Deleted
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "name")
private String name;
#OneToMany(fetch = FetchType.EAGER)
#WhereJoinTable(clause = "is_deleted = false")
#JoinTable(name = "DEPARTMENT_EMPLOYEE", joinColumns = {#JoinColumn(name = "department_id")},
inverseJoinColumns = {#JoinColumn(name = "employee_id")})
#SQLDelete(sql = "UPDATE DEPARTMENT_EMPLOYEE SET is_deleted = true where department_id = ? and employee_id = ? and is_deleted = false")
private Set<Employee> departmentMembers;
#Column(name = "is_deleted", nullable = false)
private Boolean isDeleted;
#Override
public Long getId()
{
return this.id;
}
#Override
public void setId(final Long id)
{
this.id = id;
}
#Override
public Boolean isDeleted()
{
return this.isDeleted;
}
#Override
public void setDeleted(final Boolean isDeleted)
{
this.isDeleted = isDeleted;
}
public String getName()
{
return name;
}
public void setName(final String name)
{
this.name = name;
}
public Set<Employee> getDepartmentMembers()
{
return departmentMembers;
}
public void setDepartmentMembers(final Set<Employee> departmentMembers)
{
this.departmentMembers = departmentMembers;
}
}
When call PUT /employees/{id}:
Calling PUT /departments/{id}:
As you can see in the screenshots of the debugger the id field of Department is populated while it is null in Employee. I'm testing this with Swagger and I am setting the ID in the payload. I don't have any specific Jackson configuration set I just use Spring boot's default but I cannot work out why only in Employee the id field is never mapped.
Employee body:
{
"id":1,
"name": "New Name"
}
Department body:
{
"id":2,
"name": "chemistry",
"deleted":false
}
The issue was due to a Jackson annotation #JsonIdentityInfo on another entity Project which is has a relationship with Employee:
#Entity
#Table(name = "PROJECT")
public class Project implements Serializable, Identity<Long>, Deleted
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "name")
private String name;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "EMP_PROJ", joinColumns = #JoinColumn(name = "proj_id"), inverseJoinColumns = #JoinColumn(name = "emp_id"))
#JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class, property = "id")
#Where(clause = "is_deleted = false")
private Set<Employee> employees;

JsonIgnore dynamically If it is nested?

I have hibernate models like following:
Ticket Model:
#Entity
#Table(name = "ticket")
public class TicketModel {
private BigInteger id;
private UserModel user;
#Id
#Column(name = "id", nullable = false)
#SequenceGenerator(name = "seqTicket", sequenceName = "ticket_id_seq", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seqTicket")
public BigInteger getId() {
return id;
}
public void setId(BigInteger id) {
this.id = id;
}
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "user_id", referencedColumnName = "id")
public UserModel getUser() {
return user;
}
public void setUser(UserModel user) {
this.user = user;
}
}
User Model:
#Entity
#Table(name = "user")
public class UserModel {
private BigInteger id;
private String name;
private CompanyModel company;
#Id
#Column(name = "id", nullable = false)
#SequenceGenerator(name = "seqUser", sequenceName = "user_id_seq", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seqUser")
public BigInteger getId() {
return id;
}
public void setId(BigInteger id) {
this.id = id;
}
#Basic
#Column(name = "name", nullable = false)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "company_id", referencedColumnName = "id")
public CompanyModel getUser() {
return company;
}
public void setUser(CompanyModel company) {
this.company = company;
}
}
Company Model:
#Entity
#Table(name = "company")
public class UserModel {
private BigInteger id;
private String name;
#Id
#Column(name = "id", nullable = false)
#SequenceGenerator(name = "seqCompany", sequenceName = "company_id_seq", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seqCompany")
public BigInteger getId() {
return id;
}
public void setId(BigInteger id) {
this.id = id;
}
#Basic
#Column(name = "name", nullable = false)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Now, what i want to do is json ignoring user's company in my rest controller if I am returning ticket object. But if I am returning User object I dont want to ignore company relation.
For example:
in ticket controller's return it should be a json like :
{
"id":1,
"user":{
"id":3,
"name":"something"
}
}
but in user controller's return it should be like:
{
"id":3,
"name":"something",
"company":{
"id":5,
"name":"something else"
}
}
So shortly, I want to ignore relations if it is in second dimension.
Is that possible?

Spring Data rest how to perform CRUD on #manytomany relation ,composite table with extra column

I am unable to perform CRUD via json POST from restful client Postman on Composite table having extra column .I am using Spring boot ,spring data rest and spring JPA.
I have 3 tables in data base
-user
-competency
-user_competency (join/composite table with extra column)
Here are my classes
User
#Entity
#Table(name = "\"user\"", schema = "public")
#JsonIdentityInfo(
generator = ObjectIdGenerators.IntSequenceGenerator.class,
property = "userId")
public class User implements java.io.Serializable {
private Long userId;
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "user_id", unique = true, nullable = false)
public Long getUserId() {
return this.userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
private Set<UserCompetency> userCompetencies = new HashSet<UserCompetency>(0);
#OneToMany(fetch = FetchType.EAGER,cascade = {CascadeType.ALL}, mappedBy = "user")
public Set<UserCompetency> getUserCompetencies() {
return this.userCompetencies;
}
public void setUserCompetencies(Set<UserCompetency> userCompetencies) {
this.userCompetencies = userCompetencies;
}
}
Competency
#Entity
#Table(name = "competency", schema = "public")
#JsonIdentityInfo(
generator = ObjectIdGenerators.IntSequenceGenerator.class,
property = "competencyId")
public class Competency implements java.io.Serializable {
private Long competencyId;
private Set<UserCompetency> userCompetencies = new HashSet<UserCompetency>(0);
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "competency_id", unique = true, nullable = false)
public Long getCompetencyId() {
return this.competencyId;
}
public void setCompetencyId(Long competencyId) {
this.competencyId = competencyId;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "competency")
public Set<UserCompetency> getUserCompetencies() {
return this.userCompetencies;
}
public void setUserCompetencies(Set<UserCompetency> userCompetencies) {
this.userCompetencies = userCompetencies;
}
}
UserCompetency
#Entity
#Table(name = "user_competency", schema = "public")
#JsonIdentityInfo(
generator =ObjectIdGenerators.IntSequenceGenerator.class,
property = "id")
public class UserCompetency implements java.io.Serializable {
private UserCompetencyId id;
private Level level;
private User user;
private Competency competency;
#EmbeddedId
#AttributeOverrides({
#AttributeOverride(name = "competencyId", column = #Column(name = "competency_id", nullable = false)),
#AttributeOverride(name = "userId", column = #Column(name = "user_id", nullable = false)) })
public UserCompetencyId getId() {
return this.id;
}
public void setId(UserCompetencyId id) {
this.id = id;
}
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "level_id")
public Level getLevel() {
return this.level;
}
public void setLevel(Level level) {
this.level = level;
}
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "user_id", nullable = false, insertable = false, updatable = false)
public User getUser() {
return this.user;
}
public void setUser(User user) {
this.user = user;
}
#ManyToOne(fetch = FetchType.EAGER,cascade=CascadeType.ALL)
#JoinColumn(name = "competency_id", nullable = false, insertable = false, updatable = false)
public Competency getCompetency() {
return this.competency;
}
public void setCompetency(Competency competency) {
this.competency = competency;
}
}
UserCompetencyId
#Embeddable
public class UserCompetencyId implements java.io.Serializable {
private Long competencyId;
private Long userId;
public UserCompetencyId() {
}
public UserCompetencyId(Long competencyId, Long userId) {
this.competencyId = competencyId;
this.userId = userId;
}
#Column(name = "competency_id", nullable = false)
public Long getCompetencyId() {
return this.competencyId;
}
public void setCompetencyId(Long competencyId) {
this.competencyId = competencyId;
}
#Column(name = "user_id", nullable = false)
public Long getUserId() {
return this.userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public boolean equals(Object other) {
if ((this == other))
return true;
if ((other == null))
return false;
if (!(other instanceof UserCompetencyId))
return false;
UserCompetencyId castOther = (UserCompetencyId) other;
return (this.getCompetencyId() == castOther.getCompetencyId()) && (this.getUserId() == castOther.getUserId());
}
}
Suppose i have already record in User and Competency tables and i want to assocaite both i am trying to post like this ,but it give me error of 405 Method Not Allowed.
help required ,what should be structure of json to be posted User will already exist and competency will might exist or new can be added and associated with existing user.
With this code I was able to post a new relation:
UserCompetency.class
#Entity
#Table(name = "user_competency")
#IdClass(UserCompetencyId.class)
public class UserCompetency implements java.io.Serializable {
#Id #ManyToOne
#JoinColumn(name = "competency_id", nullable = false, insertable = false, updatable = false)
private Competency competency;
#Id #ManyToOne
#JoinColumn(name = "user_id", nullable = false, insertable = false, updatable = false)
private User user;
UserCompetencyId.class
public class UserCompetencyId implements java.io.Serializable {
private Long competency;
private Long user;
public UserCompetencyId() {
}
public UserCompetencyId(Long competency, Long user) {
this.competency = competency;
this.user = user;
}
UserCompetencyRepository.class
public interface UserCompetencyRepository extends JpaRepository<UserCompetency, UserCompetencyId> {
}
POST http://localhost:8080/userCompetencies
{
"competency": "/competencies/2"
, "user": "/user/4"
}
Apparently there seems to be no "natural/easy" way to get what you want. But there is a promissing project for integrating embeddables by extending the serialization process: https://github.com/gregturn/embeddable-spring-data-rest
UserCompetencyIdJacksonModule, UserCompetencyIdSerializer, ..
Then you should be able PATCH (not POST) your JSON from above.

Resources