use JPA entity mapping while storing the entity but ignore fields or a particular table while reading back - jpa

I am using similar code to what is listed in: How to map one class with multiple tables in Hibernate/javax.persistance?
I was trying to write a sample login program, based on above example I map my user class to secondary table where I store password field. now when I retrieve back user entity. I also get secondary table field so password is also available in user object.
Is it possible, that during registration I want to use secondary table storage method but when I read back. it should not return password back with user?
How can I achieve this? I am looking for some JPA way like #transient ignore the particular column.

I wouldn't go for such implementation.
Best practice is to never store a clear-text password, but a digest instead:
#Entity
public class Account
{
#Column
private String username;
#Column(length = 32)
private String password;
public String getUsername()
{
return username;
}
public void setUsername(String username)
{
this.username = username;
}
public String getPassword()
{
return password;
}
public void setPassword(String password)
{
this.password = DigestUtils.md5Hex(password);
}
}
It's an uncommon requirement, and JPA patterns will do their best to fight against you :)
But... some way may still be possible:
using Entity Listeners:
#Entity
public class Account
{
#Column
private String username;
#Column
private String password;
#PostLoad
public void postLoad()
{
password = null;
}
}
be careful: when loaded inside a transaction, a null password may be eventually flushed on commit.
removing getter for password:
if you put annotations only on fields, you can remove getPassword() method. Even if the field is populated on load, it's not accessible by external java code.
using a #Transient combination:
#Entity
public class Account
{
#Column
private String username;
#Column
private String password;
#Transient
private String password2;
public String getPassword()
{
return password2;
}
public void setPassword(String password)
{
this.password = password;
this.password2 = password;
}
}

Related

Table per class configuration with Morphia and MongoDb is not working

I am trying to have table per class configuration with Morphia + MongoDb
#Entity("user")
public class User{
#Id
private ObjectId id;
private String username;
public void setId(ObjectId id){
this.id = id;
}
public ObjectId getId(){
return this.id;
}
public void setUsername(String username){
this.username = username;
}
public String getUsername(){
return this.username;
}
}
And Assistant
#Entity("assistant")
public class Assistant extends User{
private String fullname;
public String getFullname(){
return this.fullname;
}
public void setFullname(String fullname){
this.fullname = fullname;
}
}
I Want to have a user document and assistant document with same ObjectId. How Do this?
MongoDB is not a relational database, you will need to change your mental & database model.
If somebody is an assistant, all the data will go to the assistant collection. There are no joins (except for aggregations, but you don't want to do this for a simple user lookup), so all the information should be in one entity.
You could even keep the assistants in the user collection. Or speaking in more general terms: Keep all subclasses in the entity of its parent class.
Morphia will automatically store the Java class for every entity, so you can simply filter on that. And since there is no strict schema, there are also no null values since the JSON only stores the available attributes.

Get the same java object on saving that object in mongodb

MY POJO looks like this:
#Document(collection = "users")
public class User {
#Id
private String id;
String username;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
I am able to save the object's values in the mongodb by calling mongoDBClient.save(userObj); as bellow:
public void save(Object paramObject) {
mongoOperations.save(paramObject);
}
The problem with this save api is that it's returning void. I want to get the same object which was saved. How can I achieve that?
paramObject is viable for introspection after save. It represents it's persistent state at that stage.
For example, the driver is responsible to assign the id on your behalf.
In addition, all properties which you don't set yourself and are designated to be populated by spring data - such as properties annotated with #CreatedDate - are also available after the save() method (assuming auditing is configured).
In any case, the Id is set. Later you can query for the same object by calling findById(paramObject.getId(), User.class)

JavaEE JPA synchronise object with database

I've got a User class and an Email class.
I used the #OneToMany annotatioin to describe a realationship that one user can have many emails and one email is assigned to one user.
Now the problem is: when creating a user and an email and assigning the email to the user, I try to find a way that the Set of emails is getting initialized by JPA. Usually this works fine when I am doing em.find(User.class, "test");
This only does not work when I'm creating a user. The emails attribute is always of size 0 or even null. But when I create a user, then redeploy my application and then execute em.find(User.class, "test"), the emails attribute is set correctly of size 1 and I can access it.
#Entity
public class User implements Serializable {
private String username;
private String password;
private Set<Email> emails;
#OneToMany(mappedBy = "user", fetch = FetchType.EAGER)
public Set<Email> getEmails() {
return emails;
}
public void setEmails(Set<Email> emails) {
this.emails = emails;
}
#Id
#Column(name = "Username")
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
#Basic
#Column(name = "Password")
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
-
#Entity
public class Email implements Serializable {
private int id;
private String email;
private User user;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "Id")
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#ManyToOne
#JoinColumn(name = "user")
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
#Basic
#Column(name = "Email")
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
-
User user = new User();
user.setUsername("test");
user.setPassword("asdf");
em.persist(user);
Email e = new Email();
e.setEmail("test#test.com");
e.setUser(user);
em.persist(e);
return user;
after executing these statements, the user attribute emails is null (obviously). But strangely when I do em.find(User.class, "test"); in another method, the emails attribute is of size 0, even though the records are correctly inserted to the database.
When I now redeploy my application and call em.find(User.class, "test"); again, the emails attribute is of size 1.
I've already tried to call em.merge(); or em.refresh(); which did not work.
I am using glassfish 4.1.1. As transaction-type I use JTA and eclipselink for the JPA implementation
You need to add the email to the User as well and merge the user if you are doing it in two steps, or (you may need cascade=CascadeType.ALL) just put it in the User to begin with and persist the User if you are doing it in one step.
User user = new User();
Set<Email> emails = new HashSet<Email>();
user.setEmails(emails);
user.setUsername("test");
user.setPassword("asdf");
Email e = new Email();
e.setEmail("test#test.com");
e.setUser(user);
emails.add(e);
em.persist(user);
return user;
You need to set both sides of any bidirectional relationship, JPA will not do it for you. If you do not, the unset side will not reflect what is in the database until it is reloaded/refreshed from the database. You can force the refresh using em.refresh(user), but it is usually better to avoid the database hit and just add the email to the user's list of emails.

JPA find from composite Key

I have a class like this...
#Entity
public class User{
private String userId;
#Id
public String getUserId(){
return userId;
}
public void setUserId(String userId){
this.userId = userId;
}
}
#Embeddible
public class RegPk{
private String serial;
private String userId;
....
}
#Entity
#IdClass(RegPk.class)
public class Registration {
private String userId, serial;
private User user
#Id
#Column(name="SRL_C")
public String getSerial() {return serial;}
public void setSerial(String serial) {this.serial = serial;}
#ManyToOne(cascade={CascadeType.REFRESH})
#JoinColumn(name="USERID", referencedColumnName="USERID", nullable = false)
public User getUser() {return user;}
public void setUser(User user) {this.user = user;}
#Id
#Column(name="USERID", nullable = false)
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
}
RegPk pk = new RegPk();
pk.setSerial(dr.getSerial());
pk.setUserId(dr.getUserId());
Registration userOld = em.find(Registration.class, pk);
But when I try to run it I get null back. I swear I thought I had it working so...
1.) is this kind of thing even possible?
2.) what am I doing wrong?
Yes, it's possible, provided you use the MapsId annotation. Otherwise, you have two different fields mapped to the same column, which is invalid.
The javadoc provides an example which almost matches exactly with your situation.

Mutually referential fields in Play

I am trying to model users with home directories in my system. I got the following model declarations:
#Entity
public class Directory extends Model {
public String name;
#ManyToOne public Directory parent;
#ManyToOne public User owner;
#OneToMany public Set<User> sharees;
}
#Entity
public class User extends Model {
#Unique #Column(unique=true) public String username;
public String password;
public Directory homeDirectory;
public User(String username, String password) {
this.username = username;
this.password = password;
this.homeDirectory = new Directory(username, null, this);
}
}
When I create a user and call .save(), I get an error (A javax.persistence.PersistenceException has been caught, org.hibernate.exception.GenericJDBCException: could not insert: [models.User]). Can anyone explain why?
Using fixtures, can I test this? I'd need to create forward references in my yaml file, but I'm not sure if that's possible.
Thanks,
Vincent.
The error is thrown because of a missing #OneToOne annotation for homeDirectory.
I assume you're creating a directory for each user. If that's the case, then you should also use CascadeType.ALL so these directories automatically get created/deleted when users get created/deleted.
And no Yaml does not support forward references,
so you'll have to work around that when using bidirectional relations.