Exception thrown with OneToMany annotation - jpa

In my Play 2.0 application using the EBean ORM I have the following class:
#Entity
public class User extends Model {
#Id
public Long id;
#Constraints.Required
public String someString;
#OneToMany(mappedBy="user", cascade=CascadeType.REMOVE)
#OrderBy("index")
public List<UserImage> userImages = new ArrayList<UserImage>();
}
Unless I comment out the #OneToMany line completely, the application throws a RunTimeException stating
Error reading annotations for models.User
The UserImage class I refer to here looks like this:
public class UserImage extends Model {
#Id
public long id;
#Constraints.Min(0)
public int index;
#Column(name="user_id")
#ManyToOne
public User user;
//...
}
What am I doing wrong here? Why doesn't EBean understand my annotation?

I think you missed the #Entity annotation on the UserImage class:
#Entity
public class UserImage extends Model {
#Id
public long id;
#Constraints.Min(0)
public int index;
#Column(name="user_id")
#ManyToOne
public User user;
//...
}

Related

Build method in JPA with composite key

This is my entity with composite key:
#Entity
#Table(name = "course_ratings")
public class CourseRating {
#EmbeddedId
private CourseRatingKey id;
}
Where CourseRatingKey looks like this:
#Embeddable
public class CourseRatingKey implements Serializable {
#Column(name = "user_id")
private int userId;
#Column(name = "course_id")
private int courseId;
public CourseRatingKey() {
}
// getters, setters, equals(), hashCode()
}
And my JPA repository
#Repository
public interface CourseRatingRepository extends JpaRepository<CourseRating, CourseRatingKey> {
}
I am trying to build method that will return list of all CourseRating with given courseId property of CourseRatingKey. Below method doesn't work because JPA doesn't recognize it:
repository.findAllByIdCourseId(int id);
How can I build my method name to achieve my goal?
I have solved my problem by declaring this method in repository. I'm a bit confused as the other methods work without declaring.
#Repository
public interface CourseRatingRepository extends JpaRepository<CourseRating, CourseRatingKey> {
List<CourseRating> findAllByIdCourseId(Integer id);
}

Picketlink with custom model and long Id

I have a existing Model and want to use it with Picketlink. But I am using Long as #Id field. But Picketlink expect this to be a String field. I have found some hints to use another entity which maps to the corresponding entity of my model. But actually I don't now how to do it.
I have a base class, which all entities derive from:
#MappedSuperclass
public abstract class AbstractEntity implements Serializable, Cloneable {
#Id
#Identifier
#Column(name = "SID")
private Long sid;
#Column(name = "INSERT_TIME")
private Date insertTime;
#Column(name = "UPDATE_TIME")
private Date updateTime;
// getters and setters
}
And a derived realm entity:
#Entity
#IdentityManaged(Realm.class)
public class RealmEntity extends AbstractEntity {
#AttributeValue
private String name;
#PartitionClass
private String typeName;
#ConfigurationName
private String configurationName;
#AttributeValue
private boolean enforceSSL;
#AttributeValue
private int numberFailedLoginAttempts;
// getters and setters
}
And the mapping class for Picketlink looks as follows:
#IdentityPartition(supportedTypes = {
Application.class,
User.class,
Role.class
})
public class Realm extends AbstractPartition {
#AttributeProperty
private boolean enforceSSL;
#AttributeProperty
private int numberFailedLoginAttempts;
private Realm() {
this(null);
}
public Realm(String name) {
super(name);
}
}
The PartitionManager is defined as follows:
builder
.named("default.config")
.stores()
.jpa()
.supportType(User.class, Role.class, Application.class, Realm.class)
.supportGlobalRelationship(Grant.class, ApplicationAccess.class)
.mappedEntity(App.class, AppUserRole.class, AppRole.class, AppUser.class, UserEntity.class, RelationshipIdentityTypeEntity.class, RealmEntity.class)
.addContextInitializer((context, store) -> {
if (store instanceof JPAIdentityStore) {
if (!context.isParameterSet(JPAIdentityStore.INVOCATION_CTX_ENTITY_MANAGER)) {
context.setParameter(JPAIdentityStore.INVOCATION_CTX_ENTITY_MANAGER, entityManager);
}
}
});
When I try to create a new Realm Hibernate throws an error while trying to load the Realm because the #Id is defined as Long but the #Identifier of the Picketlink model is a String.
this.shsRealm = new Realm(REALM_SHS_NAME);
this.shsRealm.setEnforceSSL(true);
this.shsRealm.setNumberFailedLoginAttempts(3);
this.partitionManager.add(this.shsRealm);
java.lang.IllegalArgumentException: Provided id of the wrong type for class de.logsolut.common.picketlink.model.RealmEntity. Expected: class java.lang.Long, got class java.lang.String
How can I map the JPA model correctly to Picketlink?

JPA : Entity extend with entity

How can I extend an entity with another entity but both of them referring to the same table ? Is it possible ? The structure is something like this :
#Entity
#Table(name = "users")
#NamedQuery(name="User.findAll", query="SELECT u FROM User u")
public class User implements Serializable{
private int id;
private String name;
}
#Entity
#Table(name = "users")
#NamedQuery(name="SubUser.findAll", query="SELECT su FROM SubUser su")
public class SubUser extends User {
#Override
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
public int getId() {
return super.getId();
}
//- Other fields and getter setter
}
I tried this way Extend JPA entity to add attributes and logic
but I got this exception
org.hibernate.mapping.SingleTableSubclass cannot be cast to org.hibernate.mapping.RootClass
Update 1
I already put the #Id for the SubUser because the #Entity shows this exception
The entity has no primary key attribute defined
Add the #Inheritance annotation to the super class
Implement Serializable
Add a getter for id (you don't need a setter necessarily)
id should be Integer, not int, so that you can represent unassigned ids with null.
Code:
#Entity
#Table(name = "users")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
private String name;
public Integer getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
#Entity
public class SubUser extends User {
}
Any basic JPA docs would describe inheritance, discriminators and use of #Id.
#Entity
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="DISCRIM", discriminatorType=DiscriminatorType.STRING)
#DiscriminatorValue("User")
#Table(name="users")
#NamedQuery(name="User.findAll", query="SELECT u FROM User u")
public class User implements Serializable{
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
private String name;
}
#Entity
#DiscriminatorValue("SubUser")
#NamedQuery(name="SubUser.findAll", query="SELECT su FROM SubUser su")
public class SubUser extends User {
}

JPA Mapping, parent to children and child to parent with two classes and abstract class

I have have two classes that inherit from an abstract class and have a parent-children relation.
So I use annotation OneToMany and ManyToOne but the parent entity in child class is always null.
Can Someone help me please, I have spend several hours to googling and test many conf without success.
These are code from my classes :
public #Table(name="flowentity") #Entity abstract class FlowEntity {
final static Logger log = LoggerFactory.getLogger(FlowEntity.class);
//Globals informations concerning the flow state
private #Id #GeneratedValue(strategy = GenerationType.IDENTITY) Integer flowId = 0;
private String flowName;
private #OneToMany(fetch=FetchType.EAGER, cascade=CascadeType.ALL)
Set<PeopleEntity> actorSet = new HashSet<>();
//Global parameters for most of flows
//Organizational parameters
private #OneToOne(fetch=FetchType.EAGER, cascade=CascadeType.ALL)
#JoinColumn(name="organisationalEntity_Id")
OrganisationalEntity organisationalEntity;
...
public #Table(name="ams_newCPEntity") #Entity class NewMultiCPEntity extends FlowEntity {
private #OneToMany(targetEntity=NewCPEntity.class, fetch=FetchType.EAGER, cascade=CascadeType.ALL,mappedBy="parent")
Set<NewCPEntity> cpList = new HashSet<NewCPEntity>();
//Constructor
public NewMultiCPEntity(){
setFlowName(EnumFlow.N_CP_M.getFlowAcronym());
}
...
public #Table(name="ams_newCPEntity") #Entity class NewCPEntity extends FlowEntity {
final static Logger log = LoggerFactory.getLogger(NewCPEntity.class);
private boolean formNCPValidated;
private #ManyToOne #JoinColumn(name="parent_Id", nullable=false)
NewMultiCPEntity parent;
public NewCPEntity(){
log.debug("Instanciation of a new CP");
setFlowName(EnumFlow.N_CP.getFlowAcronym());
}
public #Override OrganisationalEntity getOrganisationalEntity(){
return parent.getOrganisationalEntity();
}
...
If I don't add the #JoinColumn annotation, JPA create an association table but is not able to retrieve the parent whereas the association can be done directly by requesting in database.
Thankyou very much to help.
Regards,
Thank you Chris for your comment, you are right, I forget to change the name of the table. I don't think it was the problem because the inheritance mapping is in one table flowentity with a DTYPE discriminator column.
Finally I resolve my problem by setting parent attributs when adding a new child like this :
public #Table #Entity class NewMultiCPEntity extends FlowEntity {
private #OneToMany(targetEntity=NewCPEntity.class, fetch=FetchType.EAGER, cascade=CascadeType.ALL)
List<NewCPEntity> cpList = new ArrayList<>();
//Constructor
public NewMultiCPEntity(){
setOrganisationalEntity(new OrganisationalEntity());
setFlowName(EnumFlow.N_CP_M.getFlowAcronym());
}
public List<NewCPEntity> getNCPList(){
if(cpList == null){
cpList = new ArrayList<>();
}
if(cpList.isEmpty()){
addCPEntity(new NewCPEntity());
}
return Collections.unmodifiableList(cpList);}
public boolean removeCPEntity(NewCPEntity entity){
return cpList.remove(entity);
}
public boolean addCPEntity(NewCPEntity entity){
entity.setParent(this);
entity.setOrganisationalEntity(this.getOrganisationalEntity());
return cpList.add(entity);
}
And I remove the override of getOrganizationalEntity in the child :
public #Table #Entity class NewCPEntity extends FlowEntity {
final static Logger log = LoggerFactory.getLogger(NewCPEntity.class);
private #ManyToOne(targetEntity=NewMultiCPEntity.class,cascade=CascadeType.ALL)
NewMultiCPEntity parent;
public NewCPEntity(){
log.debug("Instanciation of a new CP");
setFlowName(EnumFlow.N_CP.getFlowAcronym());
}
public NewMultiCPEntity getParent() {
return parent;
}
public void setParent(NewMultiCPEntity parent){
this.parent = parent;
}
Regards,

ebean does not generate methods for inhereted annotated fields?

This works:
#MappedSuperclass
public class ExtendableTranslation extends Model {
public String label;
}
#Entity
public class LeagueT extends ExtendableTranslation {
#Id
public Integer id;
}
but if I move id field to the superclass:
#MappedSuperclass
public class ExtendableTranslation extends Model {
public String label;
#Id
public Integer id;
}
#Entity
public class LeagueT extends ExtendableTranslation {
}
I have an error:
[RuntimeException: java.lang.NoSuchMethodError: models.translations.LeagueT._ebean_setni_id(Ljava/lang/Integer;)V]
It's the same for all other annotated fields (#ManyToOne, #OneToMany). Is it a bug or I'm doing something wrong?