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
Related
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.
I tried to work with immutable objects in MongoDB and Lombok. I found a solution to my problem but it needs to write additional code from docs but I need to used Bson annotations and create a constructor where describes fields via annotations. But if I user #AllArgsConstructor catch exception: "Cannot find a public constructor for 'User'" because I can't use default constructor with final fields. I think i can customize CodecRegistry correctly and the example will work correctly but I couldn't find solution for it in docs and google and Stackoverflow.
Is there a way to solve this problem?
#Data
#Builder(builderClassName = "Builder")
#Value
#BsonDiscriminator
public class User {
private final ObjectId id;
private final String name;
private final String pass;
private final String login;
private final Role role;
#BsonCreator
public User(#BsonProperty("id") final ObjectId id,
#BsonProperty("name") final String name,
#BsonProperty("pass") final String pass,
#BsonProperty("login") final String login,
#BsonProperty("role") final Role role) {
this.id = id;
this.name = name;
this.pass = pass;
this.login = login;
this.role = role;
}
#AllArgsConstructor
public enum Role {
USER("USER"),
ADMIN("ADMIN"),
GUEST("GUEST");
#Getter
private String value;
}
public static class Builder {
}
}
Example for MongoDB where I create, save and then update users:
public class ExampleMongoDB {
public static void main(String[] args) {
final MongoClient mongoClient = MongoClients.create();
final MongoDatabase database = mongoClient.getDatabase("db");
database.drop();
final CodecRegistry pojoCodecRegistry = fromRegistries(MongoClientSettings.getDefaultCodecRegistry(),
fromProviders(PojoCodecProvider.builder().automatic(true).build()));
final MongoCollection<User> users = database.getCollection("users", User.class).withCodecRegistry(pojoCodecRegistry);
users.insertMany(new ExampleMongoDB().getRandomUsers());
System.out.println("Before updating:");
users.find(new Document("role", "ADMIN")).iterator().forEachRemaining(
System.out::println
);
System.out.println("After updating:");
users.updateMany(eq("role", "ADMIN"), set("role", "GUEST"));
users.find(new Document("role", "GUEST")).iterator().forEachRemaining(
System.out::println
);
}
public List<User> getRandomUsers() {
final ArrayList<User> users = new ArrayList<>();
for (int i = 0; i < 15; i++) {
users.add(
User.builder()
.login("log" + i)
.name("name" + i)
.pass("pass" + i)
.role(
(i % 2 == 0) ? User.Role.ADMIN : User.Role.USER
).build()
);
}
return users;
}
}
This should work (it worked for me):
#Builder(builderClassName = "Builder")
#Value
#AllArgsConstructor(onConstructor = #__(#BsonCreator))
#BsonDiscriminator
public class User {
#BsonId
private final ObjectId _id;
#BsonProperty("name")
private final String name;
#BsonProperty("pass")
private final String pass;
#BsonProperty("login")
private final String login;
#BsonProperty("role")
private final Role role;
}
Then in lombok.config add these (in your module/project directory):
lombok.addLombokGeneratedAnnotation=true
lombok.anyConstructor.addConstructorProperties=true
lombok.copyableAnnotations += org.bson.codecs.pojo.annotations.BsonProperty
lombok.copyableAnnotations += org.bson.codecs.pojo.annotations.BsonId
Also piece of advice, keep _id if you are going to use automatic conversion to POJOs using PojoCodec, which will save a lot of trouble.
Response.java
public class Response{
private String mobileNo;
private String contractId;
private String sim;
private String imei;
public Response(String mobileNo, String contractId){
this.mobileNo = mobileNo;
this.contractId = contractId;
}
public Response(String mobileNo, String contractId, String sim,
String imei, String identificationType) {
this.mobileNo = mobileNo;
this.contractId = contractId;
this.sim = sim;
this.imei = imei;
this.identificationType = identificationType;
}
//Getter and Setter
}
MainEx.java
public class MainEx{
Response response = null;
public Response response(){
String mobileNo = null;
String contractId = null;
String sim = null;
String imei = null;
if(something){
response= new IVRAccountDetailsRs("777","4545");
}
else{
response= new IVRAccountDetailsRs("777","4545","sim","imei");
}
return response;
}
}
When if statement call return response as
{ "mobileNo" = "777";
"contractId" = "4545";
"sim"= null;
"imei" = null;
}
But I want to get the response as bellow,
When calling if statement
Need to remove other two values.
{ "mobileNo" = "777";
"contractId" = "4545";
}
If contractId and mobileNo null then output should be
{ "mobileNo" = null;
"contractId" = null;
}
When calling else statement
{ "mobileNo" = "777";
"contractId" = "4545";
"sim"= "sim";
"imei" = "imei";
}
if all values null
{ "mobileNo" = null;
"contractId" = null;
"sim"= null;
"imei" =null;
}
Used Jackson version is 2.4.1
What can I do about this?
If the version of SpringBoot is less than 1.3, it can only be handled programmatically
#JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
public class Response {
///~
}
Spring boot can be configured directly from 1.3 in the application.properties file
spring.jackson.default-property-inclusion=non_null
Official documentation for the jacksong configuration
you can use #JsonInclude(JsonInclude.Include.NON_NULL) on sim and imei, Not on the whole class
public class Response{
private String mobileNo;
private String contractId;
#JsonInclude(JsonInclude.Include.NON_NULL)
private String sim;
#JsonInclude(JsonInclude.Include.NON_NULL)
private String imei;
public Response(String mobileNo, String contractId){
this.mobileNo = mobileNo;
this.contractId = contractId;
}
public Response(String mobileNo, String contractId, String sim,
String imei, String identificationType) {
this.mobileNo = mobileNo;
this.contractId = contractId;
this.sim = sim;
this.imei = imei;
this.identificationType = identificationType;
}
What you ask it's not possible to manage just with serialization.
I suggest to edit Response class, removing the field that don't want send when they are null.
Then create another class that extends Response, that have the other 2 fields.
At this point you can instantiate which one you want based on your condition and return anyway as a Response object.
public class SimpleResponse {
String mobileNo;
String contractId;
.....getters setters
}
public class FullResponse extends SimpleResponse {
String sim;
String imei;
....getter and setters
}
If you use jackson then add this:
#JsonInclude(JsonInclude.Include.NON_NULL) before field.
public class Response{
private String mobileNo;
private String contractId;
#JsonInclude(JsonInclude.Include.NON_NULL)
private String sim;
#JsonInclude(JsonInclude.Include.NON_NULL)
private String imei;
}
For jackson serializers:
You can use annotation over your class, to skip serializing null values:
#JsonInclude(Include.NON_NULL)
public class Response{...}
Or add a parameter to your ObjectMapper configuration:
mapper.setSerializationInclusion(Include.NON_NULL);
This may be a duplicate.
UPDATE:
You can also annotate properties.
#JsonInclude(JsonInclude.Include.NON_NULL)
private String sim;
#JsonInclude(JsonInclude.Include.NON_NULL)
private String imei;
This way other properties will serialize null values, but those two will not be serialized with null value.
Add this annotation just above the getter of sim and imei
#JsonInclude(Include.NON_NULL)
With Jackson > 1.9.11 and < 2.x use
#JsonSerialize
annotation to do that:
#JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
For the version above 2:
#JsonInclude(JsonInclude.Include.NON_NULL)
Have searched in different sites but couldn't find correct answer, hence posting this request though it could possible duplicates.sorry for that.
I am sending the below json request to my back-end service and converting to java object for processing. I can see the request body passed to my service but when i convert from json to java object , values are not populating
{
"data":{
"username":"martin",
"customerId":1234567890,
"firstName":"john",
"lastName":"smith",
"password":"p#ssrr0rd##12",
"email":"john.smith#gmail.com",
"contactNumber":"0342323443",
"department":"sports",
"location":"texas",
"status":"unlocked",
"OrderConfigs":[
{
"vpnId":"N4234554R",
"serviceId":"connectNow",
"serviceType":"WRLIP",
"ipAddress":"10.101.10.3",
"fRoute":[
"10.255.253.0/30",
" 10.255.254.0/30"
],
"timeout":1800,
"mapId":"test_map"
}
]
}
}
My Parser class have something like,
JSONObject requestJSON = new JSONObject(requestBody).getJSONObject("data");
ObjectMapper mapper = new ObjectMapper();
final String jsonData = requestJSON.toString();
OrderDTO mappedObject= mapper.readValue(jsonData , OrderDTO .class);
// I can see value coming from front-end but not populating in the mappedObject
My OrderDTO.java
#JsonInclude(value = Include.NON_NULL)
#JsonIgnoreProperties(ignoreUnknown = true,value = {"hibernateLazyInitializer", "handler", "created"})
public class OrderDTO {
private String username;
private long customerId;
private String source;
private String firstName;
private String lastName;
private String email;
private String contactNumber;
private String password;
private String department;
private String location;
private String status;
private List<OrderConfig> OrderConfigs;
#JsonInclude(value = Include.NON_NULL)
public class OrderConfig {
private String vpnId;
private String serviceId;
private String serviceType;
private String ipAddress;
private String mapId;
private String[] fRoutes;
private Map<String, Object> attributes;
private SubConfig subConfig;
private String routeFlag;
getter/setters
.....
}
all setter/getter
}
Not sure what I'm missing here. Is this right way to do?
If your are trying to use inner class, correct way to use is to declare it static for Jackson to work with inner classes.
For reference check this
code changes made are
#JsonInclude(value = Include.NON_NULL)
#JsonIgnoreProperties(ignoreUnknown = true)
static class OrderConfig {
Make sure that your json tag names match with variable names of java object
Ex : "fRoute":[
"10.255.253.0/30",
" 10.255.254.0/30"
],
private String[] fRoutes;
OrderConfigs fields will not be initialized, just modify your bean as
#JsonProperty("OrderConfigs")
private List<OrderConfig> orderConfigs;
// setter and getter as setOrderConfigs / getOrderConfigs
See my answer here. (same issue)
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.