I have tried all the answer I have found on internet and nothing seems to be working.
I have added hibernate-validation, spring validation but both are not working and bindingResult.haserrors() is always false.
Dependencies I am using currently in my project
javax.validation:validation-api:2.0.1.Final
org.hibernate.validator:hibernate-validator:6.0.18.Final
org.springframework.boot:spring-boot-starter-validation:2.1.13.RELEASE
com.github.java-json-tools:json-schema-validator:2.2.8
io.springfox:springfox-bean-validators:2.9.2
Controller
public String processRequest(
#ApiParam(value = "Input JSON",
required = true) #Valid #RequestBody MyClass myClass,
BindingResult results) {
if (results.hasErrors()) {
List<FieldError> fieldErrors = results.getFieldErrors();
throw new InvalidFieldException(fieldErrors);
}
}
MyClass
public class MyClass {
#NotBlank
#Size(min = 1, max = 80)
private String firstName;
#Size(max = 80)
private String middleName;
#NotBlank
#Size(min = 1, max = 80)
private String lastName;
}
I am call controller using this myClass Object
MyClass myClass =
MyClass.builder().firstName("linus").lastName("").build();
Can someone please help me?
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 do not understand why an Entity no argument constructor is being called when providing a request body? if i delete it and the only constructor that exist is the one that receive arguments, i get the expected output print, but i must implement a no argument constructor in order to save the Entity in the database.
this is the request body:
{
"str": "stringgg",
"intt": 2,
"doublee": 1.003
}
this is the route: when commenting out the empty constructor, the values of the new instance match the request json body
#PostMapping("/save")
public List<Modell> obj(#RequestBody Modell model) {
modelRepository.save(model);
System.out.println(model.toString());
return modelRepository.findAll();
}
this is the entity class:
#Table(name = "modelltbl")
#Entity
public class Modell {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
#Column(name = "id", nullable = false)
private long id;
#Column(name = "str", nullable = true)
private String str;
#Column(name = "intt", nullable = true)
private int intt;
#Column(name = "doublee", nullable = true)
private double doublee;
public Modell(String str, int intt, double doublee)
{
this.str = str;
this.intt = intt;
this.doublee = doublee;
}
public Modell(){}
#Override
public String toString()
{
return String.format("model class,params: %s , %o , %f ", str , intt, doublee);
}
}
First of all: Do not use entities iat controller level. It is bad application Design.
The json will be converted throug jackson library which creates the object by calling the default constructor and the setter of the properties. If you do not want this behavior you can use the #JsonCreator annotation.
#JsonCreator
public Modell(#JsonProperty("str")String str, #JsonProperty("intt")int intt, #JsonProperty("doublee")double doublee)
{
this.str = str;
this.intt = intt;
this.doublee = doublee;
}
this my is rest request that is compatible for another service :
{
"fromDate": 1562773101000,
"toDate": 1563118701000,
"turnOverType": 4,
"fromAmount": 1,
"toAmount": 10000000,
"voucherDescription": null,
"articleDescription": null,
"referenceNumbers": [],
"offset": 3,
"pageSize": 20,
"iban": "BLAHBLAHBLAHBLAH"
}
and this is corresponding model that not match request :
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "TransferRequestInquiryFilter")
public class TransferRequestInquiryFilter implements Serializable {
#XmlElement(name = "sourceIbans")
private List<String> sourceIbans;
#XmlElement(name = "transferType")
private TransferType transferType;
#XmlElement(name = "fromTransferDate")
private Timestamp fromTransferDate;
#XmlElement(name = "toTransferDate")
private Timestamp toTransferDate;
#XmlElement(name = "fromRegistrationDate")
private Timestamp fromRegistrationDate;
#XmlElement(name = "toRegistrationDate")
private Timestamp toRegistrationDate;
#XmlElement(name = "trackingNumbers")
private List<String> trackingNumbers;
#XmlElement(name = "referenceNumbers")
private List<String> referenceNumbers;
#XmlElement(name = "transactionIds")
private List<String> transactionIds;
#XmlElement(name = "status")
private TransactionStatus status;
#XmlElement(name = "fromAmount")
private Long fromAmount;
#XmlElement(name = "toAmount")
private Long toAmount;
#XmlElement(name = "destinationIbans")
private List<String> destinationIbans;
and this is my controller ..
#RequestMapping(value = "/inquiry", method = RequestMethod.POST)
public #ResponseBody
ResponseEntity<List<ExtendedTransferRequest>> transferInquiry(#RequestBody #Valid TransferRequestInquiryFilter transferRequestInquiryFilter
, BindingResult bindingResult) {
// when validation not works return bad request
List<ErrorObject> errorObjects = requestInquiryValidator.validate(transferRequestInquiryFilter);
if (errorObjects.size() > 0) {
// just throw bad request and not detail of them
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
List<ExtendedTransferRequest> extendedTransferRequestList = new ArrayList<>();
ExtendedTransferRequest extendedTransferRequest = new ExtendedTransferRequest();
List<SettlementTransaction> settlementTransactionList = settlementSearch.findSettlement(transferRequestInquiryFilter);
extendedTransferRequestList = TransferInquiryResponseMapper.INSTANCE.SettlementTransactionInquiryResponse(setlementTransactionList);
return new ResponseEntity<>(extendedTransferRequestList, HttpStatus.OK);
}
just fromAmount and toAmount fills. but i want to get an exception for this situation and throw a bad request for client. how can i do that? If I get name conflict or type conflict between rest request and model , I need to handle it and riase a bad request for client. i am using spring mvc 5 and jackson-core and jackson-databind 2.9.4
Using validation-api, annotate proper validation for fields and #validated before controller method and using #valid before RequestBody object would throw proper validation exception.
I use Angular 5 + Spring Boot. The problem is that I can not send information to my rest controller by post method.
I do not get any error either from the client side or from the server side.
Below the code you will see that I make get method which works correctly.
Let me apologize for my Еnglish.
Spring Entity { Dish }
#Entity
#Table(name = "DISHES")
#Data
public class Dish implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID")
private Long id;
#Column(name = "NAME", unique = true)
#NotNull(message = "Ястието трябва да има име.")
#Size(min = 3, max = 30, message = "Името на ястието трябва да е между 3 и 30 символа.")
private String name;
#Column(name = "DESCRIPTION")
#NotNull(message = "Описанието на ястието не може да е празно.")
#Size(min = 3, max = 300, message = "Описанието на ястието трябва да е между 3 и 30 символа.")
private String description;
#JsonIgnore
#OneToMany(cascade = CascadeType.ALL ,mappedBy = "dish")
#JsonBackReference
private List<DishCounter> dishCounters;
}
Angular Entity {Dish}
export class Dish {
constructor(public id?: number, public name?: string, public description?: string) {
}
}
Spring Rest Controller {Dish}
#CrossOrigin(origins = "http://localhost:4200")
#RestController
#RequestMapping("/dish")
public class DishRestController {
private static final Logger logger = LoggerFactory.getLogger(DishRestController.class);
private final DishService dishService;
#Autowired
public DishRestController(final DishService dishService) {
this.dishService = dishService;
}
#GetMapping("/all")
public ResponseEntity<List<Dish>> getAllDishes() {
logger.info("Rest controller find all dishes");
List<Dish> dishes = dishService.getAllDishes();
return ResponseEntity.status(HttpStatus.OK).body(dishes);
}
#PostMapping("/save")
public ResponseEntity<Void> saveDish(#RequestBody Dish dish) {
dishService.saveDish(dish);
return new ResponseEntity<>(HttpStatus.OK);
}
}
And Angular post Method
save(dish: Dish): Observable<Dish> {
let result: Observable<Dish>;
result = this.http.post(this.saveDishUrl, dish)
.map((resp => {
console.log(resp);
return resp;
}))
.catch(e => {
console.log(e);
return Observable.throw(e);
});
console.log(result);
return result;
}
Where are you calling subscribe on the post function? I don't see it here. As http post returns an observable, you must subscribe to it to make the call.
http.post(....).subscribe(response => <DO SOMETHING WITH IT>);
This might not be all of the errors on your code but this is something I noticed.
Your Java #PostMapping doesn't specify what it should be expected to receive and what it should produce in return.
#PostMapping(value = "save", consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
For Angular 5, you're using Angular 4 service Syntax, I thought they changed that on 5.
I need to validate a Resource object with #NotBlank annotations in the POST method manually. Is there any way to validate Resource object using Jackson/Spring api. Not sure how to do it.
public class FileMetadataResource extends BaseResource {
#JsonProperty("title")
#NotBlank(groups = {default.class})
#Size(max = 60)
private String title;
#JsonProperty("description")
#Size(max = 255)
#NotBlank
private String description;
}
My custom HandlerMethodArgumentResolver populates the FileMetadataResource
#RequestMapping(method = RequestMethod.POST, consumes = "multipart/related")
#ResponseStatus(HttpStatus.CREATED)
public FileMetadataResource post(FileMetadataResource fileMetadataResource) {
//How to validate fileMetadataResource using jackson here
}
ANy help is appreciated.