Persisting User Data with securesocial in Play 2.3 Java - java

I am attempting to create a Java application using Play 2.3 and the master snap-shot of securesocial that will allow users to login using either Facebook , Google+ or Twitter the allow users to link their accounts together and persist this information to a database . I have been having trouble writing a UserService (particularly when linking accounts) that will allow for this. I have found examples using earlier versions of Play/securesocial but have been unable to find an example using the master snap-shot.
If anyone has any examples they could share it would be appreciated.

I was able to create the UserService.
User Model
import play.db.ebean.Model;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
#Entity
#Table(name = "users")
public class User extends Model {
#Id
#GeneratedValue
public Long id;
public Date lastLogin;
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
public List<Profile> identities;
public User(Profile profile){
identities = new ArrayList<Profile>();
this.identities.add(profile);
lastLogin = new Date();
}
public static Finder<String ,User> find = new Finder<String, User>(String.class, User.class);
}
Profile Model
import play.db.ebean.Model;
import securesocial.core.BasicProfile;
import javax.persistence.*;
#Entity
#Table(name = "profiles")
public class Profile extends Model {
#Id
#GeneratedValue
public Long id;
public String providerId;
public String authUserId;
public String firstName;
public String lastName;
public String fullName;
public String email;
public String avatarUrl;
#ManyToOne
#JoinColumn(name = "user_id")
public User user;
public Profile(BasicProfile profile){
this.providerId = profile.providerId();
this.authUserId = profile.userId();
if(profile.firstName().isDefined())
firstName = profile.firstName().get();
if(profile.lastName().isDefined())
lastName = profile.lastName().get();
if(profile.fullName().isDefined())
fullName = profile.fullName().get();
if(profile.email().isDefined())
email = profile.email().get();
if(profile.avatarUrl().isDefined())
avatarUrl = profile.avatarUrl().get();
}
}
And the User Service
package services;
import models.Profile;
import models.User;
import play.libs.F;
import securesocial.core.BasicProfile;
import securesocial.core.PasswordInfo;
import securesocial.core.java.BaseUserService;
import securesocial.core.java.Token;
import securesocial.core.services.SaveMode;
import java.util.Date;
import java.util.List;
public class DemoUserService extends BaseUserService<User> {
#Override
public F.Promise<User> doSave(BasicProfile basicProfile, SaveMode saveMode) {
User result = null;
if(saveMode == SaveMode.SignUp()){
Profile profile = new Profile(basicProfile);
result = new User(profile);
profile.user = result;
result.save();
}else if(saveMode == SaveMode.LoggedIn()){
List<User> users = User.find.all();
for(User user: users){
for(Profile p : user.identities) {
if (p.authUserId.equals(basicProfile.userId()) && p.providerId.equals(basicProfile.providerId())) {
result = user;
result.lastLogin = new Date();
result.update();
}
}
}
}else{
throw new RuntimeException("Unknown mode");
}
return F.Promise.pure(result);
}
#Override
public F.Promise<User> doLink(User user, BasicProfile basicProfile) {
User target;
User u = User.find.byId(user.id.toString());
if(u == null) {
throw new RuntimeException("Cant find user");
}
target = u;
boolean linked = false;
for(Profile p : target.identities){
if(p.authUserId.equals(basicProfile.userId()) && p.providerId.equals(basicProfile.providerId())){
linked = true;
}
}
if(!linked) {
target.identities.add(new Profile(basicProfile));
target.update();
}
return F.Promise.pure(target);
}
#Override
public F.Promise<BasicProfile> doFind(String providerId, String userId) {
BasicProfile found = null;
List<User> users = User.find.all();
for(User u: users){
for(Profile i : u.identities){
if(i.providerId.equals(providerId) && i.authUserId.equals(userId)){
found = new BasicProfile(providerId , userId , null , null , null , null , null , null , null , null , null);
break;
}
}
}
return F.Promise.pure(found);
}
#Override
public F.Promise<BasicProfile> doFindByEmailAndProvider(String s, String s1) {
return null;
}
#Override
public F.Promise<Token> doSaveToken(Token token) {
return null;
}
#Override
public F.Promise<Token> doDeleteToken(String s) {
return null;
}
#Override
public void doDeleteExpiredTokens() {
}
#Override
public F.Promise<Token> doFindToken(String s) {
return null;
}
#Override
public F.Promise<PasswordInfo> doPasswordInfoFor(User user) {
return null;
}
#Override
public F.Promise<BasicProfile> doUpdatePasswordInfo(User user, PasswordInfo passwordInfo) {
return null;
}
}

Related

Cant get spring boot hibernate rest api to return a one to many relationship

I have modelled a car park with building and floor models. There is a one to many relationship between building and floor. I have built a rest controllers to retrieve the data. I am attempting to retrive the data via a simple get request to api/v1/parkingbuildings/1/. The issue is that when retrieving a building i do not see a list of floors as per my relation mapping. Any insight into any mistakes i may be making would be appreciated. Below is the json that gets returned;
{"building_id":1,"building_name":"Labadiestad","postcode":"SA78BQ","max_floors":14,"owner_name":"Schaefer, Gutmann and Braun"}
I am expecting to see a collection of floors in the payload and i cannot fathom why, ive written other similar simpler solutions that do the same without issue, ive compared my prior solutions and see little difference that matters in my approach.
Here is my building model
package com.admiral.reslink.models;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
#Entity(name = "parking_buildings")
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class ParkingBuilding {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long building_id;
private String building_name;
private String postcode;
private int max_floors;
private String owner_name;
// ToDo sort the relationships
#OneToMany(mappedBy = "parkingBuilding")
#JsonIgnore
private List<ParkingFloor> parkingFloors;
public ParkingBuilding() {
}
public long getBuilding_id() {
return building_id;
}
public void setBuilding_id(long building_id) {
this.building_id = building_id;
}
public String getBuilding_name() {
return building_name;
}
public void setBuilding_name(String building_name) {
this.building_name = building_name;
}
public String getPostcode() {
return postcode;
}
public void setPostcode(String postcode) {
this.postcode = postcode;
}
public int getMax_floors() {
return max_floors;
}
public void setMax_floors(int max_floors) {
this.max_floors = max_floors;
}
public String getOwner_name() {
return owner_name;
}
public void setOwner_name(String owner_name) {
this.owner_name = owner_name;
}
public List<ParkingFloor> getParkingFloors() {
return parkingFloors;
}
public void setParkingFloors(List<ParkingFloor> parkingFloors) {
this.parkingFloors = parkingFloors;
}
}
And here is my floor model
package com.admiral.reslink.models;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import javax.persistence.*;
import java.util.List;
#Entity
#Table(name = "parking_floors")
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class ParkingFloor {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long floor_id;
private int floor_number;
private int max_height_inches;
private boolean is_covered;
private boolean is_disabled_access;
// ToDo sort the relationships
#ManyToOne
#JoinColumn(name="building_id", nullable=false)
private ParkingBuilding parkingBuilding;
#OneToMany(mappedBy = "parkingFloor")
#JsonIgnore
private List<ParkingSpace> parkingSpace;
public ParkingFloor() {
}
public long getFloor_id() {
return floor_id;
}
public void setFloor_id(long floor_id) {
this.floor_id = floor_id;
}
public int getFloor_number() {
return floor_number;
}
public void setFloor_number(int floor_number) {
this.floor_number = floor_number;
}
public int getMax_height_inches() {
return max_height_inches;
}
public void setMax_height_inches(int max_height_inches) {
this.max_height_inches = max_height_inches;
}
public boolean isIs_covered() {
return is_covered;
}
public void setIs_covered(boolean is_covered) {
this.is_covered = is_covered;
}
public boolean isIs_disabled_access() {
return is_disabled_access;
}
public void setIs_disabled_access(boolean is_disabled_access) {
this.is_disabled_access = is_disabled_access;
}
public ParkingBuilding getParkingBuilding() {
return parkingBuilding;
}
public void setParkingBuilding(ParkingBuilding parkingBuilding) {
this.parkingBuilding = parkingBuilding;
}
public List<ParkingSpace> getParkingSpace() {
return parkingSpace;
}
public void setParkingSpace(List<ParkingSpace> parkingSpace) {
this.parkingSpace = parkingSpace;
}
}
Here is my building controller
package com.admiral.reslink.controllers;
import com.admiral.reslink.models.ParkingBuilding;
import com.admiral.reslink.models.ParkingFloor;
import com.admiral.reslink.repositories.ParkingBuildingRepository;
import com.admiral.reslink.repositories.ParkingFloorRepository;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
#RestController
#RequestMapping("/api/v1/parkingbuildings")
public class ParkingBuildingController {
#Autowired
private ParkingBuildingRepository parkingBuildingRepository;
#GetMapping
public List<ParkingBuilding> list() {return parkingBuildingRepository.findAll();}
#GetMapping
#RequestMapping("{id}")
public ParkingBuilding get(#PathVariable Long id) {return parkingBuildingRepository.getById(id);}
#PostMapping
public ParkingBuilding create(#RequestBody final ParkingBuilding parkingBuilding) {
return parkingBuildingRepository.saveAndFlush(parkingBuilding);
}
#RequestMapping(value="{id}", method = RequestMethod.DELETE)
public void delete(#PathVariable Long id) {
parkingBuildingRepository.deleteById(id);
}
#RequestMapping(value="{id}", method = RequestMethod.PUT)
public ParkingBuilding update(#PathVariable Long id, #RequestBody ParkingBuilding parkingBuilding) {
ParkingBuilding existingParkingBuilding = parkingBuildingRepository.getById(id);
BeanUtils.copyProperties(parkingBuilding, existingParkingBuilding, "building_id");
return parkingBuildingRepository.saveAndFlush(existingParkingBuilding);
}
}
Not sure how you are retrieving the floors. OneToMany is by default lazy and would not load unless asked.
In your repository, try:
#EntityGraph(attributePaths = "parkingFloors")
ParkingBuilding findById(long id);

Hibernate + JPA + spring boot org.hibernate.PersistentObjectException: detached entity passed to persist

I am using Spring Boot 4, Hibernate and JPA annotations. I ran into this error
org.hibernate.PersistentObjectException: detached entity passed to
persist.
I tried searching through the internet and couldn't quite get the proper answer. I tried to use merge instead of persist and it did not work. Besides I think merge is used when updating a resource.
Here is my code:
`
package com.matome.users.login.stats.springbootStarter.model;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.NamedQueries;
import com.matome.users.login.stats.springbootStarter.userconstants.UserRepositoryConstants;
#NamedQueries({
#NamedQuery(name = UserRepositoryConstants.NAME_GET_ALL_USERS,
query = UserRepositoryConstants.QUERY_GET_ALL_USERS),
#NamedQuery(name = UserRepositoryConstants.NAME_GET_USER_BY_ID,
query = UserRepositoryConstants.QUERY_GET_USER_BY_ID),
#NamedQuery(name = UserRepositoryConstants.NAME_GET_USER_BY_USERNAME,
query = UserRepositoryConstants.QUERY_GET_USER_BY_USERNAME),
#NamedQuery(name = UserRepositoryConstants.NAME_DELETE_USER,
query = UserRepositoryConstants.QUERY_DELETE_USER)
})
#Entity
public class User implements Serializable{
private static final long serialVersionUID = 1L;
#Id #GeneratedValue(strategy = GenerationType.AUTO)
Long id;
String username;
String password;
String phone;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
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 = password;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
`
CRUD service
`
package com.matome.users.login.stats.springbootStarter.CRUDService;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.transaction.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.matome.users.login.stats.springbootStarter.model.User;
import com.matome.users.login.stats.springbootStarter.repository.UserRepository;
#Service
#Transactional
public class UserCRUDService {
#Autowired
UserRepository userRepository;
public User createUser(User user) {
userRepository.save(user);
return user;
}
public User updateUser(User user) {
User existingUser = userRepository.getUserById(user.getId());
if (existingUser == null) {
throw new NoResultException();
}
existingUser.setId(user.getId());
existingUser.setUsername(user.getUsername());
existingUser.setPhone(user.getPhone());
existingUser.setPassword(user.getPassword());
userRepository.update(user);
return user;
}
public User deleteUser(long id) {
User user = userRepository.getUserById(id);
if (user == null) {
throw new NoResultException();
}
userRepository.delete(user);
return user;
}
}
`
Repository
`
package com.matome.users.login.stats.springbootStarter.repository;
import java.util.List;
import javax.persistence.TypedQuery;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.matome.users.login.stats.springbootStarter.model.User;
import com.matome.users.login.stats.springbootStarter.userconstants.UserRepositoryConstants;
#Repository
#Transactional
public class UserRepository extends AbstractRepository<User> {
TypedQuery<User> query;
public List<User> getAllUsers() {
query = entityManager.createNamedQuery(UserRepositoryConstants.NAME_GET_ALL_USERS, User.class);
return query.getResultList();
}
public User getUserById(long id) {
query = entityManager.createNamedQuery(UserRepositoryConstants.NAME_GET_USER_BY_ID, User.class);
query.setParameter("id", id);
return query.getSingleResult();
}
public User getUserByUsername(String username) {
query = entityManager.createNamedQuery(UserRepositoryConstants.NAME_GET_USER_BY_USERNAME, User.class);
query.setParameter("username", username);
return query.getSingleResult();
}
}
`
Abstract repository
`
package com.matome.users.login.stats.springbootStarter.repository;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
#Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
public abstract class AbstractRepository<T> {
#PersistenceContext
protected EntityManager entityManager;
#Transactional(propagation = Propagation.MANDATORY)
public void save(T entity) {
entityManager.persist(entity);
entityManager.flush();
entityManager.refresh(entity);
}
#Transactional
public T update(T entity) {
return entityManager.merge(entity);
}
#Transactional
public void delete(T entity) {
entityManager.remove(entity);
}
}
`
Factory
`
package com.matome.users.login.stats.springbootStarter.factories;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Service;
import com.matome.users.login.stats.springbootStarter.BackingForm.UserBackingForm;
import com.matome.users.login.stats.springbootStarter.model.User;
import com.matome.users.login.stats.springbootStarter.viewmodels.UserViewModel;
#Service
public class UserFactory {
public UserViewModel createViewModel(User user) {
UserViewModel viewModel = new UserViewModel();
viewModel.setId(user.getId());
viewModel.setUsername(user.getUsername());
viewModel.setPhone(user.getPhone());
return viewModel;
}
public List<UserViewModel> createVewModels(List<User> users) {
List<UserViewModel> viewModels = new ArrayList<>();
if (users != null) {
for (User user : users) {
viewModels.add(createViewModel(user));
}
}
return viewModels;
}
public User createEntity(UserBackingForm userBackingForm) {
User user = new User();
user.setId(userBackingForm.getId());
user.setUsername(userBackingForm.getUsername());
user.setPassword(userBackingForm.getPassword());
user.setPhone(userBackingForm.getPhone());
return user;
}
}
`
Backing form
`
package com.matome.users.login.stats.springbootStarter.BackingForm;
public class UserBackingForm {
private long id;
private String username;
private String password;
private String phone;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
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 = password;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
`
Controller
`
package com.matome.users.login.stats.springbootStarter.controller;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.matome.users.login.stats.springbootStarter.BackingForm.UserBackingForm;
import com.matome.users.login.stats.springbootStarter.CRUDService.UserCRUDService;
import com.matome.users.login.stats.springbootStarter.factories.UserFactory;
import com.matome.users.login.stats.springbootStarter.model.User;
import com.matome.users.login.stats.springbootStarter.repository.UserRepository;
import com.matome.users.login.stats.springbootStarter.viewmodels.UserViewModel;
#RestController
#RequestMapping("api")
public class UserController {
#Autowired
private UserRepository userRepository;
#Autowired
private UserCRUDService userCRUDService;
#Autowired
private UserFactory userFactory;
#RequestMapping(value = "/users", method = RequestMethod.GET)
public Map<String, Object> getAllUsers() {
Map<String, Object> map = new HashMap<>();
map.put("users", userRepository.getAllUsers());
return map;
}
#RequestMapping(value = "{id}", method = RequestMethod.GET)
public Map<String, Object> getUserById(#PathVariable long id) {
Map<String, Object> map = new HashMap<>();
map.put("user", userRepository.getUserById(id));
return map;
}
#RequestMapping(value = "/user/add", method = RequestMethod.POST)
public UserViewModel addUser(#RequestBody UserBackingForm form) {
User user = userFactory.createEntity(form);
//user.setIsActive(true);
user = userCRUDService.createUser(user);
return userFactory.createViewModel(user);
}
#RequestMapping(value = "/user/add/{id}", method = RequestMethod.PUT)
public Map<String, Object> updateUser(#PathVariable("id") Long id, #RequestBody User user) {
Map<String, Object> map = new HashMap<>();
user.setId(id);
map.put("updatedUser", userCRUDService.updateUser(user));
return map;
}
#RequestMapping(value = "/test", method = RequestMethod.GET)
public String testFinal() {
return "User test sucessfully";
}
#RequestMapping(value = "{id}", method = RequestMethod.DELETE)
public void deleteUser(#PathVariable("id") Long id) {
User user = userRepository.getUserById(id);
userRepository.delete(user);
}
}
`
View Model
`
package com.matome.users.login.stats.springbootStarter.viewmodels;
public class UserViewModel extends BaseViewModel<Long> {
private String username;
private String phone;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
`
base ViewModel
`
package com.matome.users.login.stats.springbootStarter.viewmodels;
public abstract class BaseViewModel<T> {
private T id;
public T getId() {
return id;
}
public void setId(T id) {
this.id = id;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((getId() == null) ? 0 : getId().hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
#SuppressWarnings("unchecked")
BaseViewModel<T> other = (BaseViewModel<T>) obj;
if (getId() == null) {
if (other.getId() != null)
return false;
} else if (!getId().equals(other.getId()))
return false;
return true;
}
}
`
Main
`
package com.matome.users.login.stats.springbootStarter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class Main { public static void main(String[] args) {
SpringApplication.run(Main.class,args);
}
}
`
Stack Trace
`
org.hibernate.PersistentObjectException: detached entity passed to persist: com.matome.users.login.stats.springbootStarter.model.User
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:124) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:58) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:775) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:748) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:753) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1146) ~[hibernate-entitymanager-5.0.11.Final.jar:5.0.11.Final]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_131]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_131]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_131]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_131]
at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:347) ~[spring-orm-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at com.sun.proxy.$Proxy78.persist(Unknown Source) ~[na:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_131]
`
In my opinion the problem lies in the fact that you have declared the id of User entity as auto-generated:
#Id #GeneratedValue(strategy = GenerationType.AUTO)
Long id;
and when you create the User object you set the id manually:
public User createEntity(UserBackingForm userBackingForm) {
User user = new User();
user.setId(userBackingForm.getId());
...
and thus when you pass that to persist / save, the Persistence Provider will not allow that as it expects that the id will not be set by the client.
The bottom line is that you should not set the id regarding the current configuration when you are aiming at persisting a new entry and you should be fine.
Can you provide a full stack trace ?
Some hints for you :
You should only set #Transactional at Service level, not dao / repository.
Entitymanager refresh method means get data from DB to recreate an entity. If you just persist the entity, there is no need to refresh it.
#Transactional(propagation = Propagation.MANDATORY)
public void save(T entity) {
entityManager.persist(entity);
entityManager.flush(); // This is not really usefull on a small transaction
entityManager.refresh(entity); // No need for that : persist means entity already in sync
}
On update side, if you have a managed entity there is no need to sync it back to the DB, JPA take care of that automatically. (and merge push entity in the db forcing an update of all column) :
public User updateUser(User user) {
User existingUser = userRepository.getUserById(user.getId());
// ...
existingUser.setPassword(user.getPassword());
// ...
userRepository.update(user); // This is not needed !
return user;
}
If you want simplest things, you should take a look at lombok. It will help you write simpliest bean ( #Data to generate getter/setter ...)
You use Spring, so take also a look at spring-Data-JPA, It writes for you some cumberstone code.

When I select a row in MySQL using hibernate classes, it makes an update automatically

I'm trying to develop a blacklist for my users including several variables. So when a user sign up in my application, I check if some parameters are blacklisted or not.
The problem is that when I perform a select and the database find something that fits with my search, it automatically perform an update an clean that row.
This is the MySQL log:
86 Query select * from blacklist where mobile_token = 'b'
86 Query SHOW WARNINGS
86 Query select ##session.tx_read_only
86 Query update mydatabase.blacklist set email=null, iban=null, mobile_token=null, nif=null where blacklist_id=1
86 Query SHOW WARNINGS
86 Query commit
86 Query SET autocommit=1
86 Query SET autocommit=1
86 Query set session transaction read write
This is my table:
My model:
package models.classes_hibernate;
import javax.persistence.*;
import static javax.persistence.GenerationType.IDENTITY;
#Entity
#Table(name="blacklist"
,catalog="mydatabase"
)
public class Blacklist implements java.io.Serializable {
private Integer blacklistId;
private String mobileToken;
private String iban;
private String nif;
private String email;
public Blacklist() {
}
#Id #GeneratedValue(strategy=IDENTITY)
#Column(name="blacklist_id", unique=true, nullable=false)
public Integer getBlacklistId() {
return this.blacklistId;
}
public void setBlacklistId(Integer blacklistId) {
this.blacklistId = blacklistId;
}
#Column(name="mobile_token", nullable = false)
public String getMobileToken() {
return this.mobileToken;
}
public void setMobileToken(String name) {
this.mobileToken = mobileToken;
}
#Column(name="iban", nullable = false)
public String getIban() {
return this.iban;
}
public void setIban(String name) {
this.iban = iban;
}
#Column(name="nif", nullable = false)
public String getNif() {
return this.nif;
}
public void setNif(String name) {
this.nif = nif;
}
#Column(name="email", nullable = false)
public String getEmail() {
return this.email;
}
public void setEmail(String name) {
this.email = email;
}
}
And my DAO:
package models.dao;
import com.google.common.collect.Lists;
import models.classes_hibernate.Blacklist;
import models.pages.Page;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;
import org.hibernate.type.StringType;
import play.Logger;
import play.db.jpa.JPA;
import play.db.jpa.Transactional;
import javax.persistence.NoResultException;
import javax.persistence.Query;
import java.util.List;
public class BlacklistDAOImpl implements MyAppCRUDDAOInterface<Blacklist> {
#Override
public void create(Blacklist entity) {
JPA.em().persist(entity);
}
#Override
public Blacklist read(Integer id) {
return JPA.em().find(Blacklist.class, id);
}
public Page<Blacklist> readAll(String orientation,int pageSize, int beginElementId)
{
Query query = null;
List<Blacklist> blacklists = null;
boolean areThereMore = false;
Page<Blacklist> allBlacklists = null;
int size = 0;
if(orientation.equals("all")) {
query = JPA.em().createNativeQuery("select * from blacklist",Blacklist.class);
}
if(orientation.equals("lt")) {
query = JPA.em().createNativeQuery("select * from blacklist where blacklist_id < ? ORDER BY blacklist_id DESC",Blacklist.class);
query.setParameter(1, beginElementId);
size =query.getResultList().size();
query.setMaxResults(pageSize);
}
if(orientation.equals("gt")) {
query = JPA.em().createNativeQuery("select * from blacklist blacklist_id > ? ORDER BY blacklist_id ASC",Blacklist.class);
query.setParameter(1, beginElementId);
size =query.getResultList().size();
query.setMaxResults(pageSize);
}
if (size>pageSize)
areThereMore = true;
try {
blacklists = query.getResultList();
if (orientation.equals("gt")) {
List<Blacklist> reverseList = Lists.reverse(blacklists);
blacklists = reverseList;
}
allBlacklists = new Page<Blacklist>(blacklists, areThereMore, "Blacklist");
return allBlacklists;
}
catch(NoResultException nre){
allBlacklists=null;
return allBlacklists;
}
}
#Override
public void update(Blacklist entity) {
JPA.em().merge(entity);
}
#Override
public void delete(Blacklist entity) {
JPA.em().remove(entity);
}
#Override
public boolean isManaged(Blacklist entity) {
return JPA.em().contains(entity);
}
#Override
public void close() {
JPA.em().close();
}
public Boolean isMobileTokenBlacklisted(String mobileToken) {
Query query = JPA.em().createNativeQuery("select * from blacklist where mobile_token = ?",Blacklist.class);
query.setParameter(1, mobileToken);
Blacklist blacklist;
try {
Logger.debug("Voy a comprobar");
blacklist = (Blacklist)query.getSingleResult();
} catch (NoResultException nre){
blacklist=null;
}
return blacklist != null;
}
isMobileTokenBlacklisted call:
#POST
#Path("/api/user")
#ApiOperation(position = 3, nickname ="user", value = "Sign up new user",notes = "Minimum JSON required: ",
response = AppUserJSON.class, httpMethod = "POST")
#BodyParser.Of(BodyParser.Json.class)
#Transactional
public static Result signup() {
AppUserDAOImpl appUserDAO = new AppUserDAOImpl();
AppUserJSON user = null;
AppUser appUser = null;
BlacklistDAOImpl blacklistDAO = new BlacklistDAOImpl();
try {
user = parse();
String encrypt_nif = user.nif;
String encrypt_authorization = user.parental_authorization;
String encrypt_password = user.password;
try {
encrypt_password= EncryptUtils.encrypt(config1.getString("key"),user.password);
if(user.nif!= null)
encrypt_nif = EncryptUtils.encrypt(config1.getString("key"),user.nif);
if(user.parental_authorization!= null)
encrypt_authorization = EncryptUtils.encrypt(config1.getString("key"),user.parental_authorization);
} catch (Exception e) {
e.printStackTrace();
}
appUser = new AppUser(new Date(), new Date(),user.email.toLowerCase(), encrypt_password, user.mobile_token,
user.mobile_device, 0, 0, 0, 0, encrypt_nif,
false,"NOT_LOCKED", encrypt_authorization, 0, false);
if (user.email == null) {
return status (200, "email missing");
} else if (blacklistDAO.isEmailBlacklisted(user.email)){
return status(401, "Email is blacklisted");
}
if (user.password == null)
return status(201, "password missing");
if (user.mobile_token == null) {
return status (206, "mobileToken missing");
} else if (blacklistDAO.isMobileTokenBlacklisted(user.mobile_token)){
Logger.debug("MobileToken blacklisted");
return status(401, "Mobile token is blacklisted");
}
if (user.mobile_device== null)
return status(207, "mobileDevice missing");
else{
appUserDAO.create(appUser);
user.app_user_id= appUser.getAppUserId();
return ok(Json.toJson(user));
}
} catch (IncompleteJSONException e) {
return badRequest("IncompleteJSONException");
} catch (DuplicateJSONException e) {
return badRequest("DuplicateJSONException");
}
}
Thanks!
I don't know where it comes from but we can find a way to correct some thing to improve your code and exclude definitely some queries.
Be sure to use bracket around your if. It's not compulsory but is a way to make the code clearer
In the signup method, the else is not logical. It only depends on the last if (mobiledevice test). You probably want to create your user if all test are wrong.
Here you just want to test if you have any blacklisted element corresponding to your research. You can use COUNT function or even EXISTS which can be more efficient maybe.
You can use Debug mode to see where your update is done too.

Playframework2 Ebean : Why doesn't fetch related objects?

Here's my User:
package models.user;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import play.data.validation.Constraints.MaxLength;
import play.data.validation.Constraints.MinLength;
import play.data.validation.Constraints.Required;
import play.db.ebean.Model;
#Entity
#Table(name = "T_USER")
public class User extends Model {
#Id
public Long id;
#Required
#MaxLength(30)
#MinLength(4)
public String username;
#Required
#MaxLength(30)
#MinLength(4)
public String password;
#ManyToOne(fetch = FetchType.EAGER)
#Column(nullable = false)
public Role role;
public static Finder<Long, User> find = new Finder<Long, User>(Long.class, User.class);
public User() {
}
public User(String username, String password, Role role) {
this.username = username;
this.password = password;
this.role = role;
}
#Override
public String toString() {
return "[Tying to login : ] [" + username + " - " + password + "]";
}
}
In my controller, I want to get a user's role instance, so here's what I did:
public static Result modules(Long id) {
User user = User.find.byId(id);
if ("Super User".equalsIgnoreCase(user.role.name)) {
return ok();
} else {
return forbidden();
}
}
The problem is, user.role.name is null, but user.role.id is correct here, why EBean doesn't help me to fetch role for users ?
I have experienced this problem on different occasions. You could do the following:
First, try to replace your public fields with private ones and the add the appropriate getters and setters (this is a good pattern when using Java anyway).
Second, you can write a little helper for finding/fetching the needed information. So let's say you need to get the user by Id and the do this string check. Then in your User class you can write a method like this:
public static User findById(Long id) {
return Ebean.find(User.class)
.fetch("role")
.where()
.eq("id", id)
.findUnique();
}
After that, just use the method:
public static Result modules(Long id) {
User user = User.findById(id);
if ("Super User".equalsIgnoreCase(user.getRole().getName())) {
return ok();
} else {
return forbidden();
}
}

Hibernate criteria when using mapped classes

I have created an object which maps two tables in my database, the Dictionary table and the Token table. The object (class) that represents the join between these two tables is called DictionaryToken.
Here is the class:
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.apache.log4j.Logger;
#Entity
#Table(name="dictionary", catalog="emscribedxcode")
public class DictionaryToken {
private static Logger LOG = Logger.getLogger(DictionaryToken.class);
private Long _seq;
private String _code;
private String _acute;
private String _gender;
private String _codeType;
private String _papplydate;
private String _capplydate;
private Long _tokenLength;
private List <TokenDictionary> _token;
private int _type;
private String _system;
private String _physicalsystem;
/*
* type of 0 is a straight line insert type of 1 is a language dictionary
* entyr type of 2 is a multiple token entry
*/
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "seq")
public Long getSeq() {
return _seq;
}
public void setSeq(Long seq_) {
_seq = seq_;
}
#Column(name = "code")
public String getCode() {
return _code;
}
public void setCode(String code_) {
_code = code_;
}
#Column(name = "acute")
public String getAcute() {
return _acute;
}
public void setAcute(String acute_) {
_acute = acute_;
}
#Column(name = "gender")
public String getGender() {
return _gender;
}
public void setGender(String gender_) {
_gender = gender_;
}
#Column(name = "codetype")
public String getCodeType() {
return _codeType;
}
public void setCodeType(String codeType_) {
_codeType = codeType_;
}
#Column(name = "papplydate")
public String getPapplydate() {
return _papplydate;
}
public void setPapplydate(String papplydate_) {
_papplydate = papplydate_;
}
#Column(name = "capplydate")
public String getCapplydate() {
return _capplydate;
}
public void setCapplydate(String capplydate_) {
_capplydate = capplydate_;
}
#Column(name = "token_length")
public Long getTokenLength() {
return _tokenLength;
}
public void setTokenLength(Long tokenLength_) {
_tokenLength = tokenLength_;
}
#OneToMany (mappedBy = "dictionarytoken", targetEntity = TokenDictionary.class, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
public List<TokenDictionary> get_token() {
return _token;
}
public void set_token(List<TokenDictionary> _token) {
this._token = _token;
}
public void addToToken(TokenDictionary token){
this._token.add(token);
}
#Column(name = "type")
public int getType() {
return _type;
}
public void setType(int _type) {
this._type = _type;
}
#Column(name = "physicalsystem")
public String get_physicalsystem() {
return _physicalsystem;
}
public void set_physicalsystem(String _physicalsystem) {
this._physicalsystem = _physicalsystem;
}
#Column(name = "codingsystem")
public String get_system() {
return _system;
}
public void set_system(String _system) {
this._system = _system;
}
}
Here is my problem. I can perform queries using a service with this object with no problems UNLESS I add a criteria. Here is the method which retrieves the entries
public List<DictionaryToken> getDictionaryTokenEntries(String system) {
Session session = null;
List<DictionaryToken> dictonaries = new ArrayList<DictionaryToken>();
try {
session = HibernateUtils.beginTransaction("emscribedxcode");
session.createCriteria(Dictionary.class).addOrder(Order.desc("codeType"))
Criteria criteria = session.createCriteria(DictionaryToken.class);
/*******THIS IS THE PROBLEM STATEMENT*************************/
if (system != null) {
criteria.add(Restrictions.eq("codingsystem", system));
}
/****************************************************************/
// dictonaries = criteria.list();
Order order = Order.asc("seq");
criteria.addOrder(order);
dictonaries = criteria.list();
System.out.println("Dictionaryentries = " + dictonaries.size());
// System.out.println("Dictionaries entries EVICT start...");
// for(Dictionary dic : dictonaries){
// session.evict(dic);
// }
// System.out.println("Dictionaries entries EVICT end");
} catch (HibernateException e_) {
e_.printStackTrace();
NTEVENT_LOG.error("Error while getting List of Dictionary entries");
} finally {
if (session != null && session.isOpen()) {
try {
HibernateUtils.closeSessions();
} catch (HibernateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return dictonaries;
}
When I add the criteria, I get the following error:
org.hibernate.QueryException: could not resolve property: coding system of : com.artificialmed.domain.dictionary.model.DictionaryToken
I know that it has something to do with the nature of the object which is really a join between my dictionary class and the underlying table and my token class and table.
The field codingsystem is a field in my dictionary class. I think I am suppose to use aliases but I don't know how to do this under the current circumstances. Any help would be greatly appreciated.
Elliott
This was a newbie problem. Hibernate requires the getters and setters of the models that reflect the tables to be of a specific format. The getter MUST BE get+ where name is the fieldname in the underlying table. The setter MUST BE set+ where name is the fieldname of the underlying table. And yes the first letter of Name must capitalized.

Categories

Resources