How to get specific inheritant entity using generic dao and service layer - spring

Working on my spring mvc project I face following issu:
I have UnitAppUser, VStanAppUser and RjuAppUser entity classes which extend User entity. User entity stores some general informations. Rest of inheritant entities stores the references to the particular entities (UnitAppUser has a field Unit type, VStanAppUser has a VStan type so on).
Here is my parent User entity
#Entity
#Inheritance(strategy=InheritanceType.JOINED)
#Table(name="app_user")
public class User implements Serializable {
/**
*
*/
private static final long serialVersionUID = 6628717324563396999L;
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
#NotEmpty
#Column(name="SSO_ID", unique=true, nullable=false)
private String ssoId;
#NotEmpty
#Column(name="PASSWORD", nullable=false)
private String password;
#NotEmpty
#Column(name="FIRST_NAME", nullable=false)
private String firstName;
#NotEmpty
#Column(name="LAST_NAME", nullable=false)
private String lastName;
#NotEmpty
#Column(name="EMAIL", nullable=false)
private String email;
}
Here's my child classes:
#Entity
#Table(name = "unit_app_user")
public class UnitAppUser extends User implements Serializable {
#JoinColumn(name = "UNITWORK", referencedColumnName = "ID")
#ManyToOne(optional = false)
private UnitDepart unitdepart;
public UnitDepart getWorkat() {
return unitdepart;
}
public void setWorkat(UnitDepart unitdepart) {
this.unitdepart = unitdepart;
}
}
#Entity
#Table(name="rju_app_user")
public class RjuAppUser extends User implements Serializable{
#JoinColumn(name = "workrju", referencedColumnName = "id")
#ManyToOne(optional = false)
private Rju rju;
public Rju getWorkat() {
return rju;
}
public void setWorkat(Rju rju) {
this.rju = rju;
}
}
and finally my VStan entity:
#Entity
#Table(name="vstan_app_user")
public class VstanAppUser extends User implements Serializable{
#JoinColumn(name = "WORKSTATION", referencedColumnName = "kod")
#ManyToOne(optional = false)
private Vstan vstan;
public Vstan getWorkat() {
return vstan;
}
public void setWorkat(Vstan vstan) {
this.vstan = vstan;
}
}
How to write generic dao and service to get specific entity?
As a result I should have something like this
userService.findBySSOId("somessoId").getWorkat() //should return UnitDepart, Rju or VStan

Related

OneToOne CascadeType in spring data jpa

I use OneToOne in the spring data JPA and I want to delete a record from the Address table without touching the user. But I can't.
If I remove User, in this case Address is removed, that's good.
But how can you delete an Address without touching the User?
https://github.com/myTestPercon/TestCascade
User.Java
#Entity
#Table(name = "user", schema = "testCascade")
public class User implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "name")
private String name;
#OneToOne(mappedBy = "user", cascade = CascadeType.ALL)
private Address address;
// Getter and Setter ...
}
Address.java
#Entity
#Table(name = "address", schema = "testCascade")
public class Address implements Serializable {
#Id
private Long id;
#Column(name = "city")
private String city;
#OneToOne
#MapsId
#JoinColumn(name = "id")
private User user;
// Getter and Setter ...
}
DeleteController.java
#Controller
public class DeleteController {
#Autowired
ServiceJpa serviceJpa;
#GetMapping(value = "/deleteAddressById")
public String deleteAddressById () {
serviceJpa.deleteAddressById(4L);
return "redirect:/home";
}
}
You got your mapping wrong thats all is the problem .
try the below and see
User.java
#Entity
#Table(name = "user", schema = "testCascade")
public class User implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "name")
private String name;
#OneToOne(cascade=CascadeType.ALL)
#JoinColumn(name="foriegn key column in user table for address example.. address_id")
private Address address;
// Getter and Setter ...
}
Address.java
#Entity
#Table(name = "address", schema = "testCascade")
public class Address implements Serializable {
#Id
private Long id;
#Column(name = "city")
private String city;
//name of the address variable in your user class
#OneToOne(mappedBy="address",
cascade={CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST,
CascadeType.REFRESH})
private User user;
// Getter and Setter ...
}
In order to solve this problem, you need to read the hibernate Documentation Hibernate Example 162, Example 163, Example 164.
And also I recommend to look at this is Using #PrimaryKeyJoinColumn annotation in spring data jpa
This helped me in solving this problem.
And also you need to specify the parameter orphanRemoval = true
User.java
#Entity(name = "User")
#Table(name = "user", schema = "testother")
public class User implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "name")
private String name;
#OneToOne(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
private Address address;
public void addAddress(Address address) {
address.setUser( this );
this.address = address;
}
public void removeAddress() {
if ( address != null ) {
address.setUser( null );
this.address = null;
}
}
// Getter and Setter
}
Address.java
#Entity(name = "Address")
#Table(name = "address", schema = "testother")
public class Address implements Serializable {
#Id
private Long id;
#Column(name = "city")
private String city;
#OneToOne
#MapsId
#JoinColumn(name = "id")
private User user;
// Getter and Setter
}
DeleteController .java
#Controller
public class DeleteController {
#Autowired
ServiceJpa serviceJpa;
#GetMapping(value = "/deleteUser")
public String deleteUser () {
User user = serviceJpa.findUserById(2L).get();
user.removeAddress();
serviceJpa.saveUser(user);
return "/deleteUser";
}
}
Or make a custom SQL query.
#Repository
public interface DeleteAddress extends JpaRepository<Address, Long> {
#Modifying
#Query("delete from Address b where b.id=:id")
void deleteBooks(#Param("id") Long id);
}
public class Address {
#Id
private Long id;
#MapsId
#JoinColumn(name = "id")
private User user;
}
Rename #JoinColumn(name = "id") to #JoinColumn(name = "user_id")
You can't say that the column that will point to user will be the id of the Address

Could not able to delete collection rows in JPA while calling save()

I have this below entity classes.
Parent Entity:
---------------
public class MLW implements Serializable {
#Id
#Column(name = "mlwId", updatable = false, nullable = false)
private String mlwId;
#OneToOne(optional = false, fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name="mlwId")
private MLWJob mlwJob;
private Date createdDate;
private Date lastUpdatedDate;
}
public class MLWJob implements Serializable {
#Id
private String mlwId;
#Column(name = "Id")
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name="mlwId")
private List<MLWJobItem> items;
}
public class MLWJobItem implements Serializable {
#Id
private String itemId;
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name="itemId")
private List<MLWJobItemExtension> mlwJobItemExtensions;
}
public class MLWJobItemExtension implements Serializable {
#Id
private String extnId;
#Id
private String itemId;
private String name;
private String value;
}
Repository class:
------------------
public interface MLWRepository extends JpaRepository<MLW, String> {
}
When I try to call save method using above repository I am getting below exception. Could someone help me to understand and fix this issue? TIA
could not delete collection rows:
[com.cpc.wgln.entity.MLWJobItem.mlwJobItemExtensions#0105021001713441];
nested exception is org.hibernate.exception.GenericJDBCException:
could not delete collection rows:
[com.cpc.wgln.entity.MLWJobItem.mlwJobItemExtensions#0105021001713441]

AuditingEntityListener is not working for the entity that extends another abstract entity in spring jpa

I have used the #CreatedBy, #CreatedDate, #LastModifiedBy, and #LastModifiedDate annotation on their respective fields. By using #MappedSuperclass,#EntityListeners i able to persist above columns.
But this is not working for the below case:
#MappedSuperclass
#EntityListeners(AuditingEntityListener.class)
public abstract class Auditable<U> {
#CreatedBy
protected U createdBy;
#CreatedDate
#Temporal(TIMESTAMP)
protected Date creationDate;
#LastModifiedBy
protected U lastModifiedBy;
#LastModifiedDate
#Temporal(TIMESTAMP)
protected Date lastModifiedDate;
}
#Entity
#Table(name = "tabel1")
#PrimaryKeyJoinColumn(name = "ID")
class A extends B {
#Column(name = "NAME1", nullable = false)
private String name1;
#Column(name = "CONTENT1", nullable = false)
private String content1;
}
#Entity
#Table(name = "tabel2")
public abstract class B extends Auditable{
#Id
#GeneratedValue
#Column(name = "ID", nullable = false)
private int id;
#Column(name = "NAME", nullable = false)
private String name;
#Column(name = "CONTENT", nullable = false)
private String content;
}
AuditorAwareImpl.java
public class AuditorAwareImpl implements AuditorAware<String>
{
#Override
public Optional<String> getCurrentAuditor()
{
return Optional.ofNullable("Saravanan");
}
}
JpaAuditConfiguration.java
#Configuration
#EnableJpaAuditing(auditorAwareRef = "auditorProvider")
public class JpaAuditConfiguration
{
#Bean
public AuditorAware<String> auditorProvider()
{
return new AuditorAwareImpl();
}
}
In the case, Entity B is populated with audit columns. But Entity A is not. Is there a way to populate Entity A or did i missed anything here..??
I added #Entity annotation to your classes:
#Entity
public class A extends B {
#Id
#GeneratedValue
private Integer id;
private String name;
private String content;
}
#Entity
public class B extends Auditable<String> {
#Id
#GeneratedValue
private Integer id;
private String name;
private String content;
}
Persistence config class (for Spring Boot):
#Configuration
#EnableJpaAuditing
public class PersistenceConfig {
}
Everything works perfectly!

How to get an Authenticated User's Details in Spring Security OAuth2

I am unable to extract the current logged in user in Spring Security OAuth2. My goal is to extract the user when the create event on ClientSuggestion entity is triggered and persist it to the database.
Employee.java
#Entity
#Table(name = "er_employee")
public class Employee implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "username", unique = true)
#NotNull
#Size(max = 10)
private String username;
#Column(name = "password_hash")
#NotNull
#Size(min = 8, max = 512)
private String password;
#Column(name = "email_verification_token")
#Size(max = 512)
private String emailVerificationToken;
#Column(name = "password_reset_token")
#Size(max = 512)
private String passwordResetToken;
#Column(name = "active")
#NotNull
private boolean active;
#Column(name = "is_deleted")
#NotNull
private boolean deleted;
#Column(name = "date_of_creation")
#Temporal(TemporalType.TIMESTAMP)
#NotNull
private Date dateOfCreation;
#OneToMany(mappedBy = "employee")
private List<ClientSuggestion> clientSuggestions;
//Constructors
//Getters ans setters
}
ClientSuggestion.java
#Entity
#Table(name = "er_suggestion")
public class ClientSuggestion implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "content", unique = true)
#NotNull
#Size(max = 200)
private String suggestion;
#ManyToOne
#JoinColumn(name = "employee_id")
private Employee employee;
//Constructors
//Getters ans setters
}
EmployeeRepository.java
public interface EmployeeRepository extends CrudRepository<Employee, Long> {
ClientSuggestionRepository .java
public interface ClientSuggestionRepository extends CrudRepository<ClientSuggestion, Long> {
}
The event handler
#Component
#RepositoryEventHandler(ClientSuggestion.class)
public class ClientSuggestionEventHandler {
Employee employee= (Employee ) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
#HandleBeforeCreate
public void handleClientSuggestionBeforeCreate(ClientSuggestion cs) {
cs.setDeleted(false);
cs.setActive(true);
cs.setPasswordResetToken(Encryptor.generateHash(cs.getPassword, 512));
cs.setEmployee(employee);
}
}
The bean, ClientSuggestionEventHandler, is registered in a configuration class. When I tried running the project, NullPointerException exception is thrown. I wish to find out how to get the current logged employee.
I'm new to Spring Security OAuth2. Thanks.
In Employee.java implement org.springframework.security.core.userdetails.UserDetails class
Employee.java
#Entity
#Table(name = "er_employee")
public class Employee implements Serializable, UserDetails {
And then use Employee employee= (Employee) SecurityContextHolder.getContext().getAuthentication().getPrincipal();

How to lazy fetch with spring data repository?

Database Tables
post
tag
ref_post_tag
post and tag has a Many-to-Many relationship
Entities
Post
#Entity
#Table(name = "post")
public class Post implements Serializable{
private static final long serialVersionUID = 1783734013146305964L;
public enum Status {
DRAFT, REMOVED, LIVE;
}
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
private String id;
#Column(name = "title")
private String title;
#Column(name = "create_time")
private LocalDateTime createTime;
#Column(name = "update_time")
private LocalDateTime updateTime;
#Column(name = "content")
private String content;
#Column(name = "status")
#Enumerated(EnumType.STRING)
private Status status;
#ManyToMany
#JoinTable(
name = "ref_post_tag",
joinColumns = #JoinColumn(name="post_id",referencedColumnName = "id"), inverseJoinColumns = #JoinColumn(name="tag_id", referencedColumnName = "id"))
private List<Tag> tagList;
...
}
Tag
#Entity
#Table(name="tag")
public class Tag implements Serializable{
private static final long serialVersionUID = -7015657012681544984L;
#Id
#Column(name="id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#Column(name="name")
private String name;
#Column(name="description")
private String description;
#ManyToMany(mappedBy = "tagList")
private List<Post> postList;
public Integer getId() {
return id;
}
...
}
Tag Repo
public interface TagRepo extends CrudRepository<Tag, Integer>{
}
service implementation
#Service
public class TagServiceImpl implements TagService{
#Autowired
private TagRepo tagRepo;
#Override
public void addTag(Tag tag) {
tagRepo.save(tag);
}
#Override
public Tag getTag(Integer id) {
Tag tag = tagRepo.findOne(id);
return tag;
}
#Override
public List<Tag> findAllTags() {
return CollectionUtil.toArrayList(tagRepo.findAll());
}
}
sample test (Updated)
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = TestContextConfiguration.class)
#Transactional
public abstract class ServiceTest {
}
public class TagServiceTest extends ServiceTest{
#Autowired
private TagService tagService;
#Autowired
private TagRepo tagRepo;
#Test
#Transactional
public void addTag() throws Exception {
Tag tag = new Tag();
tag.setName("new tag");
tag.setDescription("this is a new tag");
tagService.addTag(tag);
Tag tagCreated = tagRepo.findOne(tag.getId());
assertNotNull(tagCreated);
assertEquals(tagCreated.getName(), tag.getName());
}
#Test
public void getTag() throws Exception {
Tag tag = tagService.getTag(1); // tag "java" has an ID of "1"
assertNotNull(tag);
assertEquals(tag.getName(), "java");
assertEquals(143,tag.getPostList().size()); // 143 posts under tag "java"
}
}
Question
The sample test case passes. It means that the postList in fetched Tag is also eagerly fetched and filled.
Is Spring data repository's methods eagerly fetching by default?
If yes, what is the best way to change this to lazy fetching?

Resources