how to set values to Set<Object> through setter methods - java

I want to set values to Set object through setter methods.
#Override
public User mapRow(final ResultSet resultSet, final int rownumber)
throws SQLException {
Set<UserRole> userRoles = new HashSet<UserRole>();
// tried with like this but it is not possible
userRoles.add(userRoles.setUserId("ID"));
return null;
}
how can i set those values to set object.

Your question is not clear!. You wanted to add the id to specific UserRole Object(s) which is present in Set collection..??? or how you wahted to do..?
what ever you do your Set is a genaric of UserRole Object so you can add only object of UserRole not any other type!.
Hear your trying to set other than UserRole Object (In your case it may be String/Integer) so usaully setter method is void means return nothing!!!
userRoles.add(userRoles.setUserId("ID"));
So first heave the UserRole object ready by setting ID like
UserRole role = new UserRole();
// Set what ever the value you want
role.setId("ID");
Then do as bellow
Set<UserRole> userRoles = new HashSet<UserRole>();
// tried with like this but it is not possible
userRoles.add(role);

You are using a Set with a generic type of UserRole:
But then you are trying to add
userRoles.add(userRoles.add(...
which tries to add a boolean for the outer call!
Can't work!
You see, Set.add() takes an "E" input and gives back boolean. So you can't add(add())!
And then: your method is supposed to return an object of type User; but then you create a Set<UserRole> ... which you also want to return.
So long story short: you should have a closer look into the java basics first. It seems that you really do not know what you are doing.

Related

Java/SpringBoot Web app. Insert new row with auto-incremented id column

I am trying to store a new row using a few input lines on a web app into an SQL table. My jsp has all the input rows I need. However, I need to store the new object without inputting a new Id because it's auto incremented. I'm able to call my constructor to store everything else but the id.
my code for that section so far is:
#RequestMapping(value = "/save", method = RequestMethod.POST)
public ModelAndView save
//Index connect
(#RequestParam("id") String id, #RequestParam("type") String animalType,
#RequestParam("name") String animalName, #RequestParam("age") int animalAge){
ModelAndView mv = new ModelAndView("redirect:/");
AnimalConstruct newAnimal;
newAnimal.setAnimalType(animalType);
newAnimal.setAnimalName(animalName);
newAnimal.setAnimalAge(animalAge);
animals.save(newAnimal);
mv.addObject("animalList", animals.findAll());
return mv;
So if I wanted to store "(id)11, (type)bird, (name)patty, (age)5" and I'm only making the type, name, and age inputtable, what should I do for the id? The object technically injects the id as empty I think, but then I get thrown an error. I'm very new to java and Springboot and have very weak skills in both.
The magic happens with a JPA implementation (Hibernate, for instance). Just annotate your id field like:
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
When saving the object, the id will be auto-generated and stored.
Check some similar questions: Hibernate Auto Increment ID and How to auto generate primary key ID properly with Hibernate inserting records
You should not pass the ID when you expect to create an object.
#RequestMapping(value = "/protected", method = RequestMethod.POST)
public RouteDocument doPost(#RequestBody RouteDocument route) throws ControllerException {
createNewRoute(route);
return route;
}
In the previous example, the method createNewRoute, calls the database, in my case using spring JpaTemplate to save it. The object route has an ID property that is filled by JpaTemplate.save. Consequently the doPost return object returns you the same object you passed as parameter BUT with the automatically assigned ID.
Annotate your id column in the bean with :
#Id
#GeneratedValue (strategy = GenerationType.IDENTITY)
private long id;
As answered by #pedrohreis above you can also use GenerationType.AUTO but only if your sole purpose is to make autoincrement id then I prefer GenerationType.IDENTITY
Also, looking forward in your project if you wanna disables batch updates on your data then you should use GenerationType.IDENTITY.
Refer : hibernate-identifiers

Trying to save different java objects which represents the same entity. Hibernate

(This is a simplification of the real problem)
Let's start with the following little class:
#Entity
class Test {
Test(int id, String name) {
this.id = id;
this.name = name;
}
#Id
private int id;
#Column
private String name;
#Override
public int hashCode() {
return id;
}
#Override
public boolean equals(Object obj) {
if (obj instanceof Test) {
return id == ((Test) obj).id;
}
return false;
}
}
If we execute the following, no exception occurs:
EntityManagerFactory factory = Persistence.createEntityManagerFactory("local_h2_persistence");
EntityManager theManager = factory.createEntityManager();
EntityTransaction t = theManager.getTransaction();
Test obj1 = new Test(1, "uno");
tA.begin();
AtheManager.persist(obj1);
AtheManager.persist(obj1); // <-- No exception
tA.commit();
I guess the second call is ignored, or maybe the object is saved to the DB again. The thing is there is no problem in saving the same entity twice. Now let's try the following:
EntityManagerFactory factory = Persistence.createEntityManagerFactory("local_h2_persistence");
EntityManager theManager = factory.createEntityManager();
EntityTransaction t = theManager.getTransaction();
Test obj1 = new Test(1, "uno");
Test obj1_ = new Test(1, "uno");
tA.begin();
AtheManager.persist(obj1);
AtheManager.persist(obj1_); // <-- javax.persistence.EntityExistsException: a different object with the same identifier value was already associated with the session
tA.commit();
What? How could it possibly be relevant that the object is in a different memory location? Somehow it is and the code throws an exception.
How can I make the second example work just like the first?
I am just rewriting what #jb-nizet wrote in the comments, which feels like the answer to me:
Hibernate doesn't use ==. It simply does what you're telling it to do.
persist's contract is: associate this object with the session. If it's
already associated to the session, it's a noop. If it isn't, it is
associated to the session to be inserted in the database later. If
what yo want to do is make sure the state of this object is copied to
a persistent entity, and give me back that persistent entity, then
you're looking for merge().
So the solution was to just use
AtheManager.merge(obj1);
instead of
AtheManager.persist(obj1);
In first case, you save the same object twice, which is allowed.
But in second case, you save two different object to database, but both has the same primary key. It is database constraint violation.
In the first example you pass a reference to an object to save it and in the second call you pass exactly the same reference; they both point to the same object in memory.
However, in the second example you allocated two objects with two new calls which creates the objects at two different memory addresses; they are two different objects. The first reference points to some other memory address then the second object's reference. If you tried this in the second example it would return false: obj1 == obj1_

Constructor takes two Integers and they must not equal, whats the best way to implement this?

public MyClass(Integer userId, Integer otherId) {
if(!userId.equals(otherId)){
this.userId = userId;
this.otherId = otherId;
}
}
Thats as far as I got, I want to ensure an instance if never created with matching id's ?
If you can't allow the two values to be equal then pretty much your only option it to raise an exception in that case.
I created another method and made the constructor private, it returns null if matching ids
private MyClass(Integer userId, Integer otherId) {
{
this.userId = userId;
this.otherId = otherId;
}
}
public static MyClass getInstance(Integer userId, Integer otherId)
if(!userId.equals(otherId)){
return new MyClass(userId,otherId);
}
return null;
}
I might be completely missing the point of your design, but if you want to create instances of an object with unique ID's that never clash consider using a UUID. Your instances should never have to do a 'circle-jerk' of ID comparisons to make sure none of them are violating the uniqueness constraints.
Documentation on UUID.
I use another approach, I keep a registry of newly created instances (in an HashSet) and allow instatiation of Objects via a static factory.
class User {
private int _id;
private static HashSet _instanced = new HashSet();
public static User getInstance(Integer id) {
if (_instanced.contains(id)) {
return null;
}
return new User(id);
}
private User(Integer id) {
_id = id.toInt();
}
// Getter/Setter for ID
}
Since the constructor is private, none will instantiate another User with the same id.
in your methods you could then write
User x = User.getInstance(1);
Of course this will add one more level to your solution. Still I prefer this kind of approach.

Scope of object within an object in Java

I'm learning Java at the moment so I hope this question isn't too obvious. I come from another language which does not have garbage collection.
In this other language I sometimes created objects in constructor and then deleted them in the destructor so I could use them for the entire life of the object.
As a simplified example, I have a user and a booking class. The booking class references a user but if I create the user in the constructor of the booking class, it dereferences the user once it leaves the constructor and becomes out of scope. Any future reference call to the booking.bookedBy user then returns null.
class user {
public String username;
public String displayName;
user(Connection conn, String usernameIn){
username = usernameIn;
... do DB stuff to populate attributes
}
}
class booking {
int bookingID;
user bookedBy;
...
booking(Connection conn, int bookedIDIn){
bookingID = bookedIDIn;
...do DB stuff to populate attributes and grab bookedByUserID
...field value and build the BookedByUsername
user bookedBy = new user (bookedByUsername)
}
}
Is there a way around this? Or do I need to rethink my design?
You are creating a new bookedBy user variable in your constructor, rather than using your class' member variable.
You probably want to change:
user bookedBy = new user(bookedByUsername);
with:
bookedBy = new user(bookedByUsername);
You're declaring a local variable in your constructor and it's being used to assign the user you create in the constructor.
I think you want this:
class booking {
int bookingID;
user bookedBy;
...
booking(Connection conn, int bookedIDIn){
bookingID = bookedIDIn;
//there's no declaration of type needed here because
//you did that earlier when you declared your member variable up top.
bookedBy = new user (bookedByUsername)
}
}
In your booking class, you actually have declared two variables called user bookedBy. One has scope for the entire booking class and one has scope for the constructor. To fix this problem, you need to remove the variable declaration in your constructor as show below:
class booking {
int bookingID;
user bookedBy;
...
booking(Connection conn, int bookedIDIn){
bookingID = bookedIDIn;
...do DB stuff to populate attributes and grab bookedByUserID
...field value and build the BookedByUsername
bookedBy = new user (bookedByUsername)
}
}
user bookedBy;
and
user bookedBy = new user (bookedByUsername)
are two different variables.
Remove the second type declaration and your user instance will be allocated to the field level. ie:
class booking {
int bookingID;
user bookedBy;
...
booking(Connection conn, int bookedIDIn){
bookingID = bookedIDIn;
...do DB stuff to populate attributes and grab bookedByUserID
...field value and build the BookedByUsername
bookedBy = new user (bookedByUsername)
}
}

many-to-many JPA mapping inserting but not fething the child collections

i've hit a block once again with hibernate.I've posted numerous times on different aspects of the user and contact management that i've been building.
The sad thing is that i didn't really have the time to play with it and understand it better before actually starting working with it. Sorry but English is not my native language, i rather speak french. And again i've started coding in java in an autodidact way.i'm doing all of this by reading books and haven't gone to school for it. with time constraints it's hard to read a book from beginning to the end.
I'm not sure i should put every of my codes dealing with an issue here and from what i've learned from other forum is to post just the necessary and being concise.
So in my User model i have UserAccount class, Profile that holds details like name, preferences etc , AccountSession and Phone.
my contact management model have Contact and Group.
UserAccount has one-to-one association with Profile, one-to-many with AccountSession,contact and group, all bidirectional.the one-to-many association with phone is unidirectional because contact also has and unidirectional with Phone.
Contact has a bidirectional many-o-many with group and one-to-many with phone that i said earlier.
Group also has a many-to-many bedirectional with contact.
here are the mappings
// UserAccount
......
#OneToOne(targetEntity=UserProfileImpl.class,cascade={CascadeType.ALL})
#org.hibernate.annotations.Cascade(value=org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
#JoinColumn(name="USER_PROFILE_ID")
private UserProfile profile;
#OneToMany(targetEntity=ContactImpl.class, cascade={CascadeType.ALL}, mappedBy="userAccount")
#org.hibernate.annotations.Cascade(value=org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
private Set<Contact> contacts = new HashSet<Contact>();
#OneToMany(targetEntity=GroupImpl.class, cascade={CascadeType.ALL}, mappedBy="userAccount")
#org.hibernate.annotations.Cascade(value=org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
private Set<Group> groups = new HashSet<Group>();
.......
//Group
#ManyToOne(targetEntity=UserAccountImpl.class)
#JoinColumn(name="USER_ACCOUNT_ID",nullable=false)
private UserAccount userAccount;
#ManyToMany(targetEntity=ContactImpl.class,cascade={CascadeType.PERSIST, CascadeType.MERGE})
#JoinTable(name="GROUP_CONTACT_MAP", joinColumns={#JoinColumn(name="GROUP_ID")},
inverseJoinColumns={#JoinColumn(name="CONTACT_ID")})
private Set<Contact> contacts = new HashSet<Contact>();
//Contact
....
#ManyToOne(targetEntity=UserAccountImpl.class)
#JoinColumn(name="USER_ACCOUNT_ID",nullable=false)
private UserAccount userAccount;
#ManyToMany(targetEntity=GroupImpl.class, mappedBy="contacts")
private Set<Group> groups=new HashSet<Group>();
....
// helper methods from group
public void addContact(Contact contact) {
try{
this.getContacts().add(contact);
contact.getGroups().add(this);
}catch(Exception e) {
}
}
//helper method from group
public void removeContact(Contact contact) {
contact.getGroups().remove(contact);
this.getContacts().remove(contact);
}
//helper method from contact
public void addGroup(Group group) {
try{
this.getGroups().add(group);
group.getContacts().add(this);
} catch(Exception e) {
e.printStackTrace();
}
}
//Helper method from group
public void removeGroup(Group group){
try{
group.getContacts().remove(this);
this.getGroups().remove(group);
} catch(Exception e) {
e.printStackTrace();
}
}
//UserAccount setter from Contact.All the children with many-to-one have the same
/**
* #param userAccount the userAccount to set
*/
public void setUserAccount(UserAccount userAccount) {
this.userAccount = userAccount;
}
I'ld like to pull the UserAccount by its email field which is an unique field in the UserAccount table.
In the UserAccountDAO the method i call to get the UserAccount is getUserAccountByEmail here below.So i expect this method to load all the children collections of the UserAccount namely its Contact collection, group collection.I want it in such a way that when UserAccount is loaded with Contacts collection each of the contact object has its reference with its belonging groups collection if any etc and vice versa.
public UserAccount getUserAccountByEmail(String email) {
// try {
logger.info("inside getUserAccountByEmail");
logger.debug(email);
Session session = (Session) this.getDBSession().getSession();
UserAccount user = (UserAccount) session.createCriteria(this.getPersistentClass())
.setFetchMode("contacts", FetchMode.SELECT) //recently added
.setFetchMode("groups", FetchMode.SELECT) // recently added
.add(Restrictions.eq("email", email))
.uniqueResult();
logger.debug(user);
return user;
// } catch(NonUniqueResultException ne) {
// logger.debug("Exception Occured: getUserAccountByEmail returns more than one result ", ne);
// return null;
// } catch(HibernateException he){
// logger.debug("Exception Occured: Persistence or JDBC exception in method getUserAccountByEmail ",he);
// return null;
// }catch(Exception e) {
// logger.debug("Exception Occured: Exception in method getUserAccountByEmail", e);
// return null;
// }
Since there has to be an UserAccount before any contact and groups, in my unit test when testing the saving of a contact object for which there must be an existing group i do this in order
a create userAccount object ua.
b create group object g1;
c create contact object c1;
d ua.addGroup(g1);
e c1.setUserAccount(ua);
f c1.addGroup(g1);
g uaDao.save(ua); // which saves the group because of the cascade
h cDao.save(c1);
Most of the time i use the session.get() from hibernate to pull c1 by its it id generated by hibernate and do all the assertions which works actually.
but in Integration test when i call getUserAccountByEmail with and without the setFetchMode and it returns the right object but then all the children collections are empty. i've tried the JOIN and the SELECT.the query string changes but then the result set is still the same. So this arises some questions :
1. What should i do to fix this?
2. the helper method works fine but it's on the parent side(i do it in the test).What i've been wondering about is that doing c1.setUserAccount(ua); is enough to create a strong relationship between UserAccount and contact.most of the time there will not be cases where i save the userAccount with contact but yet the helper method that set the association in both side and which is in UserAccount will not been called before i save the contact for a particular userAccount.So i'm little confused about that and suspecting that setting of the association is part of the why something is not working properly.and then calling session.get(UserAccount.class, ua.getID()) i think goes what i want and i'ld like getUserAccountByEmail to do the same.
3. ChssPly76 thinks the mapping has to be rewrite.So i'm willing to let you guide me through this.I really need to know the proper way to do this because we can't lean everything from a good book.So i you think i should change the mapping just show me how.and probable i'm doing things the wrong way without even been aware of that so don't forget i'm still learning java itself.THanks for the advise and remarks and thanks for reading this
I agree with you that it seems likely that the associations between your parent objects and their child collections are not getting persisted properly. I always like to start out by looking at what is in the database to figure out what's going on. After you run your test what do you see in the actual database?
It seems likely that one of two things is happening (using UserAccount as an example):
The items in the child collection are not getting saved to the database at all, in which case you'll be able to see in the database that there are no records associated with your UserAccount. This could be caused by saving the UserAccount object before you've added the child object to the UserAccount's collection.
The items in the child collection are getting saved to the database, but without the needed association to the parent object, in which case you'll see rows for your child items but the join column (ie 'userAccount' will be null). This could be caused by not setting the userAccount() property on the child object.
These are the two scenarios that I've run into where I've seen the problem you describe. Start by taking a look at what goes into your database and see if that leads you farther.

Categories