Spring boot #RequestBody add property before saving into the database - java

I'm using springboot and mongodb. I've a Customer model as below:
package com.example.customerapi.model;
import java.io.Serializable;
import java.time.LocalDate;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSetter;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
#Getter
#Setter
#ToString
#Configuration
#Document(collection = "customer")
#JsonInclude(Include.NON_NULL)
public class Customer implements Serializable {
private static final long serialVersionUID = 6748432793461621268L;
#JsonProperty("customer_id")
private String customerId;
#Field("type")
private String type;
#JsonProperty("title")
private String title;
#JsonProperty("first_name")
private String firstName;
#JsonProperty("middle_name")
private String middleName;
#JsonProperty("last_name")
private String lastName;
#JsonProperty("email")
private String email;
#JsonProperty("phone")
private String phone;
#JsonProperty("note")
private String note;
#JsonProperty("date_of_birth")
private String dateOfBirth;
#JsonProperty("sex")
private String sex;
#JsonProperty("contact_address")
private Address address;
#CreatedDate
#JsonProperty("create_timestamp")
private LocalDate createdDate;
#LastModifiedDate
#JsonProperty("modified_timestamp")
private LocalDate modifiedDate;
}
Here, type is not a part of RequestBody. Please find below CustomerController.
package com.example.customerapi.resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import com.example.customerapi.repository.CustomerRepository;
import com.example.model.Customer;
import com.example.customerapi.dto.CustomerResponse;
#RestController
public class CustomerController {
#Autowired
private CustomerRepository customerRepository;
#PostMapping(value="/addCustomer", produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseStatus(HttpStatus.CREATED)
public ResponseEntity<CustomerResponse> saveCustomer(#RequestBody Customer customer) {
try {
customer.setType("test_type"); //this is not working
return new ResponseEntity<CustomerResponse>(new CustomerResponse(customerRepository.save(customer)), HttpStatus.CREATED);
}catch(Exception ex) {
return new ResponseEntity<CustomerResponse>(new CustomerResponse("Error saving customer"), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}
But before saving customer into database I would like to set type in Customer to a sample string.
How do I set object properties that are not a part of RequestBody?

Use #transient above
#Transient
private String type;
The field will be ignored

Related

Can't use #Valid annotation on #RequestParam from multipart form after converting string to JSON

Basically, I have implemented this converter, to allow me to send JSON data as a "data" field alongside a file upload.
import javax.validation.Valid;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.ObjectMapper;
import ****.DatasetUploadDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
import org.springframework.validation.ObjectError;
import lombok.SneakyThrows;
#Component
public class StringToDatasetUploadDtoConverter implements Converter<String,
DatasetUploadDTO> {
#Autowired
private ObjectMapper objectMapper;
#Override
#SneakyThrows
#JsonIgnoreProperties(ignoreUnknown=true)
#Valid
public DatasetUploadDTO convert(String source) {
return objectMapper.readValue(source, DatasetUploadDTO.class);
}
this is my dto class:
import java.util.List;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import org.hibernate.validator.constraints.Length;
import org.springframework.web.multipart.MultipartFile;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import ****.models.ExtraMetaData;
#Data
#RequiredArgsConstructor
public class DatasetUploadDTO {
#Length(max = 0, message = "Id modification not permitted in this context.")
private String id;
#NotBlank(message = "Description is mandatory") #Length(min=3)
private String description;
private String authorId;
#NotNull
#NotBlank(message = "ExperimentId is mandatory") #Length(min=3)
private String experimentId;
private String type;
#NotNull
private Boolean isPublic;
#NotNull
private Boolean isMetaData;
#NotNull
private List<String> userPermission;
}
In my controller, I can successfully use this converter, and save to DB etc. with no problems. However, if I then add the #Valid annotation to attempt to validate according to this schema, it doesn't actually do anything:
#RequestMapping(path = "/dataset", method = RequestMethod.POST, consumes = {"multipart/form-data"})
ResponseEntity<?> postExperiment(#AuthenticationPrincipal UserDetailsImpl jwt , #RequestParam("data") /* Here nothing happens -> */ #Valid DatasetUploadDTO uploadDTO, #RequestParam("file") MultipartFile file) {
....
}
What can I do to achieve validation of this JSON field? If all else fails, is there some way I can implement validation within the body of the function?

Is there a way to make spring boot mongodb not changing your id attribute value to his object_id?

I am working in a project to learn spring boot, i have a problem where i have a attribute actor_id stored in mongodb with a value x but when i do mongoRepository.findall(), he changes the value of my actor_id to the value of the object_id generated automatically by mongodb, so even if i want to find a value by id i have to put the object_id value instead of the value of actor_id stored in database. Image below to better help understand.
I wanted that the returned value of a get http://localhost:8093/actors in actor_id be = 1 instead of 61634ad37e775d4b87635129.
Below is my code.
Actor.java:
package com.film.SpringAplication.model;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.data.mongodb.core.mapping.MongoId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
#Document(collection="actor")
#AllArgsConstructor
#Data
public class Actor {
#Id
String actor_id;
String first_name;
String last_name;
}
ActorController.java
package com.film.SpringAplication.controller;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.film.SpringAplication.model.Actor;
import com.film.SpringAplication.service.ActorService;
#RestController
#RequestMapping("/actors")
public class ActorController {
#Autowired
ActorService actorService;
#PostMapping
public String addActor(#RequestBody Actor actor) {
return actorService.addActor(actor);
}
#GetMapping
public List<Actor> getActors() {
return actorService.getActors();
}
#GetMapping("/{id}")
public List<Actor> getActor(#PathVariable String id) {
return actorService.getActor(id);
}
#DeleteMapping("/{id}")
public String deleteActor(#PathVariable String id) {
return actorService.deleteActor(id);
}
}
ActorService.java:
package com.film.SpringAplication.service;
import java.util.List;
import java.util.Optional;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import com.film.SpringAplication.model.Actor;
import com.film.SpringAplication.repository.ActorRepository;
import lombok.RequiredArgsConstructor;
#Service
#RequiredArgsConstructor
public class ActorService {
private final ActorRepository actorRepository;
private final MongoTemplate mongoTemplate;
public String addActor(Actor actor) {
actorRepository.save(actor);
return "Actor Added";
}
public List<Actor> getActors() {
List<Actor> lista = actorRepository.findAll();
return lista;
}
public List<Actor> getActor(String id) {
Query query=new Query()
.addCriteria(Criteria.where("actor_id").is(id));
return mongoTemplate.find(query,Actor.class);
//return actorRepository.findById(id);
}
public String deleteActor(String id) {
actorRepository.deleteById(id);
return "User deleted";
}
}
ActorRepository.java:
package com.film.SpringAplication.repository;
import org.springframework.data.mongodb.repository.MongoRepository;
import com.film.SpringAplication.model.Actor;
public interface ActorRepository extends MongoRepository<Actor,String>{
}
What you can do is, you can use #Field. You annotate #Id to actor_id. So basically it takes as the default primary key. You can do two things. You can annotate _id as default primary key.
#Document(collection="actor")
#AllArgsConstructor
#Data
public class Actor {
#Id
ObjectId _id;
String actor_id;
String first_name;
String last_name;
}
Else you can annotate #Field
#Document(collection="actor")
#AllArgsConstructor
#Data
public class Actor {
#Id
#Field("actor_id")
String actor_id;
String first_name;
String last_name;
}
Related answer

Spring boot with Mongo db rest Api

I have created a crud application Using spring boot initializer.
Dependencies:
Lombok
Spring Web
Spring Mongo
This app calls from a database/cluster that I have set up on atlas. but I want it to call the correct collection and just do a simple get all api call in postman
but I get a server 500 error
Service Java file:
package com.fullstack.app.Service;
import com.fullstack.app.exception.EntityNotFoundException;
import com.fullstack.app.Model.*;
import com.fullstack.app.Model.Request.WCCreationRequest;
import com.fullstack.app.Repository.StatusData_WCRepo;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
#Service
#RequiredArgsConstructor
public class StatusDataService {
private static StatusData_WCRepo wcRepository;
public StatusData createData (WCCreationRequest request) {
StatusData statusData = new StatusData();
BeanUtils.copyProperties(request, statusData);
return wcRepository.save(statusData);
}
public static List<StatusData> getAllData() {
return wcRepository.findAll();
}
}
request:
package com.fullstack.app.Model;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import lombok.Getter;
import lombok.Setter;
#Getter
#Setter
#Document(collection = "StatusData_WC")
public class StatusData {
#Id
private String ID_Number;
private String Surname;
private String Full_Names;
private String Address;
private String VR;
private Integer Ward;
private Integer VD_Number;
}
Controller:
package com.fullstack.app.Controller;
import com.fullstack.app.Model.StatusData;
import com.fullstack.app.Model.Request.WCCreationRequest;
import com.fullstack.app.Service.StatusDataService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import lombok.RequiredArgsConstructor;
#RestController
#RequestMapping(value = "/api/statusData")
#RequiredArgsConstructor
public class StatusDataController {
private final StatusDataService sdService;
#GetMapping("/statusdata")
public ResponseEntity getAllData(#RequestParam(required = false) String id) {
if (id == null) {
return ResponseEntity.ok(StatusDataService.getAllData());
}
return ResponseEntity.ok(StatusDataService.getAllData());
}
}
Application properties:
spring.data.mongodb.uri=mongodb+srv://*****:******#cluster0.wlmmf.mongodb.net/myFirstDatabase?retryWrites=true&w=majority

Can a Hibernate #Id be a string? [duplicate]

This question already has answers here:
Hibernate String Primary Key with Annotation
(4 answers)
Closed 2 years ago.
I have a table with some information of company offices and its Id is a string. I'm trying to map it in Hibernate with the #Id tag but its giving me an error for java.lang.NumberFormatException
This causes me to wonder if its possible to use strings as Ids or if I'm missing something?
Here is the error:
Jul 23, 2020 1:18:09 PM org.apache.catalina.core.ApplicationDispatcher invoke
SEVERE: Servlet.service() for servlet [jsp] threw exception
java.lang.NumberFormatException: For input string: "officeCode"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:580)
at java.lang.Integer.parseInt(Integer.java:615)
at javax.el.ListELResolver.coerce(ListELResolver.java:150)
at javax.el.ListELResolver.getValue(ListELResolver.java:67)
...
This is the office class:
package com.ver.company.model;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name = "offices")
public class Office implements Serializable{
public Office() {}
#Id
private String officeCode;
#Column
private String city;
#Column
private String phone;
#Column
private String addressLine1;
#Column
private String addressLine2;
#Column
private String state;
#Column
private String country;
#Column
private String postalCode;
#Column
private String territory;
}
}
Dao implementation:
package dom.ver.company.dao;
import java.util.List;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import dom.ver.company.model.Office;
#Repository
public class OfficeDaoImpl implements OfficeDao {
public OfficeDaoImpl () {}
#Autowired
private SessionFactory sessionFactory;
public void insertOffice(Office office) {
sessionFactory.getCurrentSession().saveOrUpdate(office);
}
public List<Office> selectOffices() {
return sessionFactory.getCurrentSession().createQuery("from Office")
.list();
}
}
Service:
package dom.ver.company.service;
import java.sql.SQLException;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import dom.ver.company.OfficeDao;
import dom.ver.company.dao.OfficeDaoImpl;
import dom.ver.company.model.Office;
#Service
#Transactional
public class OfficeServiceImpl implements OfficeService {
#Autowired
private OfficeDao officeDao;
#Override
#Transactional
public List<Office> selectOffices() {
return officeDao.selectOffices();
}
}
Controller class:
package dom.ver.company.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import dom.ver.company.model.Office;
import dom.ver.company.service.OfficeService;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
#Controller
public class OfficeController {
#Autowired
OfficeService officeServiceImpl;
OfficeController(){}
#RequestMapping({ "/", "/index" })
public ModelAndView loadIndex(ModelAndView model) {
List<Office> officeList = officeServiceImpl.selectOffices();
model.addObject("officeList", officeList);
model.setViewName("index");
return model;
}
}
If you don't specify the generation strategy, Hibernate will use GenerationType.AUTO, which is not applicable to String.
You can use it like this:
#Id
#GeneratedValue(generator="uuid")
#GenericGenerator(name="uuid", strategy="uuid2")
private String officeCode;

How to write a unit test for OneToMany connection (testing Rest endpoint)?

I'm a beginner in programming, so please forgive me if I'm asking a trivial question.
My question is, how can I make my testing method be able to check the UserModel's OneToMany connection related to the CalendarModel. I want to check, that the list contains the proper Entity, so all the 4 fields of the UserModel were tested.
My UserModel:
import com.fasterxml.jackson.annotation.JsonIgnore;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
#Entity
public class UserModel {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#OneToMany(mappedBy = "id")
#JsonIgnore
private List<CalendarModel> calendarModels;
private String username;
private String password;
public UserModel(long id, String username, String password) {
this.id = id;
this.username = username;
this.password = password;
}
public UserModel() {
}
public long getId() {
return id;
}
//Other Getters and Setters
My CalendarModel:
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
#Entity
public class CalendarModel {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne(cascade = CascadeType.MERGE)
private UserModel userModel;
private String googleId;
private String summary;
public CalendarModel() {
}
public CalendarModel(UserModel userModel, String googleId, String summary) {
this.userModel = userModel;
this.googleId = googleId;
this.summary = summary;
}
public Long getId() {
return id;
}
//Other Getters and Setters
My RestController with the endpoint:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
#RestController
public class UserController {
private UserServiceImpl service;
#Autowired
public UserController(UserServiceImpl service) {
this.service = service;
}
#GetMapping("/api/users")
public ResponseEntity<Object> allUser() {
List<UserModel> userModelList = service.listUsers();
if (!userModelList.isEmpty() && userModelList != null) {
return new ResponseEntity<>(userModelList, HttpStatus.OK);
}
return new ResponseEntity<>("Error: users not found!", HttpStatus.INTERNAL_SERVER_ERROR);
}
}
My UserModelBuilder class for testing purposes:
public class UserModelBuilder {
long id = 1;
String userName = "user";
String password = "password";
public UserModelBuilder() {
}
public UserModelBuilder withId(long id) {
this.id = id;
return this;
}
public UserModelBuilder withUsername(String userName) {
this.userName = userName;
return this;
}
public UserModelBuilder withPassword(String password) {
this.password = password;
return this;
}
public UserModel build() {
return new UserModel(id, userName, password);
}
}
My test (currently working properly):
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import java.util.Arrays;
import static org.hamcrest.Matchers.*;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
#RunWith(SpringRunner.class)
#WebMvcTest(UserController.class)
public class UserControllerTest {
#Autowired
private MockMvc mockMvc;
#MockBean
private UserServiceImpl service;
#Test
public void listAllUserTest() throws Exception {
UserModel firstUser = new UserModelBuilder()
.withId(1)
.withPassword("password")
.withUsername("firstuser")
.build();
UserModel secondUser = new UserModelBuilder()
.withId(2)
.withPassword("otherpass")
.withUsername("seconduser")
.build();
Mockito.when(service.listUsers()).thenReturn(Arrays.asList(firstUser, secondUser));
MvcResult mvcResult = mockMvc.perform(
MockMvcRequestBuilders.get("/api/users")
.accept(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$", hasSize(2)))
.andExpect(jsonPath("$[0].id", is(1)))
.andExpect(jsonPath("$[0].password", is("password")))
.andExpect(jsonPath("$[0].username", is("firstuser")))
.andExpect(jsonPath("$[1].id", is(2)))
.andExpect(jsonPath("$[1].password", is("otherpass")))
.andExpect(jsonPath("$[1].username", is("seconduser")))
.andExpect(status().isOk())
.andDo(print())
.andReturn();
Mockito.verify(service).listUsers();
}
}
Thank you in advance! :)

Categories