I'm creating an update API that updates the profile of the super admin, I mapped the member table to a DTO, on the member table password is set to not null and I did not include the password field on the dto because there's a provision for that be, when I tested the API on postman it returned on the console
DataIntegrityViolationException
SQL Error: 1048, SQLState: 23000
Column 'password' cannot be null
Here is my code
Dto
#Getter
#Setter
public class UpdateProfileDto {
#NotNull(message = "{member.firstName.notNull}")
#JsonProperty("first_name")
private String firstName;
#NotNull(message = "{member.lastName.notNull}")
#JsonProperty("last_name")
private String lastName;
#JsonProperty("nationality")
private Long nationality;
#JsonProperty("country_of_residence")
private Long countryOfResidence;
#JsonProperty("date_of_birth")
#DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
#JsonFormat(pattern = "dd-MM-yyyy")
#Past(message = "{customer.dateOfBirth.past}")
private Date dateOfBirth;
#JsonProperty("current_job_title")
private String currentJobTitle;
#NotNull(message = "{member.emailAddress.notNull}")
#JsonProperty("email_address")
private String emailAddress;
#JsonProperty("username")
private String username;
#NotNull(message = "{member.phoneNumber.notNull}")
#PhoneNumber
#JsonProperty("phone_number")
private String phoneNumber;
#Size(max = 300, message = "{member.city.size}")
#JsonProperty("city")
private String city;
#Size(max = 300, message = "{member.state.size}")
#JsonProperty("state")
private String state;
}
ServiceImpl
#Override
#Transactional
public Member updateProfile(UpdateProfileDto body) {
Member superAdmin = repository.getOne(id);
if (superAdmin == null) {
throw new MemberNotFoundException(id);
}
Optional<Role> existingRole = roleJpaRepository.findByCode(RoleType.SUPER_ADMINISTRATOR.getValue());
if (existingRole.isEmpty()) {
throw new RoleNotFoundException(RoleType.SUPER_ADMINISTRATOR.getValue());
}
Member existing;
existing = mapper.map(body, Member.class);
existing.setPassword(superAdmin.getPassword());
existing.getRoles().add(existingRole.get());
existing.setNationality(countryRepository.getOne(body.getNationality()));
existing.setCountryOfResidence(countryRepository.getOne(body.getCountryOfResidence()));
return adminJpaRepository.save(existing);
}
Controller
#RestController
#RequestMapping(
value = "super-admin",
produces = { MediaType.APPLICATION_JSON_VALUE }
)
public class SuperAdminController {
private final SuperAdminService service;
public SuperAdminController(SuperAdminService service) {
this.service = service;
}
#PutMapping("/update")
public Member updateProfile(#Valid #RequestBody UpdateProfileDto body){
Member superAdmin = service.updateProfile(body);
return superAdmin;
}
}
The password bug has been fixed(changes reflected in serviceImpl), but when I run the code it returned Duplicate entry 'ijava#gmail.com-111803918380' for key 'member.email_address_phone_number_uq' email, and the phone number is set as a unique constraint in the member table, how can I bypass this?
You have few options, depending on your exact use case.
Extract existing password, using unique property in UpdateProfileDto, email looks like it can do the job.
Pseudocode:
Member existing = repository.findByEmail;
Member superAdmin = mapper.map(body, Member.class);
superAdmin.setPassword(existing.getPassword());
Set a dummy value for password, to be updated later on.
superAdmin.setPassword("dummy-password");
Make the column nullable in database.
Related
I want to save user in database, but i have an error about saving date:
Error accessing field [private java.util.Date ru.sfedu.diplomabackend.model.User.created] by reflection for persistent property [ru.sfedu.diplomabackend.model.User#created] : User(id=null, email=user#gmail.com, password=$2a$12$H3Wm1XGRPFse5AP0ZnzAs.SPiGMBp35mRgqI5WLwu1Zp/1RVRSnwC, firstName=Da, lastName=Mi, created=Fri Jun 04 21:51:39 MSK 2021, goalSet=[], diaryDays=[])
Caused by: java.lang.IllegalArgumentException: Can not set java.util.Date field ru.sfedu.diplomabackend.model.User.created to ru.sfedu.diplomabackend.model.User
User class:
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String email;
private String password;
private String firstName;
private String lastName;
private Date created;
UserPostRequestDto class:
public class UserPostRequestDto {
private String email;
private String password;
private String firstName;
private String lastName;
private Date created;
public UserPostRequestDto(User user) {
email = user.getEmail();
password = user.getPassword();
firstName = user.getFirstName();
lastName = user.getLastName();
}
public User toUser() {
User user = new User();
user.setEmail(email);
user.setPassword(password);
user.setFirstName(firstName);
user.setLastName(lastName);
user.setCreated(new Date());
return user;
}
rest controller:
public ResponseEntity<?> createUser(#RequestBody UserPostRequestDto userPostRequestDto) {
var user = userPostRequestDto.toUser();
//user.setCreated(new Date());
user.setPassword(passwordEncoder.encode(user.getPassword()));
return userDao.addUser(user)
? ResponseEntity.ok(user)
: new ResponseEntity<>("Invalid user", HttpStatus.BAD_REQUEST);
}
Your error clearly says that you are trying to assign a ru.sfedu.diplomabackend.model.User object into the ru.sfedu.diplomabackend.model.User.created field that holds a java.util.Date object. Square peg, round hole.
Caused by: java.lang.IllegalArgumentException: Can not set java.util.Date field ru.sfedu.diplomabackend.model.User.created to ru.sfedu.diplomabackend.model.User
You must have some offending code not shown to us here.
P.S. As commented, you should never use the terrible Date class. Replaced years ago by java.time.Instant.
I'm trying to add a custom constructor to a model generated by swagger, I was wondering if its possible for the model generation to be like below
example swagger model
#Schema(description = "Base Profile")
#javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaClientCodegen", date = "2020-10-08T18:15:35.865361-04:00[America/Vancouver]")
public class Account {
#SerializedName("id")
private Integer id = null;
#SerializedName("username")
private String username = null;
#SerializedName("lastModified")
private LocalDate lastModified = null;
#SerializedName("email")
private String email = null;
//getter setter
}
I need a constructor that does not contain the username and email
public Account(String username, String email)
Thanks
I have written the following code snippet to fetch records of certain zip files from zips table using hibernate as the JPA provider.
public List<ZipEntity> getZipEntityFromZipName(String zipName, String version, String createdBy,
String type) throws FileException {
int numAttempts = 0;
do {
numAttempts++;
EntityManager entityManager = getNewEntityManager();
try {
TypedQuery<ZipEntity> query = entityManager
.createNamedQuery(Constants.Database.Queries.GET_FROM_ZIP_NAME, ZipEntity.class)
.setParameter("zipName", zipName)
.setParameter("version", version)
.setParameter("createdBy", createdBy)
.setParameter("type", type);
return query.getResultList();
} catch (PersistenceException e) {
validatePersistenceException(e);
} finally {
closeEntityManager(entityManager);
}
} while (numAttempts <= maxRetries);
throw new FileException("Database connection failed.");
Here are the relevant entity classes
#NamedNativeQueries({
#NamedNativeQuery(
name = Constants.Database.Queries.GET_FROM_ZIP_NAME,
query = Constants.Database.Queries.GET_FROM_ZIP_NAME_QUERY,
resultClass = ZipEntity.class
)
})
#Entity
#Table(name = "zips")
public class ZipEntity {
#EmbeddedId
private ZipKey ZipKey;
public ZipEntity() {
}
public ZipEntity(String zipName, String version, String createdBy, String file, String type,
String extension) {
this.ZipKey = new ZipKey(zipName, version, createdBy, file, type, extension);
}
}
#Embeddable
public class ZipKey implements Serializable {
static final long serialVersionUID = 1L;
#Column(name = "zip_name")
private String zipName;
#Column(name = "version")
private String version;
#Column(name = "created_by")
private String createdBy;
#Column(name = "filepath")
private String file;
#Column(name = "type")
private String type;
#Column(name = "extension")
private String extension;
// Getter, setters and Constructor
}
And the query in Constant class is as follows,
public static final String GET_FROM_ZIP_NAME = "getFile";
public static final String GET_FROM_ZIP_NAME_QUERY = "SELECT * FROM zips WHERE zip_name = " +
":zipName AND version = :version AND created_by = :createdBy AND type = :type";
Event though setMaxResults() is not defined for the above query the results obtained from the above code snippet are limited to 25 record, although the same query executed at DB results in 35 records. What I am doing wrong in here ?
Please debug your solution and check values of "zipName","version","createdBy" and also "type" parameters to verify that they are the expected values by you. This query has for conditions combined by AND logic which affects to your results. To get 35 records, your parameters should make your conditions true for all 35 records.
You can limit the records as below in NamedNativeQuery which provides you 35 records at a time.
#NamedNativeQuery(
name = Constants.Database.Queries.GET_FROM_ZIP_NAME,
query = Constants.Database.Queries.GET_FROM_ZIP_NAME_QUERY,
fetchSize = 35,
resultClass = ZipEntity.class
)
I have use case where i need to map or fill data for particular fields
for example : I Have a user Model which i need to convert to UserDTO with only
particular fields like username and accountId.
MODEL :
public class UserCore{
private String accountId;
private String username;
private String workEmail;
private String firstName;
private String password;
private String hashedPassword;
}
UserDTO :
public class UserCoreDTO{
private String accountId;
private String username;
private String workEmail;
private String firstName;
private String password;
private String hashedPassword;
}
is there any way in map-struct so that i can map only particular fields from source to destination
for example :
UserMapper mapper = Mappers.getMapper( UserMapper.class );
mapper.map(fieldsToFetch,source,destination);
Here's an example form the docs:
#Mapper
public interface FishTankMapper {
#Mappings({
#Mapping(target = "fish.kind", source = "fish.type"),
#Mapping(target = "fish.name", ignore = true),
#Mapping(target = "ornament", source = "interior.ornament"),
#Mapping(target = "material.materialType", source = "material"),
#Mapping(target = "quality.report.organisation.name", source = "quality.report.organisationName")
})
FishTankDto map( FishTank source );
}
ignore = true will probably work for all fields, not just nested fields as in the example.
I am using Spring-data-mongodb and i can persist an object on a list, but when i try to add another, it doesn't work, the application doesn't throw an exception.
this is my Json:
[
{
idUser: "4a9f10d9-e19f-42af-ba00-891a567cc41f",
login: "peter",
password: "mypassword",
email: "peter#eeee.com",
patients:
[
{
idPatient: "d31e8052-36d3-4285-9f97-454f3437812d",
name: "ada",
birthday: 1363474800000,
idUser: "4a9f10d9-e19f-42af-ba00-891a567cc41f",
region:
{
idRegion: "d8acfa45-486e-49e0-b4e6-edde6743cf30",
name: "Madrid"
},
personalCalendars: null
},
null
]
}
]
As you can see, my first Patient element is correctly, and the second was insert as null.
I leave my code:
User.java
#Document(collection = "users")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private String id;
#Indexed
private UUID idUser;
#Indexed(unique = true)
private String login;
private String password;
#Indexed(unique = true)
private String email;
#DBRef
private List<Patient> patients;
#PersistenceConstructor
public User(UUID idUser, String login, String password, String email, List<Patient> patients){
this.idUser = idUser;
this.login = login;
this.password = password;
this.email = email;
this.patients = patients;
}
Patient.java
#Document(collection = "patients")
public class Patient implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private String id;
#Indexed
private UUID idPatient;
private String name;
private Date birthday;
private UUID idUser;
private Region region;
#Transient
private List<PersonalCalendar> personalCalendars;
#PersistenceConstructor
public Patient(UUID idPatient, String name, Date birthday,UUID idUser, Region region){
this.idPatient = idPatient;
this.name = name;
this.birthday = birthday;
this.idUser = idUser;
this.region = region;
}
and the DAO whereI do the insert.
#Override
public Patient createPatient(User user, Patient patient) {
this.mongoOps.save(patient , "patients");
this.mongoOps.save(user , "users");
return this.getPatientById(patient.getIdPatient());
}
The console returns this, but no persists the patient:
15:16:16.718 [tomcat-http--6] DEBUG o.s.data.mongodb.core.MongoTemplate - Saving DBObject containing fields: [_class, _id, idPatient, name, birthday, idUser, region]
15:16:16.723 [tomcat-http--6] DEBUG o.s.data.mongodb.core.MongoDbUtils - Getting Mongo Database name=[application]
15:16:16.747 [tomcat-http--6] DEBUG org.mongodb.driver.protocol.insert - Inserting 1 documents into namespace application.patients on connection [connectionId{localValue:2, serverValue:119}] to server 127.0.0.1:27017
15:16:16.761 [tomcat-http--6] DEBUG org.mongodb.driver.protocol.insert - Insert completed
I need help.
Thanks a lot
First, if you use Spring Data with MongoDB, use it properly:
#Repository
public interface UserRepository extends MongoRepository<User, String> {
}
Now just inject UserRepository via #Autowired annotation:
#Autowired
private UserRepository userRepository;
User user = new User();
Patient patient = new Patient();
user.addPatient(patient);
// Just call save from userRepository to save your User with Patient.
// save method will return instance of saved user (together with instance of
// patient)
User user = userRepository.save(user);
Note that save method can also be used for updating of existing User. If User is new (not having generated id) it will be inserted. If user exists (has generated id) it will be just updated.
Presuming that User class has a addPatient method that looks like this:
public void addPatient(Patient patient) {
this.patients.add(patient);
}
Also, make sure that your list is initialized: List<Patient> patients = new ArrayList<>();