I am working on an authentication model that would suit GlassFish's JDBC Realm requirements.
In this model I have one group which can contain multiple users, but each user can only be in one group (e.g. su, admin, etc.).
I have two entities: Groups.java (for groups) and Credential.java (for users) and intend to feed the generated join table to Glassfish's "Group Table" property.
I am able to persist both Groups and Credential instances, but the required middle table (credential_groups) is not even created, let alone updated.
Below are my entities:
Credential.java:
@Entity
@Access(AccessType.PROPERTY)
@Table(name = "credential")
public class Credential extends MetaInfo implements Serializable {
private String username;
private String passwd;
private Groups group;
private boolean blocked;
private boolean suspended;
public Credential() {
super();
}
public Credential(String createdBy) {
super(Instant.now(), createdBy);
}
public Credential(String createdBy, String username, String passwd) {
this(createdBy);
this.username = username;
this.passwd = passwd;
}
@Id
@Column(name = "username")
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
updateModified();
}
@Column(name = "passwd")
public String getPasswd() {
return passwd;
}
public void setPasswd(String passwd) {
this.passwd = passwd;
updateModified();
}
@ManyToOne(fetch = FetchType.LAZY)
public Groups getGroups() {
return group;
}
public void setGroups(Groups group) {
this.group = group;
group.getCredentials().add(this);
updateModified();
}
@Column(name = "is_blocked")
public boolean isBlocked() {
return blocked;
}
public void setBlocked(boolean blocked) {
this.blocked = blocked;
updateModified();
}
@Column(name = "is_suspended")
public boolean isSuspended() {
return suspended;
}
public void setSuspended(boolean suspended) {
this.suspended = suspended;
updateModified();
}
}
Groups.java:
@Entity
@Access(AccessType.PROPERTY)
@Table(name = "groups")
@NamedQueries({
@NamedQuery(name = "findAllGroups",
query = "SELECT g FROM Groups g order by g.modifiedDate DESC")
})
public class Groups extends MetaInfo implements Serializable {
private String groupName;
private Set<Credential> credentials;
public Groups() {
super();
credentials = new HashSet();
}
public Groups(String groupName) {
this();
this.groupName = groupName;
}
public Groups(String createdBy, String groupName) {
this();
setCreatedBy(createdBy);
this.groupName = groupName;
}
@Id
@Column(name = "group_name")
public String getGroupName() {
return groupName;
}
public void setGroupName(String groupName) {
this.groupName = groupName;
updateModified();
}
@OneToMany(mappedBy = "groups")
@JoinTable(
name = "credential_groups",
joinColumns = @JoinColumn(name = "group_name"),
inverseJoinColumns = @JoinColumn(name = "username")
)
public Set<Credential> getCredentials() {
return credentials;
}
public void setCredentials(Set<Credential> credentials) {
this.credentials = credentials;
}
public void addCredential(Credential c) {
credentials.add(c);
if (c.getGroups() != this) {
c.setGroups(this);
}
}
}
As I said persisting both works (for Groups I have also tried updating, querying), but this error keeps on firing on every operation with either entity:
Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Can't write; duplicate key in table '#sql-4d2_54'
Error Code: 1022
Call: ALTER TABLE credential ADD CONSTRAINT FK_credential_GROUPS_group_name FOREIGN KEY (GROUPS_group_name) REFERENCES groups (group_name)
Query: DataModifyQuery(sql="ALTER TABLE credential ADD CONSTRAINT FK_credential_GROUPS_group_name FOREIGN KEY (GROUPS_group_name) REFERENCES groups (group_name)")
Important update: This is the error that is being thrown even before the pasted above exception:
Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'group VARCHAR(255) NOT NULL, PRIMARY KEY (credential, group))' at line 1
Error Code: 1064
Call: CREATE TABLE credential_groups (credential VARCHAR(255) NOT NULL, group VARCHAR(255) NOT NULL, PRIMARY KEY (credential, group))
As requested by Francois Motard, here's my jUnit method that triggers the error (the group is created in another test class):
public class CredentialRepositoryTests {
private final OCGroupsRepository groupRepo;
private final OCCredentialRepository credentialRepo;
public CredentialRepositoryTests() {
groupRepo = new OCGroupsRepository();
credentialRepo = new OCCredentialRepository();
}
...
@Test
public void createCredentialTest(){
//retrieve the group
Groups admin = groupRepo.getByGroupName("admin");
Credential rimma = new Credential("user_creator", "sample_user", "abc123");
admin.addCredential(rimma);
assertTrue(groupRepo.updateGroups(admin));
}
I based my code on the instructions from the EJB 3.0 in Action by Manning and tried to resolve the join table issue based on this stackoverflow answer: How to create join table with JPA annotations?
Can anyone help me have the join table created and updated? Thank you very much.