Reputation: 7736
I have the following tables Customers, Roles, CustomerRoles. Customers and Roles have a Long PK and CustomerRoles obviously does the many to many mappings. Consider the Roles table to be a fixed table (but not hard coded) defined by the system. I.e. a table driven "enum". I.e. "Admin", "User", etc.
On the Java side, I have a Customer entity and a RoleEntity and I'm using Hibernate / JPA to map.
It's all working how it is now, but I wind up with Json that looks like this:
{
"customerId": 100000,
"firstName": "Bob",
"lastName": "Jenkins",
"roles": [
{
"name": "Admin"
},
{
"name": "Super User"
}
]
},
What I really want is for it to look like:
"roles": [ "Admin", "Super User" ]
and internally have it FK'ed by the M2M table using the ids. Note the roleid field is set to json ignore, but it still leaves it as a object array rather then a string array.
Obviously, the strings need to be enforced against whats in the Roles table.
Any suggestions?
Customer entity:
@ApiModelProperty(notes="Id of the customer.", required=true, value="100000")
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@JsonProperty(access=Access.READ_ONLY)
private Long customerId = 0L;
@NotNull
@Size(min=2, max=64)
@ApiModelProperty(notes="First name of the customer.", required=true, value="John")
private String firstName;
@NotNull
@Size(min=2, max=64)
@ApiModelProperty(notes="Last name of the customer.", required=true, value="Smith")
private String lastName;
@ManyToMany(cascade={ CascadeType.PERSIST })
@JoinTable(name="CustomerRoles",
joinColumns={ @JoinColumn(name="CustomerId") },
inverseJoinColumns={ @JoinColumn(name="RoleId") }
)
private List<Role> roles = new ArrayList<>();
public Long getCustomerId() {
return this.customerId;
}
public String getFirstName() {
return this.firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return this.lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public List<Role> getRoles() {
//return new ArrayList<Role>(this.roles);
return this.roles;
}
Role entity:
@ApiModelProperty(notes="Id of the role.", required=true, value="1")
@Id
//@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long roleId;
@NotNull
@Size(min=2, max=64)
@ApiModelProperty(notes="Name of the role.", required=true, value="Admin")
private String name;
@JsonIgnore
public Long getRoleId() {
return this.roleId;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
Upvotes: 2
Views: 2467
Reputation: 136
Add a new method in your Customer entity
@JsonProperty("roles")
public List<String> getRolesAsStrList() {
return this.roles
.stream()
.map(Role::getName)
.collect(toList());
}
And then add @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
on roles property
//other annotations
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private List<Role> roles = new ArrayList<>();
And for POST
to automatically bind from String
to Role
just add two constructor in Role.java
public Role() {
}
public Role(String name) {
this.name = name;
}
This will automatically handle payload like this and create two role entity with name "Admin" and "Super User".
{
"customerId": 100000,
"firstName": "Bob",
"lastName": "Jenkins",
"roles": [ "Admin", "Super User"]
}
However, if you need the id field of role you need to manually handle it before persisting or you can keep name of the role as foreign key in CustomerRoles
table assuming name of roles will be unique.
If you need more advanced serialization or deserialization you can write a custom
JsonSerializer
and JsonDeserializer
for that. See JsonComponent if you are using spring boot to serve your api.
Upvotes: 3