How do I reuse multiple DTOs (spring boot) - java

I am a student who wants to implement api server using spring.
Currently, I use request and response to per api. (If api exists for signin, I have created AccountSignInDto.Request, AccountSignInResponse.) but, I felt that there were more and more duplicate codes.
I wonder how I can reuse multiple dto to reduce duplicate code.
The details are as follows.
AccountCreateDto.java
AccountFindIdByEmailDto.java
AccountFindPasswordDto.java
AccountReadDto.java
AccountSignInDto.java
AccountUpdateDto.java
QuestionReadDto.java
package com.se.apiserver.v1.account.application.dto;
import com.se.apiserver.v1.account.domain.entity.AccountType;
import javax.validation.constraints.Email;
import javax.validation.constraints.Size;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.*;
public class AccountCreateDto {
#Data
#NoArgsConstructor
#AllArgsConstructor
#ApiModel("signIn request")
#Builder
static public class Request {
#ApiModelProperty(example = "account", notes = "id")
#Size(min = 4, max = 20)
private String id;
#ApiModelProperty(example = "password", notes = "password")
#Size(min = 8, max = 20)
private String password;
#ApiModelProperty(example = "name", notes = "name")
#Size(min = 2, max = 20)
private String name;
#ApiModelProperty(example = "nickname", notes = "nick-name")
#Size(min = 2, max = 20)
private String nickname;
#ApiModelProperty(example = "11110000", notes = "stu-num")
#Size(min = 8, max = 20)
private String studentId;
#ApiModelProperty(example = "STUDENT", notes = "account type")
private AccountType type;
#ApiModelProperty(example = "01012345678", notes = "phone-number, 00011112222")
#Size(min = 10, max = 20)
private String phoneNumber;
#ApiModelProperty(example = "abc#def.com", notes = "email")
#Email
private String email;
#ApiModelProperty(example = "1", notes = "question number")
private Long questionId;
#ApiModelProperty(example = "region", notes = "answer")
#Size(min = 2, max = 100)
private String answer;
}
#Data
#AllArgsConstructor
#ApiModel("signIn response")
static public class Response {
#ApiModelProperty(example = "1", notes = "account pk")
private Long id;
}
}
I'm sorry for my poor English.
Thanks in advance!

Try declare Request as a abstract class, and all other dtos extend Request. Like code shows below:
public abstract class Request {
#ApiModelProperty(example = "account", notes = "id")
#Size(min = 4, max = 20)
private String id;
#ApiModelProperty(example = "password", notes = "password")
#Size(min = 8, max = 20)
private String password;
...
}
public class AccountCreateDto extends Request {
}
public class AccountUpdateDto extends Request {
}
This example ignore the influence of lombok.

Related

I am Upgrading Spring Application from java 8 to Java 11

I am upgrading a project from Java-8 to Java-11 which is using eclipselink 2.7.0 and while running application i am getting below mentioned error.
Exception Description: Problem compiling [ select org from Organization org ]. The abstract schema type '' is unknown.
Here is my Organization class
#Entity(name="Organization")
#NamedQuery(name="getOrganizationByTenant",query="select o from Organization o where o.organizationName=:orgName and o.tenantId=:tenantId")
#Table(name = "Organization", schema = "xyz")
public class Organization {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long organizationId;
#Size(min = 1, max = 300)
#SpecialCharValidator
private String organizationName;
#Size(min = 0, max = 4000)
#SpecialCharValidator
private String organizationFullName;
#Size(min = 0, max = 4000)
#SpecialCharValidator
private String remarks;
#NotNull
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="organizationType")
private Code organizationType;
#NotNull
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="organizationSubType")
private Code organizationSubType;
private Long parentOrganizationId;
#Size(min = 0, max = 1000)
private String organizationURL;
#NotNull private Long tenantId;
private Integer createdBy;
private Date createdOn;
private Integer updatedBy;
private Date updatedOn;
private boolean isDeleted;
private Boolean isShared;
}
```
Here is my function code that is fetching data :
return filters.getList(em, Organization.class," select org from Organization org ", options,SORT_COLUMNS);

How to determine violated entity during batch saving in spring data

I have next problem
public void batchSave(List<Entity> entities) {
repositoryJpa.save(entities);
}
If entities list contains already persisted entity i got DataIntegrityViolationException.
Is there way how to know which entity violated persisting?
Researching spring data source code and DataIntegrityViolationException i could find any place where wrong entity can be stored.
UPD
public class Entity {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "GENERATOR")
#Column(name = "ID", unique = true, nullable = false)
public Long getId() {
return id;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "NTRY_TABS_TABH_ID", nullable = false)
public OtherEntity getOtherEntity() {
return otherEntity;
}
#Column(name = "SORT_KEY", nullable = false)
public String getSortKey() {
return sortKey;
}
#Enumerated(EnumType.STRING)
#Column(name = "TYPE", nullable = false)
public OperationType getOperationType() {
return operationType;
}
#OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "activeEntryEntity")
public SortKeyEntity getSortKeyEntity() {
return sortKeyEntity;
}
#Version
#Column(name = "VERSION", nullable = false, insertable = false)
public Long getVersion() {
return version;
}
}
Use javax validation , and you will be able to do something like this:
import javax.validation.constraints.AssertTrue;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import javax.validation.constraints.Email;
public class User {
#NotNull(message = "Name cannot be null")
private String name;
#AssertTrue
private boolean working;
#Size(min = 10, max = 200, message
= "About Me must be between 10 and 200 characters")
private String aboutMe;
#Min(value = 18, message = "Age should not be less than 18")
#Max(value = 150, message = "Age should not be greater than 150")
private int age;
#Email(message = "Email should be valid")
private String email;
// standard setters and getters
}
And then you can validate this like :
Set<ConstraintViolation<User>> violations = validator.validate(user);
Take a look at this:
https://www.baeldung.com/javax-validation

Need to understand the java 8 behavior for creating objects and updating reference

I am failed to understand the following problem.
I have one DTO file as follows.ClientRegistrationDTO.java
public class ClientRegistrationDTO {
private Long clientId;
private String clientCode;
private String clientName;
private String url;
private String logo;
private Long languageId;
private String timeZone;
//contact details
private Set<Address> addresses;
private Set<ContactDetails> contactDetails;
public ClientRegistrationDTO(){}
public ClientRegistrationDTO(Set<Address> addressSet,Set<ContactDetails> contactDetails){
this.addresses = addressSet;
this.contactDetails = contactDetails;
}
}
So I have a method registerClient which accept this DTO file to operate over the save client as well as a user. As follows
public ClientRagistrationResponce registerClient(
ClientRegistrationDTO clientRegistrationDTO) {
ClientRagistrationResponce clientInfo = null;
if (clientRegistrationDTO != null) {
clientInfo = new ClientRagistrationResponce(); // creating responce variable
//setting another ragisterDTO file with default value
ClientRegistrationDTO clientRegistrationDTO2 = new
Line no 9 ClientRegistrationDTO(clientRegistrationDTO.getAddresses(),clientRegistrationDTO.getContactDetails());
// creating addresses Set from clientRegistrationDTO to insert
// against user.
Line no 15 Set<Address> clientAddress = new HashSet<>(clientRegistrationDTO.getAddresses());
Line no 16 Set<ContactDetails> clientContactDetails = new HashSet<>(clientRegistrationDTO.getContactDetails());
Line no 18 Set<Address> userAddress = new HashSet<>(clientRegistrationDTO2.getAddresses());
Line no 19 Set<ContactDetails> userContactDetails = new HashSet<>(clientRegistrationDTO2.getContactDetails());
// Save the client
Client client = saveClient(clientRegistrationDTO);
// Save the contact info
ContactInfo clientContactInfo = saveContactInfo(
client.getClientId(), RDHCoreConstants.CONTACT_TYPE_CLIENT);
// Save client addresses
Line no 29 Set<Address> clientAddressSet = saveClientAddresses(
clientContactInfo.getContactInfoId(), clientAddress);
// Save Client contact details
Line no 33 Set<ContactDetails> clientContactDetailsSet = saveClientContactDetails(
clientContactInfo.getContactInfoId(), clientContactDetails);
// save user
User user = saveUser(clientRegistrationDTO);
// Save User contact info
ContactInfo userContactInfo = saveContactInfo(user.getUserId(),
RDHCoreConstants.CONTACT_TYPE_USER);
// Save User addresses
saveUserAddresses(userContactInfo.getContactInfoId(), userAddress);
// Save User contact details
saveUserContactDetails(userContactInfo.getContactInfoId(),
userContactDetails);
saveClientUser(client.getClientId(), user.getUserId());
// setting the return DTO
clientInfo.setClientId(client.getClientId());
clientInfo.setAddresses(clientAddressSet);
clientInfo.setContactDetails(clientContactDetailsSet);
}
return clientInfo;
}
Firstly I created another Object with a different name of the same type to set address & contact details are safe with updation. #Line no 9.
So now whenever the client Address & ContactDetails saved # line no 29 & 33. it updates the address in ClientRagistrationDTO.java file and all the reference which I passed to create another set of Address and contactDetails. # Line no 9.
I'm confused, why it's updating all its reference, even though I never updated the same.
Please guide me step by steps.
Note: I used Spring Data JPA with following relation ContactInfo table has a contactInfoId as primary_key. whihc is foreign_key in Address as well as ContactDetails.
Follwing is the entity of the tables.ContactInfo
#Entity
#Table(name = "contactinfo", schema = "test")
public #Data class ContactInfo {
#Id
#Column(name = "CONTACTINFOID")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long contactInfoId;
#Column(name="CLIENTUSERID")
private Long clientUserId;
#Column(name = "CONTACTTYPE")
#NotNull
#Size(min = 1, max = 10)
private String contactType;
}
Follwing is the Address
#Entity
#Table(name = "address", schema = "test")
public class Address {
#Id
#Column(name = "ADDRESSID")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long addressId;
#Column(name = "ADDRESS1")
#Size(min = 1, max = 50)
private String address1;
#Column(name = "ADDRESS2")
#Size(min = 1, max = 50)
private String address2;
#Column(name = "CITY")
#Size(min = 1, max = 50)
private String city;
#Column(name = "ZIP")
#Size(min = 1, max = 15)
private String zip;
#Column(name = "STATE")
#Size(min = 1, max = 50)
private String state;
#Column(name = "COUNTRY")
#Size(min = 1, max = 50)
private String country;
#Column(name = "ISPRIMARY")
#NotNull
#Size(min = 1, max = 1)
private String isPrimary;
#Column(name = "CONTACTINFOID")
private Long contactInfoId;
}
Follwing is the ContactDetails.
#Entity
#Table(name = "contactdetails", schema = "test")
public class ContactDetails {
#Id
#Column(name = "CONTACTDETAILSID")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long contactId;
#Column(name = "CONTACTTYPE")
#NotNull
#Size(min = 1, max = 20)
private String contactType;
#Column(name = "CONTACTDETAIL")
#NotNull
#Size(min = 1, max = 20)
private String contactDetail;
#Column(name = "EXTENSION")
private String extension;
#Column(name = "ISPRIMARY")
#NotNull
#Size(min = 1, max = 1)
private String isPrimary;
#Column(name = "CONTACTINFOID")
private Long contactInfoId;
}
Hope enough information is provided to solve this issue.

Spring boot REST api ConstraintViolationException on password field

I'm having a weird issue on my Spring backend, where I am sending a post request with a domain User object from my angular2 frontend that is being recieved by a REST API endpoint and translating it into the Spring User model object. The issue is that the password field from the JSON request seems to not be translating to the password field on the backend. All the other fields (username, name, email, etc.) are coming through fine, but the password is null.
Request payload as seen from network tab in chrome
email : "asdf#asdf.com" firstName : "asdfasdjk" lastName : "asdfs"
login : "adfsjk" password : "fasdfasdfasdsd"
Response seen from network tab
error: "Internal Server Error" exception: "javax.validation.ConstraintViolationException" message: "Validation failed for classes [domain.User] during persist time for groups [javax.validation.groups.Default, ]
List of constraint violations:[ ConstraintViolationImpl{interpolatedMessage='may not be null', propertyPath=password, rootBeanClass=class domain.User, messageTemplate='{javax.validation.constraints.NotNull.message}'}]"
path:"/api/users" status: 500
Spring Rest method:
#RequestMapping(value = "/users",
method = RequestMethod.POST,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
public ResponseEntity<User> createUser(#RequestBody User user) throws URISyntaxException {
User result = userRepository.save(user);
return ResponseEntity.created(new URI("/api/users/" + result.getId()))
.headers(HeaderUtil.createEntityCreationAlert("user", result.getId().toString()))
.body(result);
}
Spring domain object
#Entity
#Table(name = "user")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class User extends AbstractAuditingEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#NotNull
#Size(max = 100)
#Column(length = 100, unique = true)
private String login;
#JsonIgnore
#NotNull
#Size(min = 5, max = 60)
#Column(length = 60)
private String password;
#Size(max = 50)
#Column(name = "first_name", length = 50)
private String firstName;
#Size(max = 50)
#Column(name = "last_name", length = 50)
private String lastName;
#Email
#Size(max = 100)
#Column(length = 100, unique = true)
private String email;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "user_tag",
joinColumns = #JoinColumn(name = "users_id", referencedColumnName = "ID"),
inverseJoinColumns = #JoinColumn(name = "tags_id", referencedColumnName = "ID"))
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private List<Tag> tags = new ArrayList<>();
}
Angular2 domain object
export class User {
id: number;
login: string;
password: string;
firstName: string;
lastName: string;
email: string;
}
The problem is with using #JsonIgnore on the password field, this makes the filed ignorable when reading from or writing to JSON message, one solution is to use #JsonProperty with access = Access.WRITE_ONLY as follows
public class User extends AbstractAuditingEntity implements Serializable {
// Other fileds
#NotNull
#JsonProperty(access = Access.WRITE_ONLY)
#Size(min = 5, max = 60)
#Column(length = 60)
private String password;
}
Another solution is to implement a getter and setter for the password field, and annotate the getter with #JsonIgnore and the setter with #JsonProperty, as follows
public class User extends AbstractAuditingEntity implements Serializable {
// Other fileds
#NotNull
#Size(min = 5, max = 60)
#Column(length = 60)
private String password;
#JsonIgnore
public String getPassword() {
return password;
}
#JsonProperty
public void setPassword(String password) {
this.password = password;
}
}

Spring Architecture circular references and stackoverflows

I have a question about how to avoid circular references and stackoverflows.
I have a User object and another News Object (with a User variable). I need a Comments object (that already has a News variable), but I also need that it has a reference to the User that has created the Comment.
If I create a User variable inside my Comment object I will have circular references and stackoverflows, so I think that I should only incluide a variable like userid in my Comment object.
So it could be that I'm right in my thinking or that I'm doing something wrong to get the stackoverflow errors. What would you do and why? If you can help, that will be great. Thanks.
This is the User...
#Entity
#Table(name = "users")
#PasswordMatch(message = "{register.repeatpassword.mismatch}")
public class SiteUser {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
#Column(name = "email", unique = true)
#Email(message = "{register.email.invalid}")
#NotBlank(message = "{register.email.invalid}")
private String email;
#Transient
#Size(min = 5, max = 15, message = "{register.password.size}")
private String plainPassword;
#Column(name = "password", length = 60)
private String password;
#Column(name = "enabled")
private Boolean enabled = false;
#NotNull
#Column(name = "firstname", length = 20)
#Size(min = 2, max = 20, message = "{register.firstname.size}")
private String firstname;
#NotNull
#Column(name = "surname", length = 25)
#Size(min = 2, max = 25, message = "{register.surname.size}")
private String surname;
#Transient
private String repeatPassword;
#Column(name = "role", length = 20)
private String role;
public SiteUser() {
}
Here comes the StatusUpdate(you can call it piece of news or article). It has a site user that is the one who has created that article.
#Entity
#Table(name = "status_update")
public class StatusUpdate {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Size(min=5, max=255, message="{addstatus.title.size}")
#Column(name = "title")
private String title;
#Size(min=5, max=5000, message="{addstatus.text.size}")
#Column(name = "text")
private String text;
#Column(name = "added")
#Temporal(TemporalType.TIMESTAMP)
#DateTimeFormat(pattern="yyyy/MM/dd hh:mm:ss")
private Date added;
#OneToOne(targetEntity = SiteUser.class)
#JoinColumn(name="user_id")
private SiteUser siteUser;
#PrePersist
protected void onCreate() {
if (added == null) {
added = new Date();
}
}
public StatusUpdate() {
}
And the Comment which can be done by any registered user, right? As you will notice the Comment has no User object to avoid circular references. And that is the question. How can avoid circular references if Autowired a User
#Entity
#Table(name = "comments")
public class Comment {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne
#JoinColumn(name = "statusupdateid")
private StatusUpdate statusUpdate;
#Column(name = "commenttext")
private String commenttext;
#Column(name = "commentdate")
#Temporal(TemporalType.TIMESTAMP)
#DateTimeFormat(pattern = "yyyy/MM/dd hh:mm:ss")
private Date commentdate;
#Column(name = "userid")
private Long userid;
public Comment() {
}

Categories