How to validate data in service layer in spring boot - java

Controller:
#RestController
#RequestMapping(path = "api/v1/users")
public class UserController {
#Autowired
UserService userService;
#PostMapping("/register")
public ResponseEntity<Map<String, String>> registerUser(#RequestBody Map<String, Object> userMap){
Map<String, String> map = new HashMap<>();
try {
String first_name = (String) userMap.get("first_name");
String last_name = (String) userMap.get("last_name");
Users user = userService.registerUser(first_name, last_name);
map.put("message:","User registered successfully");
}catch(Exception e) {
map.put("message:",e.getMessage());
return new ResponseEntity<>(map, HttpStatus.UNAUTHORIZED);
}
return new ResponseEntity<>(map, HttpStatus.OK);
}
}
Service Layer:
#Service
#Transactional
public class UserServicesImpl implements UserService{
#Autowired
UserRepository userRepository;
#Override
public Users registerUser(String first_name, String last_name) throws EtAuthException {
String username = first_name+99;
Integer userId = userRepository.create(first_namea, last_name);
return userRepository.findById(userId);
}
}
Repository:
#Repository
public class UserRepositoryImpl implements UserRepository {
private final UserRepositoryBasic userRepositoryBasic;
public UserRepositoryImpl(UserRepositoryBasic userRepositoryBasic) {
this.userRepositoryBasic = userRepositoryBasic;
}
#Override
public Integer create(String first_name, String last_name) throws EtAuthException {
try{
Users insertData = userRepositoryBasic.save(new Users(first_name, last_name));
return insertData.getId();
}catch (Exception e){
throw new EtAuthException(e.getMessage());
}
}
}
Model/Entity:
#Entity
#Table(name="users")
public class Users {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", updatable = false, nullable = false)
private Integer id;
#NotBlank(message="First name can not be empty")
#Column(nullable = false, length = 40)
private String first_name;
#NotBlank(message="Last name can not be empty")
#Column(nullable = false, length = 40)
private String last_name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getFirst_name() {
return first_name;
}
public void setFirst_name(String first_name) {
this.first_name = first_name;
}
public String getLast_name() {
return last_name;
}
public void setLast_name(String last_name) {
this.last_name = last_name;
}
public Users(String first_name, String last_name) {
this.first_name = first_name;
this.last_name = last_name;
}
public Users() {
}
}
The response I am getting is:
I want to do the validation at Service Layer but unable to do so. Validation works for my code implementation but the problem is that the validation message is shown with the package and class names which I do not want to show. I am trying to get only the validation error message if validation fail.
I tried adding #Valid annotation but unable to get the response I am looking for.
I am looking for a response below if validation fails.
"message": ["First name can not be empty","Last name can not be empty"]
Can anyone help me out with this problem. Thank you in advance.

Add a global exception handler to parse your error and return error message in the format you need.
#ExceptionHandler({ ConstraintViolationException.class })
public ResponseEntity<Object> handleConstraintViolation(
ConstraintViolationException ex, WebRequest request) {
List<String> errors = new ArrayList<String>();
for (ConstraintViolation<?> violation : ex.getConstraintViolations()) {
errors.add(violation.getRootBeanClass().getName() + " " +
violation.getPropertyPath() + ": " + violation.getMessage());
}
ApiError apiError =
new ApiError(HttpStatus.BAD_REQUEST, ex.getLocalizedMessage(), errors);
return new ResponseEntity<Object>(
apiError, new HttpHeaders(), apiError.getStatus());
}
Source

You must to change your userMap object for your validated User class in your controller:
public ResponseEntity<Users> registerUser(#RequestBody #Valid Users){
Users createdUser = userService.registerUser(user.firstName, user.lastName);
return ResponseEntity.ok().body(createdUser).build();
}
This should returns the error messages for not valid fields only in a JSON structure.
A good practice is the use of DTOs instead Entities clases for Controllers requests and responses, you can read more about that here:
https://www.amitph.com/spring-entity-to-dto/
In this way you can choose those fields from your Entities that you want to show.

Related

How to insert a json body with multiple data to multiple tables with relationship in springboot

I have two entities: UserEntity and LoginEntity and crudrepositories for each. The entities have a relationship of OneToOne where one user will have one login account. I also created a controller and I can get all the data from the database i.e when call getalluser I get all users with their relationship to login. and when I call getAllLogins I get all logins accounts. I also managed to insert the user and the login using API each individually and it's working fine but this will omit the foreign-key user_id.
Now since am knew am stack on how to insert the user and login each respectively with their relationships through one json body
#Entity#Table(name="user_table")public class UserEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long uid;
private String fname;
private String lname;
#OneToOne( cascade = CascadeType.ALL, mappedBy = "userEntityFk")
private LoginEntity logins;
public UserEntity() {
super();
}
public Long getUid() {
return uid;
}
public void setUid(Long uid) {
this.uid = uid;
}
public String getFname() {
return fname;
}
public void setFname(String fname) {
this.fname = fname;
}
public String getLname() {
return lname;
}
public void setLname(String lname) {
this.lname = lname;
}
public LoginEntity getLogins() {
return logins;
}
public void setLogins(LoginEntity logins) {
this.logins = logins;
}
public UserEntity(Long uid, String fname, String lname, LoginEntity logins) {
super();
this.uid = uid;
this.fname = fname;
this.lname = lname;
this.logins = logins;
}
#Entity #Table(name="login_table") public class LoginEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long lid;
private String username;
private String password;
#OneToOne(cascade = CascadeType.ALL )
private UserEntity userEntityFk;
public LoginEntity() {
super();
}
public LoginEntity(Long lid, String username, String password, UserEntity userEntityFk) {
super();
this.lid = lid;
this.username = username;
this.password = password;
this.userEntityFk = userEntityFk;
}
public Long getLid() {
return lid;
}
public void setLid(Long lid) {
this.lid = lid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public UserEntity getUserEntityFk() {
return userEntityFk;
}
public void setUserEntityFk(UserEntity userEntityFk) {
this.userEntityFk = userEntityFk;
}
}
#Repository
public interface LoginRepo extends CrudRepository<LoginEntity, Integer> {
}
#Repository
public interface UserRepo extends CrudRepository<UserEntity, Integer> {
}
#RestController
#RequestMapping(path="/api")
public class MainController {
#Autowired
private UserRepo userRepository;
#Autowired
private LoginRepo loginRepository;
//===this works fine i can get all the users after insert
#GetMapping(path="/user_acc")
public #ResponseBody Iterable<UserEntity> getAllUsers() {
// This returns a JSON or XML with the users
return userRepository.findAll();
}
//================this too works fine after insert
#GetMapping(path="/login_acc")
public #ResponseBody Iterable<LoginEntity> getAlllogins() {
// This returns a JSON or XML with the users
return loginRepository.findAll();
}
//===adding single user works fine. and it returns user_id
#PostMapping("/user_acc")
public Long addNewUser(#RequestBody UserEntity userz){
UserEntity ue = userRepository.save(userz);
return ue.getUid();
}
//===this works but the foreign key not inserted and thats where my problem is
#PostMapping("/login_acc")
public LoginEntity addNewLogin(#RequestBody LoginEntity loginz){
return loginRepository.save(loginz);
}
}
class UserLogin{
UserEntity myuser;
LoginEntity mylogin;
public UserEntity getMyuser() {
return myuser;
}
public void setMyuser(UserEntity myuser) {
this.myuser = myuser;
}
public LoginEntity getMylogin() {
return mylogin;
}
public void setMylogin(LoginEntity mylogin) {
this.mylogin = mylogin;
}
}
result on post http://localhost:8080/api/login_acc. account created but no foreign key
result on post http://localhost:8080/api/login_acc. account created but no foreign key
{
"lid": 1,
"username": "admin1",
"password": "11111",
"userEntityFk": null
}
result on geting all users on get method http://localhost:8080/api/user_acc
{
"uid": 1,
"fname": "hassan",
"lname": "zahor",
"logins": null
}
what i want to post is this body below to multiple tables
{
"fname":"hassan",
"lname":"zahor",
"username": "admin5",
"password": "55555"
}
This one should works better :
{
"fname":"hassan",
"lname":"zahor",
"userEntityFk" : {
"username": "admin5",
"password": "55555"
}
}
However, you will get an error if your endpoint returns an object that contains a loop inclusion : spring will try to map it into json indefinitely.
You can correct this issue to map your result into another object before returning it from your controller, or just remove the property "logins" from UserEntity.

Spring Boot Hibernate Many To One not saving joinColumn result

I'm trying to store images in MySQL using Spring boot, I have a user entity and I want to create a Many To One relationship between my FileUpload entity.
I'm using react on the front end and the purpose of this upload service is to have profile pictures that a user can set themselves but I'd first like to get the relationship between the User and FileUpload entities correct.
The issue I have is that the joinColumn in the FileUpload table does not save the User Entities id when a user uploads an image. It just returns a null value in the foreign key field.
FileUpload.java
#Entity
#Table(name="file_upload")
public class FileUpload {
#Id
#GenericGenerator(name = "uuid", strategy = "uuid2")
#GeneratedValue(generator = "uuid")
private String id;
private String name;
private String type;
#Lob
private byte[] data;
#ManyToOne
#JoinColumn( name="user_id")
private User user;
public FileUpload() {
}
public FileUpload(String name, String type, byte[] data) {
this.name = name;
this.type = type;
this.data = data;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public byte[] getData() {
return data;
}
public void setData(byte[] data) {
this.data = data;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
FileUploadService.java
I also have a repository for this, with no custom methods inside.
#Service
public class FileUploadService {
#Autowired
private FileUploadRepository fileUploadRepository;
public FileUpload store(MultipartFile file) throws IOException {
String fileName = StringUtils.cleanPath(file.getOriginalFilename());
FileUpload fileDB = new FileUpload(fileName, file.getContentType(), file.getBytes());
return fileUploadRepository.save(fileDB);
}
public FileUpload getFile(String id) {
return fileUploadRepository.findById(id).get();
}
public Stream<FileUpload> getAllFiles() {
return fileUploadRepository.findAll().stream();
}
}
FileUploadController.java
#Controller
#CrossOrigin()
public class FileUploadController {
#Autowired
private FileUploadService fileUploadService;
#PostMapping("/upload")
public ResponseEntity<?> uploadFile(#RequestParam("file")MultipartFile file) {
String message = "";
try {
fileUploadService.store(file);
message = "Uploaded the file successfully: " + file.getOriginalFilename();
return ResponseEntity.status(HttpStatus.OK).body(new ApiResponse(true, message));
} catch (Exception e) {
message = "Could not upload the file: " + file.getOriginalFilename() + "!";
return ResponseEntity.status(HttpStatus.EXPECTATION_FAILED).body(new ApiResponse(true, message));
}
}
#GetMapping("/files")
public ResponseEntity<List<?>> getListFiles() {
List<FileUploadResponse> files = fileUploadService.getAllFiles().map(dbFile -> {
String fileDownloadUri = ServletUriComponentsBuilder
.fromCurrentContextPath()
.path("/files/")
.path(dbFile.getId())
.toUriString();
return new FileUploadResponse(
dbFile.getName(),
fileDownloadUri,
dbFile.getType(),
dbFile.getData().length);
}).collect(Collectors.toList());
return ResponseEntity.status(HttpStatus.OK).body(files);
}
#GetMapping("/files/{id}")
public ResponseEntity<byte[]> getFile(#PathVariable String id) {
FileUpload fileUpload = fileUploadService.getFile(id);
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileUpload.getName() + "\"")
.body(fileUpload.getData());
}
}
Postman POST request
MySQL Tables
User
FileUpload
I have the same relationship with a confirmation token entity i have to confirm a users email which does work properly with the ManyToOne relationship but this doesn't. I am using the same relationship mapping but it gives me null values as seen above.
#ManyToOne
#JoinColumn( name="user_id")
private User user;
I can upload the file fine but I want to be able to keep track of a user and their files.
You need to assign a user to this entity:
FileUpload fileDB = new FileUpload(fileName, file.getContentType(), file.getBytes());
fileDB.setUser(userThatSentImage); // you need to set user
return fileUploadRepository.save(fileDB);
How do you authenticate users? If you are using spring security, here you can find how to retrieve user from session: https://www.baeldung.com/get-user-in-spring-security

How can I see the validation error returned from the rest api on kotlin?

I have a spring based rest api.Checking my dto class for errors
ErrorDetails.java
public class ErrorDetails {
public ErrorDetails(Date timestamp, String message, String details) {
super();
this.timestamp = timestamp;
this.message = message;
this.details = details;
}
public Date getTimestamp() {
return timestamp;
}
public void setTimestamp(Date timestamp) {
this.timestamp = timestamp;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getDetails() {
return details;
}
public void setDetails(String details) {
this.details = details;
}
private Date timestamp;
private String message;
private String details;
}
GlobalExceptionHandler.java
#ControllerAdvice
public class GlobalExceptionHandler {
#ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<?> customValidationErrorHanding(MethodArgumentNotValidException exception){
ErrorDetails errorDetails = new ErrorDetails(new Date(), "Validation Error!",
exception.getBindingResult().getFieldError().getDefaultMessage());
return new ResponseEntity<>(errorDetails,HttpStatus.BAD_REQUEST);
}
}
CustomerDto.java
public class CustomerDto {
private String nickName;
#NotNull
#Size(min = 2 , max = 20 , message = "Incorret name")
private String name;
#NotNull
#Size(min = 2 , max = 20 , message = "Incorret surname")
private String surname;
#NotBlank
#Email
private String e_mail;
#NotNull
#Size(min = 6, max = 20, message = "Your password should be at least 6 character")
private String password;
#NotNull
private long balance;
#Nullable
private long carID;
//getter and setter method...
}
CustomerController.java
#RestController
public class CustomerController {
#Autowired
private CustomerService customerService;
#PostMapping("/addcustomer")
public Customer addCustomer(#Valid #RequestBody CustomerDto customer) {
return customerService.save(customer);
}
}
CustomerServiceImpl.java
#Transactional
#Service
public class CustomerServiceImpl implements CustomerService{
#Autowired
private CustomerRepository customerRepository;
#Override
public Customer save(CustomerDto customerdto){
try {
Customer customer = new Customer();
convertToEntity(customer, customerdto);
return customerRepository.save(customer);
}
catch (Exception e) {
e.printStackTrace();
return null;
}
}
CustomerRepository.java
#Repository
public interface CustomerRepository extends CrudRepository<Customer,String>{
}
For example, when I test it in the postman app, I get the error correctly when the customer password is less than 6 digits.
{
"timestamp": "2021-01-04T20:32:40.665+00:00",
"message": "Validation Error!",
"details": "Your password should be at least 6 character"
}
I'm connecting from kotlin to spring with retrofit. For example, when I post a customer whose password is less than 6 digits, How can I see the details message in kotlin
This is how I do customer post in kotlin
val test= Customer("aaaa","aaaaa","aaaaaaa","aaaaaa#gmail.com","1",1111)
val req= serviceNew.addCustomer(test)
req.enqueue(object : Callback<String> {
override fun onFailure(call: Call<String>, t: Throwable) {
println(t.message)
println("fail")
}
override fun onResponse(call: Call<String>, response: Response<String>) {
if(response.isSuccessful) {
println(response.body())
}
else
{
//println(????)
}
}
})
You can get response message or code using methods response.message(), response.code() or response.errorBody(). Here is the documentation for Retrofit response: https://square.github.io/retrofit/2.x/retrofit/retrofit2/Response.html
In your case you can get the raw error body string by using response.errorBody().string() and then convert this string to JSONObject and get the details by using .getString("details") method.

Spring #OneToMany problems

Doing a project with parcel service. I created OrderItem API and Dispatcher API. Now, I want to connect then by relations. The idea is: dispatcher can have many orderItems. OrderItem can only have one dispatcher. If you delete dispatcher, his order items also has to go out.
I have already created a little bit, but I'm so messed up here and can't finish this thing logically. Would someone give me some ideas on how I should attack this problem.
Do I need to put relations both sides or only to one of them?
When do I need to create constructors with arguments? Because in entity class you have to have no arg constructors...?
OrderItem class:
#Entity
public class OrderItem {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#NotBlank(message = "Order weight is required")
private String weight;
#NotBlank(message = "Order dimensions are required")
private String dimensions;
#NotBlank(message = "Order origin is required")
private String origin;
#NotBlank(message = "Order destination is required")
private String destination;
#NotNull(message = "Order comment cannot be null")
private String comment;
#ManyToOne
private Dispatcher dispatcher;
public OrderItem() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getWeight() {
return weight;
}
public void setWeight(String weight) {
this.weight = weight;
}
public String getDimensions() {
return dimensions;
}
public void setDimensions(String dimensions) {
this.dimensions = dimensions;
}
public String getOrigin() {
return origin;
}
public void setOrigin(String origin) {
this.origin = origin;
}
public String getDestination() {
return destination;
}
public void setDestination(String destination) {
this.destination = destination;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
public Dispatcher getDispatcher() {
return dispatcher;
}
public void setDispatcher(Dispatcher dispatcher) {
this.dispatcher = dispatcher;
}
}
OrderController class:
#RestController
#RequestMapping("/order")
public class OrderController {
#Autowired
OrderService service;
#Autowired
private MapValidationErrorService mapValidationErrorService;
#GetMapping("/{dispatcherId}/orders")
public List<OrderItem> getAllOrderItems(#PathVariable int dispatcherId) {
return service.getAllOrderItems(dispatcherId);
}
#PostMapping("/{dispatcherId}/orders")
public ResponseEntity<?> saveOrder(#Valid #RequestBody OrderItem orderItem, #PathVariable int dispatcherId, BindingResult result) {
ResponseEntity<?> errorMap = mapValidationErrorService.MapValidationService(result);
if (errorMap != null) {
return errorMap;
}
orderItem.setDispatcher(new Dispatcher(dispatcherId, "", "", ""));
service.insertOrUpdate(orderItem);
return new ResponseEntity<String>("Order was created successfully", HttpStatus.CREATED);
}
#PutMapping("/update")
public ResponseEntity<?> updateOrder(#Valid #RequestBody OrderItem orderItem, BindingResult result) {
ResponseEntity<?> errorMap = mapValidationErrorService.MapValidationService(result);
if (errorMap != null) {
return errorMap;
}
service.insertOrUpdate(orderItem);
return new ResponseEntity<String>("Order was updated successfully", HttpStatus.OK);
}
#GetMapping("/all")
public Iterable<OrderItem> getAllOrders() {
return service.findAllOrders();
}
#DeleteMapping("/{orderId}")
public ResponseEntity<String> deleteOrder(#PathVariable int orderId) {
if (service.findById(orderId) == null) {
throw new CustomErrorException("Order doesn't exist, check order id");
}
service.deleteOrder(orderId);
return new ResponseEntity<String>("Order with ID " + orderId + " was deleted", HttpStatus.OK);
}
#GetMapping("/{orderId}")
public ResponseEntity<OrderItem> getOrderById(#PathVariable int orderId) {
OrderItem item = service.findById(orderId);
if (service.findById(orderId) == null) {
throw new CustomErrorException("Order id not found - " + orderId);
}
return new ResponseEntity<OrderItem>(item, HttpStatus.OK);
}
}
Dispatcher class:
#Entity
public class Dispatcher {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#NotBlank(message = "Dispatcher first name is required")
private String firstName;
#NotBlank(message = "Dispatcher last name is required")
private String lastName;
#NotBlank(message = "Dispatcher email name is required")
private String email;
#NotBlank(message = "Dispatcher email is required")
private String password;
#NotBlank(message = "Dispatcher phone number is required")
private String phoneNumber;
public Dispatcher() {
}
public Dispatcher(int id, String firstName, String lastName, String email) {
super();
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
}
DispatcherController class:
#RestController
#RequestMapping("/dispatcher")
public class DispatcherController {
#Autowired
DispatcherService service;
#Autowired
private MapValidationErrorService mapValidationErrorService;
#PostMapping("/save")
public ResponseEntity<?> saveDispatcher(#Valid #RequestBody Dispatcher dispatcher, BindingResult result) {
ResponseEntity<?> errorMap = mapValidationErrorService.MapValidationService(result);
if (errorMap != null) {
return errorMap;
}
service.insertOrUpdate(dispatcher);
return new ResponseEntity<String>("Dispatcher was created successfully", HttpStatus.CREATED);
}
#GetMapping("/all")
public Iterable<Dispatcher> getAllDispatchers() {
return service.findAllDispatchers();
}
#GetMapping("/{dispatcherId}")
public ResponseEntity<?> getDispatcherById(#PathVariable int dispatcherId) {
Dispatcher dispatcher = service.findById(dispatcherId);
if (service.findById(dispatcherId) == null) {
throw new CustomErrorException("Dispatcher id not found - " + dispatcherId);
}
return new ResponseEntity<Dispatcher>(dispatcher, HttpStatus.OK);
}
#DeleteMapping("/{dispatcherId}")
public ResponseEntity<?> deleteDispatcher(#PathVariable int dispatcherId) {
if (service.findById(dispatcherId) == null) {
throw new CustomErrorException("Dispatcher doesn't exist, check dispatcher id");
}
service.deleteDispatcher(dispatcherId);
return new ResponseEntity<String>("Order with ID " + dispatcherId + " was deleted", HttpStatus.OK);
}
#PutMapping("/update")
public ResponseEntity<?> updateDispatcher(#Valid #RequestBody Dispatcher dispatcher, BindingResult result) {
ResponseEntity<?> errorMap = mapValidationErrorService.MapValidationService(result);
if (errorMap != null) {
return errorMap;
}
service.insertOrUpdate(dispatcher);
return new ResponseEntity<String>("Dispatcher was updated successfully", HttpStatus.OK);
}
}
I think you have defined the relationship incorrectly. And yes you need to have no-args constructor. This helps hibernate to map the values from database to java objects when retrieving data from the database
Assuming you are going for a uni-directional mapping,
#Entity
public class OrderItem {
#ManyToOne( cascade = CascadeType.ALL )
#JoinColumn(name = <foriegn_key_column in orderItem table i.e. id>)
private Dispatcher dispatcher;
}
#Entity
public class Dispatcher {
private List<OrderItem > orders;
}
The main difference is that bidirectional relationship gives you access in both directions. so that you can access the other side without any queries. It works for cascade actions too.
The bidirectional #OneToMany generates better DML because the #ManyToOne owns the relationship.
Unidirectional #ManyToOneor bidirectional #OneToMany are more efficient than unidirectional #OneToMany.
Before JPA 2.0 this unidirection #OneToMany used a join table to manage the association between parent and child rows. So higher cost in read (3 tables join) and write (3 tables insertion).
Since JPA 2.0 for unidirectional #OneToMany you should use it in correlation with #JoinColumn
With the #JoinColumn the #OneToMany association controls the child table FK.. and so no need for extra junction table.
But performance wise there is no better than bidirectional associations.
Pros of unidirectional #OneToMany -> simplicity.
For your second question : NoArg is required only by the persistence framework (Hibernate for e.g). But you can (and should) use your own constructors to create consistent objects.

Failed to read HTTP message. Required request body is missing

I have faced with a problem that I can't get my object on server side.
I am getting this error:
128870 [http-apr-8080-exec-1] WARN org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver - Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing: public com.webserverconfig.user.entity.User com.webserverconfig.user.controller.UserController.login(com.webserverconfig.user.entity.User)
I am trying to send object on server side using GET request. I want to use this object just to verify fields on it. (I am doing simple user login method and i want to check userName and userPassword).
Here is my code on server side:
Request:
#RequestMapping(value = "/login", method = RequestMethod.GET)
#ResponseStatus(value = HttpStatus.ACCEPTED)
public User login(#RequestBody User user) {
userValidator.validateUserLogin(user);
securityService.autoLogin(user.getUserName(), user.getUserPassword());
return user;
}
Entity user:
#Entity
#Table(name = "Users")
public class User {
public User() {
}
#Id
#GeneratedValue(generator = "increment")
#GenericGenerator(name = "increment", strategy = "increment")
#Column(name = "Id", unique = true, nullable = false)
private long id;
#Column(name = "userName", nullable = false)
private String userName;
#Column(name = "userPassword", nullable = false)
private String userPassword;
#Transient
private String confirmPassword;
public long getId() {
return id;
}
public String getUserName() {
return userName;
}
public String getUserPassword() {
return userPassword;
}
public String getConfirmPassword() {
return confirmPassword;
}
public void setId(long id) {
this.id = id;
}
public void setUserName(String userName) {
this.userName = userName;
}
public void setUserPassword(String userPassword) {
this.userPassword = userPassword;
}
public void setConfirmPassword(String confirmPassword) {
this.confirmPassword = confirmPassword;
}
}
Client side code:
private class LoginUserTask extends AsyncTask<Void, Void, User> {
#Override
protected User doInBackground(Void... voids) {
restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
User user = new User(userName, userPassword);
return restTemplate.getForObject(URL.getUserLogin(), User.class, user);
}
#Override
protected void onPostExecute(User user) {
responseEntity = restTemplate.getForEntity(URL.getUserLogin(), String.class);
HttpStatus responseStatus = responseEntity.getStatusCode();
if(responseStatus.equals(HttpStatus.ACCEPTED)){
view.makeToast("User login completed " + user.getUserName());
} else {
view.makeToast("User login or password is not correct");
}
}
}
Am I missing something? Can anybody help with this please ?
You have set a #RequestBody annotation with a User object as an input parameter.
In this case, you have to use POST method along with a User object in the body of the request.

Categories