Spring JPA: How to get the custom json response - java

I need to list all the permission available in the system, and on each permission i need to show to particular user which permission is active on him ...
here is table relations:
All Record from Table: authority_master(select * from authority_master)
All Record from Table: users_authority_relation (select * from users_authority_relation;)
All Record from Table: userdetails (select*from userdetails)
Expected JSON Output : if i want to know which and all permission active on each user(basically whose record exists in table "user_authority_relation" table ,(here i want to list all the permissions available in table "authority_master" and on that "isActive" json key is True only if that particular authority exists in table "user_authority_relation"
Basically i need to select userdetails table and join with users_authority_relation , this will give result only who has permission But it will not list all the avaialble permission. i am confused on this how to get like below expected json result

If you are allowed to make multiple database call, you can do this
Get list of Authority authList from database.
Get list of users
For each user do the step 4-5
loop authList and check if the current user's authority list contains the element. if yes set isActive true otherwise false.
Set the authList as currents users permission

As i am also in spring boot learning phase and i found your problem interesting so i attempted to solve your problem
Your entity beans might look like this
user_authority_relation bean
#Table(name="user_authority_relation")
#Data
public class UserAuthRelation implements Serializable {
#Id
#GeneratedValue
Long user_auth_id;
#ManyToOne
#JoinColumn(name="userid")
UserDetails user;
#JoinColumn(name="authorityid")
#OneToOne
AuthorityMaster authority;
}
UserDetailsBean.java
#Entity
#Table(name="userdetails")
#Data
public class UserDetails implements Serializable {
#Id
#GeneratedValue
Long userid;
String name;
#OneToMany(mappedBy="user")
List<UserAuthRelation> userAuths;
}
AuthorityMaster.java
#Entity
#Table(name="authority_master")
#Data
public class AuthorityMaster implements Serializable {
#Id
#GeneratedValue
Long authorityid;
String authority;
String description;
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
AuthorityMaster other = (AuthorityMaster) obj;
if (authorityid == null) {
if (other.authorityid != null)
return false;
} else if (!authorityid.equals(other.authorityid))
return false;
return true;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((authorityid == null) ? 0 : authorityid.hashCode());
return result;
}
}
To get desired response, we need to make some classes which can help to create custom response bean which may look like this
#Data
public class CustomResponseJson implements Serializable {
List<UserResponseJson> usersList;
}
#Data
public class UserResponseJson {
Long userId;
List<PermissionObject> permissions;
}
#Data
public class PermissionObject {
String authority;
Long authorityid;
Boolean isactive;
}
Rest Controller
#RestController
public class UsersController {
#Autowired
UserDetailRepository userRepo;
#Autowired
AuthorityRepository authRepo;
#GetMapping("/fetchUserPermissons")
#ResponseBody
public CustomResponseJson fetchUserPermission() {
//find all available users
List<UserDetails> users = userRepo.findAll();
//find all available authorities
List<AuthorityMaster> auths = authRepo.findAll();
//initilizing custom reponse bean
CustomResponseJson res =new CustomResponseJson();
if(users!=null && !users.isEmpty()){
//list of all users in json response
List<UserResponseJson> userJsonReponse = new ArrayList<UserResponseJson>();
for(UserDetails user : users){
UserResponseJson userjson = new UserResponseJson();
userjson.setUserId(user.getUserid());
//prepare list of all authority availed and not availed to user
List<PermissionObject> permissions = new ArrayList<PermissionObject>();
if(user.getUserAuths()!=null && user.getUserAuths().size()>0){
List<AuthorityMaster> tempList = new ArrayList<AuthorityMaster>();
for(UserAuthRelation rel : user.getUserAuths()){
tempList.add(rel.getAuthority());
PermissionObject permObj = new PermissionObject();
permObj.setAuthority(rel.getAuthority().getAuthority());
permObj.setAuthorityid(rel.getAuthority().getAuthorityid());
permObj.setIsactive(true);
permissions.add(permObj);
}
//to find authority which is not assigned to user
List<AuthorityMaster> remainedAuths = auths.stream()
.filter(e -> !tempList.contains(e))
.collect (Collectors.toList());
for(AuthorityMaster auth:remainedAuths){
PermissionObject permObj = new PermissionObject();
permObj.setAuthority(auth.getAuthority());
permObj.setAuthorityid(auth.getAuthorityid());
permObj.setIsactive(false);
permissions.add(permObj);
}
}
userjson.setPermissions(permissions);
userJsonReponse.add(userjson);
}
res.setUsersList(userJsonReponse);
}
return res;
}
}
OUTPUT

You should create one response DTO which can hold all data from different resources(databases, external services)
My Controller response is:
#Data
#AllArgsConstructor
#NoArgsConstructor
public class AxeleStatisticReportDTO implements Serializable {
private static final long serialVersionUID = 1L;
private List<EmailLogDTO> emailAndCount = new ArrayList<>();
private List<IpLogDTO> ipRequestsCount = new ArrayList<>();
}

Related

How to put check if record already exist - spring boot

I'm new in spring & try to enhance my skill by creating little projects. In my new app I'd like to put uniqueness check on accountNumber, unfortunately I did not get success. I'd like to apply isPresent() method but it doesn't exist when I call it. Grateful if I get help.
Following is my Service class where I apply logics, I also mention Rep. & Ent. classes for your reference. I apply unique condition in 3rd line where find ***if ..... ***.
I've found similar question but the solution in this stack doesn't match with the way I like to do, I'd like to use JPA not JPQL.
AccountService
#Autowired
private AccountRepository accountRepository;
#Transactional
public ResponseEntity<Object> addAccount(CurrentAccount currentAccount){
**if(currentAccount.getAccountNumber().is)**
accountRepository.save(currentAccount);
return ResponseEntity.ok("Account Accepted");
}
CurrentAccount
public class CurrentAccount {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
#Column(name = "account_number")
private String accountNumber;
#Column(name = "account_balance")
private Integer accountBalance;
AccountRepository
public interface AccountRepository extends JpaRepository<CurrentAccount, Long> {
Optional<CurrentAccount> findByAccountNumber(String accountNumber);
}
Simply use existsBy method of JPA, Something like this.
It returns true, if the CurrentAccount exists with the given account number.
boolean existsCurrentAccountByAccountNumber(String accountNo);
If you want to check with more than one parameter then do this.
boolean existsCurrentAccountByAccountNumberAndName(String accountNo, String name);
Service
#Transactional
public ResponseEntity<Object> addAccount(CurrentAccount currentAccount){
if(accountRepository.existsCurrentAccountByAccountNumberAndName(currentAccount.getAccountNumber(), currentAccount.getName())){
return new ResponseEntity<>(HttpStatus.BAD_REQUEST); // or anything you want to do if record is already exists.
}else{
accountRepository.save(currentAccount);
return ResponseEntity.ok("Account Accepted");
}
}
This is my method (Spring):
public boolean checkAccount (String email) {
try {
String SQL = "select * from Account where email=?";
Account account = jdbcTemplateObject.queryForObject(SQL, new Object[]{email}, new AccountMapper());
if (account != null) {
return true;
}
} catch (EmptyResultDataAccessException e) {
return false;
}
return false;
}

Spring + MySQL records being duplicated instead of updated

In my project I'm migrating data from SQLite db into MySQL db. The problem is that when I migrate multiple times, the already existing records are being duplicated, instead of being updated(in case there are any changes in SQLite, otherwise no action is expected).
I'm using JpaRepository.saveAll(), which internally invokes save() for each entity:
#Transactional
public <S extends T> S save(S entity) {
Assert.notNull(entity, "Entity must not be null.");
if (this.entityInformation.isNew(entity)) {
this.em.persist(entity);
return entity;
} else {
return this.em.merge(entity);
}
}
Then isNew() is invoked but I'm not sure how it compares records in the target db to the ones that are currently being migrated and if that's where the problem occurs at all.
Do you have any suggestions to solving my problem?
That's my entity:
#Entity
#Table(name = "movies")
public class Movie {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
-- properties
-- constructors/getters/setters/equals/hashcode
}
That's the service that migrates movies(SQLiteMovie is the entity extracted from SQLite, which is then mapped to (MySQL)Movie):
#Service
public class MovieMigrationServiceImpl implements MovieMigrationService {
private static final int MOVIE_TYPE = 1;
private final MovieMapper movieMapper;
private final MovieService movieService;
private final SQLiteMovieService sqliteMovieService;
public MovieMigrationServiceImpl(MovieMapper movieMapper, MovieService movieService,
SQLiteMovieService sqliteMovieService) {
this.movieMapper = movieMapper;
this.movieService = movieService;
this.sqliteMovieService = sqliteMovieService;
}
#Override
public String migrateMovies() {
Collection<SQLiteMovie> sqliteMovies = sqliteMovieService.getAllByMetadataType(MOVIE_TYPE);
Collection<Movie> movies = mapMovies(sqliteMovies);
movieService.saveMovies(movies);
return movies.size() + " movies migrated successfully!";
}
private Collection<Movie> mapMovies(Collection<SQLiteMovie> sqliteMovies) {
return sqliteMovies.stream()
.map(movieMapper::toMovie)
.collect(Collectors.toList());
}
}
And finally that's the structure of the table in MySQL:
Thanks in advance!

Spring boot API - How to ensure no concurrency issues

I'm still in the process of learning Java / spring and I think I'm getting better. Now at this point I'm able to build a rest api BUT I'm at a lost at how to ensure I've no concurrency issues . I've read many topics regarding making the API stateless or making my POJO's immutable but I'm sure if in my case below I need to. And if I did, I'm actually unsure how my code can function by making everything final in my POJO.
If someone could help me learn here I'd be VERY grateful. Thank you for your time
Below i have a POJO called User:
#Getter
#Setter
#Document(collection = "UserProfiles")
public class User {
#Id
#JsonIgnore
private String _id;
#JsonView({ProfileViews.Intro.class, ProfileViews.Full.class})
private String userId;
#JsonView({ProfileViews.Intro.class, ProfileViews.Full.class})
private String name;
#JsonView({ProfileViews.Intro.class, ProfileViews.Full.class})
private String displayName;
#DBRef
#JsonView({ProfileViews.Full.class})
private UserInterests personalInterests;
#DBRef
#JsonIgnore
private ProfileFollows profileFollowDetails;
}
#Getter
#Setter
#Document(collection = "ProfileFollows")
public class ProfileFollows {
#Id
//Id of The Mongo Document
private String id;
//The Id of the User Profile who owns the document
private String userId;
//A list containing the Ids of the Users who have followed the Profile belonging to userId
private List<String> profileFollowedByUserIds;
//A list containing the Ids of the Profiles the current user has followed
private List<String> profileFollowingByUserList;
}
And here is my Service layer where I create and update the user
#Service
public class UserService {
#Autowired
UserDal userDal;
public User createNewUserAccount(String userId, String userName) {
//check If userId already in DB
if (checkIfUserIdExits(userId)) {
throw new UserAlreadyExistsException("Cannot create User with Id { " + userId + " }, a user with this Id already " +
"exists");
}
//Create a Empty / Base New User Object
User newUser = new User();
UserInterests userInterests = new UserInterests();
userInterests.setUserId(userId);
userInterests.setPersonalInterestsExtras(null);
userInterests.setCreatedDate(Instant.now());
userInterests.setLastUpdatedAt(Instant.now());
userInterestsDAL.save(userInterests);
newUser.setPersonalInterests(userInterests);
ProfileFollows userProfileFollows = new ProfileFollows();
userProfileFollows.setUserId(userId);
userProfileFollows.setProfileFollowedByUserIds(new ArrayList<>());
userProfileFollows.setProfileFollowingByUserList(new ArrayList<>());
newUser.setProfileFollowDetails(profileFollowsDAL.save(userProfileFollows));
newUser.setUserId(userId);
newUser.setDisplayName(generateUserDisplayName(userName));
newUser.setCreatedDate(Instant.now());
newUser.setLastUpdatedAt(Instant.now());
//save the new User Profile to the DB
return userDal.save(newUser);
}
Here is my UserDAL:
public interface UserDal {
/**
* Method to check if a user exists with a given user Id
* #param Id -- Id of user to look up where id is a string
* #return
*/
Boolean existsById(String Id);
/**
* Method to save a user to the DB
* #param user -- User object to save to the DB
* #return
*/
User save(User user);
}
My User Repository / DALImpl:
#Repository
public class UserDALImpl implements UserDal {
private final MongoTemplate mongoTemplate;
#Autowired
public UserDALImpl(MongoTemplate mongoTemplate) {
this.mongoTemplate = mongoTemplate;
}
#Override
public User save(User user) {
return mongoTemplate.save(user);
}
And lastly my controller:
#RestController
#RequestMapping("/profile")
public class CreateProfileController {
#Autowired
public CreateProfileController() {
}
#Autowired
UserService userService;
#ApiOperation(value = "Allows for the creation of a user Profile")
#PostMapping("/create")
public User createUserProfile(#RequestParam(name = "userId") String userId,
#RequestParam(name = "displayName", required = true, defaultValue = "AnonymousDev") String displayName) {
if (userId.equals("")) throw new BadRequestException("UserId cannot be blank");
if (userService.checkIfUserIdExits(userId)) {
throw new UserAlreadyExistsException("Unable to create user with Id { " + userId + " }, the " +
"userId already exists");
}
return userService.createNewUserAccount(userId, displayName);
}
}

Java DTO Object search mechanism?

I have produced a DTO object from 2 microservices. Profile and ProfileCredit. I am able to successfully retrieve a populated DTO object with relevant data. However I am further curious is it possible to query or do conditional filter on the generated DTO object? and if so what is the approach to achieve just that?
For example using 'swagger' this is what gets returned
Is it possible to filter by profileCredit field which is present in the dto but the data is retrieved within separate microservice?
Any help, suggestions or references to any other posts or pages would be truly helpful.
Controller
#GetMapping(path="/profile/search/username/{username}", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ResponseEntity<Page<ProfileCreditDTO>> findProfileByUsername(#PathVariable String username, Pageable pageable) {
Page<ProfileCreditDTO> results= profileCreditService.findProfileBySelectedParameters(username,pageable);
if(results== null){
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
} else
return new ResponseEntity<>(results,HttpStatus.OK);
}
Query within profileCreditService
#Query("SELECT p from PROFILES p where lower(p.username) LIKE :username%")
Page<ProfileCreditDTO> findProfileBySelectedParameters(String username, Pageable pageable);
ProfileCreditServiceImpl
public ProfileCreditDTO findProfileCreditByProfileId(final Long profileId){
log.info("Start of findProfileCreditByProfileId method {}",profileId);
ProfileCreditDTO rc= new ProfileCreditDTO();
Profile profile=profileRepository.findOne(profileId);
if(profile == null){
return null; }
CreditDTO creditDto= profileCreditClient.findClientByProfileId(profile.getId());
if(creditDto == null){
return null; }
rc.setProfile(profile);
rc.setCredit(creditDto);
return rc;
}
private ProfileCreditDTO convertProfileToProfileCreditDTO(final Profile theProfile){
if(theProfile == null)
return null;
ProfileCreditDTO theDTO= new ProfileCreditDTO();
theDTO.setProfile(theProfile);
CreditDTO theCreditDto= profileCreditClient.findClientByProfileId(theProfile.getId());
if(theCreditDto != null )
theDTO.setCredit(theCreditDto);
return theDTO;
}
Profile Domain
#Entity(name = "PROFILES")
#Data #NoArgsConstructor #AllArgsConstructor
#ToString
public class Profile implements Serializable {
#Id
#GeneratedValue(strategy= GenerationType.AUTO)
private Long id;
#Size(min = 2, max = 20)
private String username;
private Integer profileType;
private Integer gender;
private Integer orientation;
private boolean online;
#JsonFormat(pattern="uuuu-MM-dd'T'HH:mm:ss.SSS")
private LocalDateTime created;
#JsonFormat(pattern="uuuu-MM-dd'T'HH:mm:ss.SSS")
private LocalDateTime lastEdited;
Profile Credit DTO
#Data
#AllArgsConstructor
#NoArgsConstructor
#ToString
public class ProfileCreditDTO {
//profile fields
private Long profileId;
#Size(min = 2, max = 50)
private String username;
private Integer gender;
private Integer profileType;
private Integer orientation;
private boolean online;
// Credit fields
private Long creditId;
#Column(unique = true)
private double profileCredit;
public void setProfile(final Profile profile) {
this.setProfileId(profile.getId());
this.setUsername(profile.getUsername());
this.setGender(profile.getGender());
this.setProfileType(profile.getProfileType());
this.setOrientation(profile.getOrientation());
this.setOnline(profile.isOnline());
}
public void setCredit(final CreditDTO credit){
this.setCreditId(credit.getId());
this.setProfileCredit(credit.getProfileCredit());
}
ProfileCreditClient (feign)
#Component
#FeignClient(name = "profileCreditService")
public interface ProfileCreditClient {
#GetMapping("/api/credit/profile/{profileId}")
CreditDTO findClientByProfileId(#PathVariable("profileId") Long clientId);
}
Profile Repository Query
#Query("SELECT p from PROFILES p where lower(p.username) LIKE :username%")
Page<Profile> findByAllParameters(#Param("username") String username, Pageable pageable);

Remote EJB and JPA #Version

A multi-tiered application that I am developing accesses its database through a Payara application server. Originally I was using webservices (jax-ws) to provide the access. That decision was prompted by the ease of creating the services by using the #WebService and #Stateless annotations on my entity facade classes.
Due to some limitations of webservices (things like equals and hashCode methods not being created in the webservice interface), I decided to try to use EJB's to accomplish the same functionality. Using the webservices I was able to successfully perform all CRUD functionality on all of the database entities. All of my entity classes extend an AbstractEntity class, which is annotated #MappedSuperClass.
#MappedSuperclass
public abstract class AbstractEntity {
#Column(name = "UUID")
#Basic
private String uuid;
#Version
#Access(AccessType.FIELD)
#Column(name = "Revision")
#Basic
private long revision;
public AbstractEntity() {
uuid = UUID.randomUUID().toString();
}
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
/**
* #return entity's database primary key if persisted
*/
public abstract Long getId();
public long getRevision() {
return revision;
}
public void setRevision(long revision) {
this.revision = revision;
}
/**
* #return true if this entity is persisted to database, false
otherwise.
*/
public boolean isPersisted() {
return getId() != null;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof AbstractEntity) {
return this.uuid.equals(((AbstractEntity) obj).uuid);
}
return false;
}
#Override
public int hashCode() {
return uuid.hashCode();
}
}
The client application correctly looks up the remote interfaces through JNDI, and I'm able to run my methods to query the data and return result lists exactly the same as I can using webservices. The problem, however, is in the version number and uuid that are returned with each entity instance. In all cases, the revision number that is returned is 0, and the revision and uuid don't match the revision and uuid stored in the database. I have verified that the result of my query on the server contains entities that have the correct version numbers, but when the entities get to the client, all of them are set to 0. Of course, if I make any changes to the entity on the client and then try to update the entity, I get an optimistic locking exception on the update method.
Does this have something to do with the entities being detached from the database? The update method is:
#Override
public ShiplistItem updateShipList(ShiplistItem shipitem) {
LOGGER.log(Level.INFO, "Entering updateShipList.");
LOGGER.log(Level.INFO, "shipitem: {0}", shipitem.toString());
if (shipitem.isPersisted()) {
return em.merge(shipitem);
} else {
em.persist(shipitem);
return shipitem;
}
}
I don't understand why the webservice would return the entities correctly, but the ejb seems to neglect the stored values for revision and uuid.
All help is appreciated!!
EDIT - Entity class snippet
public class ShiplistItem extends AbstractEntity implements
Serializable, Comparable<ShiplistItem> {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(unique = true, nullable = false)
private Long id;
....
EDIT #2
#Override
public List<ShiplistItem> listShipListByDate(String date) {
Query query = em.createQuery("SELECT s from ShiplistItem s
where s.shipdate = :shipdate", ShiplistItem.class)
.setParameter("shipdate", date);
LOGGER.log(Level.INFO, "SQL: {0}.", query.toString());
List<ShiplistItem> result = new ArrayList<>();
try {
result = (List<ShiplistItem>) query.getResultList();
} catch (Exception ex) {
LOGGER.log(Level.INFO, "No shipping list for date {0}", date);
}
for (ShiplistItem shiplistItem : result) {
LOGGER.log(Level.INFO, "revision: {0}",shiplistItem.getRevision());
}
LOGGER.log(Level.INFO, "shiplist size: {0}", result.size());
return result;
}

Categories

Resources