Hi I’m new in SpringBoot and I created this microservice that doesn’t work.
when I try to run a get with postman I get this error ,can you help me?
"timestamp": "2022-09-29T15:24:02.783+00:00",
"status": 500,
"error": "Internal Server Error",
"trace": "org.springframework.data.crossstore.ChangeSetPersister$NotFoundException\r\n\tat com.poste.anagrafica.controller.UserController.listUserByRegistrationNumber(UserController.java:45)\r\n\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\r\n\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\r\n\tat java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\r\n\tat java.base/java.lang.reflect.Method.invoke(Method.java:566)\r\n\tat org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)\r\n\tat org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)\r\n\tat org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)\r\n\tat org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1071)\r\n\tat org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:964)\r\n\tat org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)\r\n\tat org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)\r\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:655)\r\n\tat org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)\r\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:764)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)\r\n\tat org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)\r\n\tat org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)\r\n\tat org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)\r\n\tat org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)\r\n\tat org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)\r\n\tat org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360)\r\n\tat org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399)\r\n\tat org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)\r\n\tat org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:890)\r\n\tat org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1789)\r\n\tat org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)\r\n\tat org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)\r\n\tat org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)\r\n\tat org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\r\n\tat java.base/java.lang.Thread.run(Thread.java:829)\r\n",
"message": "No message available",
"path": "/user/cerca/ciao"
}
I attach the classes
this is the database
the class entiy
#Entity
#Table(name = "USERS")
#Data
#NoArgsConstructor
#AllArgsConstructor
#Getter
#Setter
public class User implements Serializable {
#Id
#Column(name = "user_id", nullable = false)
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "created_date")
private LocalDateTime createdDate;
#Column(name = "deleted", nullable = false)
private Long number;
#Column(name = "modified_date")
private LocalDateTime modifiedDate;
#Column(name = "birth_place")
private String birthPlace;
#Column(name = "birthday")
private Date birthDay;
#Column(name = "canNominate")
private Long canNominate;
#Column(name = "email")
private String email;
#Column(name = "firstName")
private String firstName;
#Column(name= "fiscalCode")
private String fiscalCode;
#Column(name = "hiringDate")
private Date hiringDate;
#Column(name ="last_name")
private String lastName;
#Column(name = "matricola")
private String matricola;
#Column(name = "position")
private String position;
#Column(name = "registration_number")
private String registrationNumber;
#Column(name = "replaced")
private Long replaced;
#Column(name = "terminationDate")
private Date terminationDate;
#Column(name = "user_status")
private String userStatus;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "application_role_id")
private Role applicationRoleID;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "company_id")
private Company companyID;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "direction_id")
private Direction directions ;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "level_id")
private Levels levelID;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "referent_id")
private User referentID;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "role_id")
private Role roleID;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "task_id")
private EmployeeTask taskID;
}
the controller class, for configure the endpoint and the necessary method
#RestController
#RequestMapping("/user")
#Log
public class UserController {
private static final Logger logger = LoggerFactory.getLogger(UserController.class);
#Autowired
UserService userService;
#GetMapping(value = "/cerca/{registration_number}", produces = "application/json")
public ResponseEntity<UserDto> listUserByRegistrationNumber(#PathVariable("registration_Number") String registrationNumber)
throws ChangeSetPersister.NotFoundException
{
log.info("****** Ottengo l'user con numeroRegistrazione " + registrationNumber + " *******");
UserDto user = userService.SelByRegistrationNumber(registrationNumber);
if (user == null)
{
String ErrMsg = String.format("L'user con numeroRegistrazione %s non è stato trovato!", registrationNumber);
log.warning(ErrMsg);
throw new ChangeSetPersister.NotFoundException();
}
return new ResponseEntity<UserDto>(user, HttpStatus.OK);
}
}
the dto class
#Data
public class UserDto {
private Long userId;
private LocalDateTime createdDate;
private Long number;
private LocalDateTime modifiedDate;
private String birthPlace;
private Date birthDay;
private Long canNominate;
private String email;
private String firstName;
private String fiscalCode;
private Date hiringDate;
private String lastName;
private String matricola;
private String position;
private String registrationNumber;
private Long replaced;
private Date terminationDate;
private String userStatus;
private Role applicationRoleID;
private Company companyID;
private Direction directions ;
private Levels levelID;
private User referentID;
private Role role;
the repository class
public interface UserRepository extends PagingAndSortingRepository<User, Long> {
#Query(value = "SELECT * FROM USERS WHERE REGISTRATION_NUMBER LIKE :registrationNumber", nativeQuery = true)
List<User> findByRegistrationNumberLike(#Param("registrationNumber") String registrationNumber);
User findByRegistrationNumber(String registrationNumber);
}
the service interface and serviceImpl
public interface UserService {
public Iterable<User> SelTutti();
public List<User> SelByRegistrationNumberLike(String registrationNumber);
public UserDto SelByRegistrationNumber(String registrationNumber);
}
#Service
public class UserServiceImpl implements UserService{
#Autowired
UserRepository userRepository;
#Autowired
ModelMapper modelMapper;
#Override
public Iterable<User> SelTutti() {
return userRepository.findAll();
}
#Override
public List<User> SelByRegistrationNumberLike(String registrationNumber) {
return userRepository.findByRegistrationNumberLike(registrationNumber);
}
#Override
public UserDto SelByRegistrationNumber(String registrationNumber) {
User user = userRepository.findByRegistrationNumber(registrationNumber);
UserDto userDto = null;
if (user != null)
{
userDto = modelMapper.map(user, UserDto.class);
userDto.setMatricola(userDto.getMatricola().trim());
userDto.setUserStatus(userDto.getUserStatus().trim());
}
return userDto;
}
and model map config
#Configuration
public class ModelMapConfig {
#Bean
public ModelMapper modelMapper(){
return new ModelMapper();
}
}
There is a typo in your controller:
//...
#GetMapping(value = "/cerca/{registration_number}", produces = "application/json")
public ResponseEntity<UserDto> listUserByRegistrationNumber(#PathVariable("registration_Number") String registrationNumber)
//...
Note: one time #PathVariable("registration_Number") is spelled with a capital 'N' and one time with lower case 'n': #GetMapping(value = "/cerca/{registration_number}"
Both must be the same.
Your mapping is:
/cerca/{registration_number}
So you have to call the microservices like this:
http://localhost:8080/cerca/<a valid registration number>
Related
I developed a microservice and when I go to get to postman ( http://localhost:8080/user/utenti/ ) I get this error InvalidDefinitionException No serializer found for class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor and no properties discovered create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: java.util.ArrayList[0]->com.application.dto.UserDto["applicationRoleID"]->com.poste.anagrafica.entity.Role$HibernateProxy$N0iZZA2I["hibernateLazyInitializer"])
Can you help me please?
For clarity I enclose the schema of the database and the classes entity , dto and controller
The Entity classes
"""
#Entity
#Table(name = "USERS")
#Data
#NoArgsConstructor
#AllArgsConstructor
#Getter
#Setter
public class User implements Serializable {
#Id
#Column(name = "user_id", nullable = false)
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "created_date")
private LocalDateTime createdDate;
#Column(name = "deleted", nullable = false)
private Long number;
#Column(name = "modified_date")
private LocalDateTime modifiedDate;
#Column(name = "birth_place")
private String birthPlace;
#Column(name = "birthday")
private Date birthDay;
#Column(name = "canNominate")
private Long canNominate;
#Column(name = "email")
private String email;
#Column(name = "firstName")
private String firstName;
#Column(name= "fiscalCode")
private String fiscalCode;
#Column(name = "hiringDate")
private Date hiringDate;
#Column(name ="last_name")
private String lastName;
#Column(name = "matricola")
private String matricola;
#Column(name = "position")
private String position;
#Column(name = "registration_number")
private String registrationNumber;
#Column(name = "replaced")
private Long replaced;
#Column(name = "terminationDate")
private Date terminationDate;
#Column(name = "user_status")
private String userStatus;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "application_role_id")
private Role applicationRoleID;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "company_id")
private Company companyID;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "direction_id")
private Direction directions ;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "level_id")
private Levels levelID;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "referent_id")
private User referentID;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "role_id")
private Role roleID;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "task_id")
private EmployeeTask taskID;
}
"""
the UserDTO class
"""
#Data
public class UserDto {
private Long userId;
private LocalDateTime createdDate;
private Long number;
private LocalDateTime modifiedDate;
private String birthPlace;
private Date birthDay;
private Long canNominate;
private String email;
private String firstName;
private String fiscalCode;
private Date hiringDate;
private String lastName;
private String matricola;
private String position;
private String registrationNumber;
private Long replaced;
private Date terminationDate;
private String userStatus;
private Role applicationRoleID;
private Company companyID;
private Direction directions ;
private Levels levelID;
private User referentID;
private Role role;
private EmployeeTask taskID;
}
"""
the controller class
"""
#RestController
#RequestMapping("/user")
#Log
public class UserController {
private static final Logger logger = LoggerFactory.getLogger(UserController.class);
#Autowired
UserService userService;
#GetMapping(value = "/cerca/{registration_number}", produces = "application/json")
public ResponseEntity<List<UserDto>> listUserByRegistrationNumber(#PathVariable("registration_number") String registrationNumber)
throws ChangeSetPersister.NotFoundException
{
log.info("****** Ottengo l'user con numeroRegistrazione " + registrationNumber + " *******");
List<UserDto> user = userService.SelByRegistrationNumber(registrationNumber);
return new ResponseEntity<List<UserDto>>(user, HttpStatus.OK);
}
#GetMapping(value = "/utenti", produces = "application/json")
public ResponseEntity<List<UserDto>> listAllUsers ()throws ChangeSetPersister.NotFoundException{
List<UserDto> user = userService.SelTutti();
return new ResponseEntity<List<UserDto>>(user, HttpStatus.OK);
}
}
"""
the application.properties
"""
spring.datasource.url = jdbc:oracle:thin:#192.134.2.82:1521/orcl
spring.datasource.username =admin
spring.datasource.password =zzzx
spring.datasource.driver-class-name=oracle.jdbc.OracleDriver
# JPA settings
spring.jpa.database-platform=org.hibernate.dialect.Oracle12cDialect
spring.jpa.hibernate.use-new-id-generator-mappings=false
spring.jpa.hibernate.ddl-auto=update
spring.jpa.hibernate.naming.implicit- strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
"""
You can try
spring.jackson.serialization.fail-on-empty-beans=false
in your application.properties.
I have two models that are having one to many relation (customers have many invoices)
so i create one - many relation on it, this is my customer class :
#Entity
#Table(name = "customer")
public class Customer {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private int id;
#Column(name = "serial_number")
private long serialNumber;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
#Column(name = "email")
private String email;
#Column(name = "mobile_number")
private String mobileNumber;
#Column(name = "is_deleted")
private boolean isDeleted;
#OneToMany
private Set <Invoice> invoices;
}
and this is invoices class :
#Entity
#Table(name = "invoice")
public class Invoice {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private int id;
#Column(name = "serial_number")
private long serialNumber;
#Column(name = "status")
private String status;
#Column(name = "created_date")
private Timestamp createdDate;
#Column(name = "is_deleted")
private boolean isDeleted;
#ManyToOne
#JoinColumn(name = "customer_id")
private Customer customer;
}
and then i create GET API ( get customers ) but it's nor working and return this error :
nested exception is com.fasterxml.jackson.databind.JsonMappingException: could not extract ResultSet (through reference chain: java.util.ArrayList[0]->com.example.invoices.model.Customer["invoices"]), path=/customer/viewList}]
and this is my api :
public List<Customer> getAllCustomers() {
List<Customer> customers = cutomerRepository.findAll();
return customers;
}
and controller :
#GetMapping("/viewList")
public ResponseEntity<List<Customer>> getAllCustomers() {
List<Customer> customers = new ArrayList<>();
customers = customerService.getAllCustomers();
if (customers.isEmpty()) {
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
return new ResponseEntity<>(customers, HttpStatus.OK);
}
You have a Bidirectional relation and therefore an endless loop if json tries to deserialize the Object.
You can use #JsonIgnore to break the loop or use DTOs to return at the endpoint
#Entity
#Table(name = "invoice")
public class Invoice {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private int id;
#Column(name = "serial_number")
private long serialNumber;
#Column(name = "status")
private String status;
#Column(name = "created_date")
private Timestamp createdDate;
#Column(name = "is_deleted")
private boolean isDeleted;
#ManyToOne
#JsonIgnore
#JoinColumn(name = "customer_id")
private Customer customer;
}
DTO would look something like this (I like to use records for this but since I don't know if you use Java 17 I still use class):
Customer:
#Data
public class CustomerDTO {
private final int id;
private final long serialNumber;
private final String firstName;
private final String lastName;
private final String email;
private final String mobileNumber;
private final boolean isDeleted;
private final Set <Invoice> invoices;
public static CustomerDTO fromModel(Customer customer) {
return new CustomerDTO(
customer.getId(),
customer.getSerialNumber(),
customer.getFirstName(),
customer.getLastName(),
customer.getEmail(),
customer.getMobileNumber(),
customer.isDeleted(),
customer.getInvoices()
.stream()
.map(InvoiceDTO::fromModel)
.collect(Collectors.toSet())
);
}
}
Invoice (here you don't show the customer again):
#Data
public class InvoiceDTO {
private final int id;
private final String status;
private final Timestamp createdDate;
private final boolean isDeleted;
public static InvoiceDTO fromModel(Invoice invoice) {
return new InvoiceDTO(
invoice.getId(),
invoice.getStatus(),
invoice.getCreatedDate(),
invoice.isDeleted()
);
}
}
Controller:
#GetMapping("/viewList")
public ResponseEntity<List<CustomerDTO>> getAllCustomers() {
List<CustomerDTO> customers = new ArrayList<>();
customers = customerService.getAllCustomers()
.stream()
.map(CustomerDTO::fromModel)
.toList() //Depending on Java Version .collect(Collectors.toList());
if (customers.isEmpty()) {
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
return new ResponseEntity<>(customers., HttpStatus.OK);
}
Do not open the entity class directly to the outside world
As DTO use for example:
public class InvoiceDTO {
private int id;
private long serialNumber;
private String status;
private Timestamp createdDate;
private boolean isDeleted;
private CustomerDTO customer;
}
See it applied in my GitHub repo FurnitureStoreApplication, example DTO classes in package dto:
I am currently trying to update a Record which contains an Embedded Entity. When trying this, i am getting the following Error:
Request processing failed; nested exception is java.lang.RuntimeException: java.lang.StackOverflowError
When i create the Entity, everything is working fine.
This is what i have right now:
My Main Entity:
#Entity(name = "Account")
#Table(name = "account")
#DynamicUpdate
#NoArgsConstructor
#AllArgsConstructor
#Getter
#Setter
public class Account extends Auditable<String> {
#Id
#Column(name = "Id")
private String id;
#Column(
name = "Description",
length = 512)
private String description;
#Column(
name = "AnnualRevenue",
length = 18)
private String annualRevenue;
#Embedded
#AttributeOverrides(value = {
#AttributeOverride(name = "city", column = #Column(name = "billingAddressCity")),
#AttributeOverride(name = "country", column = #Column(name = "billingAddressCountry")),
#AttributeOverride(name = "latitude", column = #Column(name = "billingAddressLatitude")),
#AttributeOverride(name = "longitude", column = #Column(name = "billingAddressLongitude")),
#AttributeOverride(name = "postalCode", column = #Column(name = "billingAddressPostalCode")),
#AttributeOverride(name = "state", column = #Column(name = "billingAddressState")),
#AttributeOverride(name = "street", column = #Column(name = "billingAddressStreet"))
})
private Address billingAddress;
#Column(name = "Industry")
private String industry;
#Column(name = "IsDeleted")
private boolean isDeleted;
#Column(
name = "Employees",
length = 8
)
private int employees;
#Column(name = "Name")
private String name;
#Column(name = "Phone")
private String phone;
#Column(name = "Type")
private String type;
#Column(name = "Website")
private String website;
#OneToMany(
orphanRemoval = true,
fetch = FetchType.LAZY,
cascade = {
CascadeType.ALL
}
)
#JsonIgnoreProperties("account")
private final List<Contact> contacts = new ArrayList<>();
}
Here, i am using an Embedded Entity for the Address which looks like this:
#Embeddable
#NoArgsConstructor
#AllArgsConstructor
#Getter
#Setter
public class Address {
private String city;
private String country;
private Double latitude;
private Double longitude;
private String postalCode;
private String state;
private String street;
}
Furthermore, the Account can have multiple Contacts which is is defined like this:
#Entity(name = "Contact")
#Table(name = "contact")
#NoArgsConstructor
#AllArgsConstructor
#Getter
#Setter
#JsonInclude
public class Contact extends Auditable<String> {
#Id
#Column(name = "Id")
private String id;
#Column(name = "Department")
private String department;
#Column(
name = "Email"
)
private String email;
#Column(name = "FirstName")
private String firstName;
#Column(name = "Name")
private String name;
#Column(name = "Salutation")
private String salutation;
#ManyToOne
#JoinColumn(
name = "accountId",
nullable = false,
referencedColumnName = "Id",
foreignKey = #ForeignKey(
name = "AccountContactFK"
)
)
#JsonIgnoreProperties("contacts")
private Account account;
}
For the Account, i am using the DTO Principle to map the Fields which looks like this:
DTO for Creation:
#Getter
#Setter
public class AccountCreationDTO {
private String description;
private String annualRevenue;
private Address billingAddress;
private String industry;
private boolean isDeleted;
private int employees;
private String name;
private String phone;
private String type;
private String website;
}
DTO for Update:
#Getter
#Setter
public class AccountUpdateDTO {
#Id
private String id;
private String description;
private String annualRevenue;
#Embedded
private Address billingAddress;
private String industry;
private boolean isDeleted;
private int employees;
private String name;
private String phone;
private String type;
private String website;
}
And here is my Controller:
#RestController
#RequestMapping("/api/v1")
#RequiredArgsConstructor
#Slf4j
public class AccountController {
private final AccountRepository accountRepository;
#RequestMapping(value = "/createAccount", method = RequestMethod.POST)
public Account createObject(#RequestBody #DTO(AccountCreationDTO.class) Account account) {
//account.setBillingAddress(account.getBillingAddress());
//this.addressRepository.save(account.getBillingAddress());
Account createdAccount = this.accountRepository.saveAndFlush(account);
log.info("Created Account: {}", createdAccount);
return createdAccount;
}
#PutMapping(value = "/updateAcc")
public ResponseEntity<Account> updateAccount(#DTO(AccountUpdateDTO.class) Account account) {
Account updatedAccount = this.accountRepository.saveAndFlush(account);
log.info("Updated Account: {}", updatedAccount);
return ResponseEntity.ok().body(updatedAccount);
}
}
I have three entities with bi-directional Many-To-One mapping:
#MappedSuperclass
#Getter
#Setter
abstract class Media {
#Id
#Column
#GeneratedValue(strategy = GenerationType.SEQUENCE)
protected Long id;
#Column(name = "imdb_id")
private String imdbId;
#Column(name = "api_movie_id")
private String apiMovieId;
#Column
private Long metadataItemIdentity;
#Column
protected String title;
#Column(name = "original_title")
protected String originalTitle;
#Column
protected String studio;
#Column
protected Double rating;
#Column(length = 500)
protected String description;
#Column(name = "content_rating")
protected String contentRating;
#Column
protected String genres;
#Column
protected String director;
#Column
protected Long duration;
#Column
protected String writer;
#Column
protected String stars;
#Column(name = "year_of_release")
protected Integer year;
#Column(name = "country_code")
protected String countryCode;
#Column(name = "is_ok")
protected boolean isOk = true;
#Column(name = "audio_lang")
protected String audioLanguage = "";
#Column(name = "sub_lang")
protected String subtitlesLanguage = "";
#Column(name = "api_name")
protected String apiName;
}
#Entity(name = "seasons")
#Getter
#Setter()
#Builder
#AllArgsConstructor
#NoArgsConstructor
public class Season {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
#Column
protected Long id;
#Column
private Long metadataItemIdentity;
#ManyToOne
#JoinColumn(name = "fk_series")
private Series series;
#OneToMany(mappedBy = "season", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
private List<Episode> episodes;
private Integer number;
}
#Entity(name = "series")
#Getter
#Setter
#Builder
#AllArgsConstructor
#NoArgsConstructor
public class Series extends Media {
#OneToMany(mappedBy = "series", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
List<Season> seasons;
}
And now the logic for saving:
#Service
#Slf4j
public class SeriesMigrateServiceImpl implements SeriesMigrateService {
private final SeriesService seriesService;
private final MetaDataItemRepository metaDataItemRepository;
private final ModelMapper modelMapper;
#Autowired
public SeriesMigrateServiceImpl(SeriesService seriesService,
MetaDataItemRepository metaDataItemRepository,
ModelMapper modelMapper) {
this.seriesService = seriesService;
this.metaDataItemRepository = metaDataItemRepository;
this.modelMapper = modelMapper;
}
#Override
public void migrateSeries() {
List<Series> allSeries = this.getAllSeriesFromSqlite();
allSeries.forEach(this::populateSeasons);
seriesService.saveSeries(allSeries);
}
private void populateSeasons(Series series) {
List<Season> allSeasons = this.getAllSeasonsForSeriesFromSqlite(series);
allSeasons.forEach(season -> season.setSeries(series));
allSeasons.forEach(this::populateEpisodes);
series.setSeasons(allSeasons);
}
private void populateEpisodes(Season season) {
List<Episode> allEpisodes = this.getAllEpisodesForSeasonFromSqlite(season);
allEpisodes.forEach(episode -> episode.setSeason(season));
season.setEpisodes(allEpisodes);
}
private List<Series> getAllSeriesFromSqlite() {
return metaDataItemRepository
.findAllSeries().stream()
.map(item -> this.convert(item, Series.class))
.collect(Collectors.toList());
}
private List<Season> getAllSeasonsForSeriesFromSqlite(Series series) {
return metaDataItemRepository
.findAllByParentIdentityAndMetadataType(series.getMetadataItemIdentity(), 3).stream()
.map(item -> this.convert(item, Season.class))
.collect(Collectors.toList());
}
private List<Episode> getAllEpisodesForSeasonFromSqlite(Season season) {
return metaDataItemRepository
.findAllByParentIdentityAndMetadataType(season.getMetadataItemIdentity(), 4).stream()
.map(item -> this.convert(item, Episode.class))
.collect(Collectors.toList());
}
private <T> T convert(MetaDataItem item, Class<T> classType) {
return modelMapper.map(item, classType);
}
}
What happens is that sometimes Hibernate saves twice the entities for example if i have 840 media files Hibernate saves 1680 ? And the thing that bothers me most is that sometimes works correctly sometimes doesn't ? Any suggestions?
*EDIT
#Service
public class SeriesServiceImpl implements SeriesService {
private final SeriesRepository seriesRepository;
#Autowired
public SeriesServiceImpl(SeriesRepository seriesRepository) {
this.seriesRepository = seriesRepository;
}
#Override
#Transactional
public List<Series> saveSeries(List<Series> series) {
return seriesRepository.save(series);
}
}
I have been using many to many mapping here is my POJO classes.
Menu.java :
#Entity
#Table(name = "menu")
public class Menu {
#Id
#Column(name = "menuid")
#GeneratedValue
private int menuid;
#Column(name = "parentid")
private int parentid;
#Column(name = "menuname")
private String menuname;
#Column(name = "url")
private String url;
#Column(name = "status")
private String status;
#Column(name = "usertype")
private String usertype;
#Column(name = "isparent")
private boolean isParent;
private ArrayList<Menu> childMenu;
#ManyToMany(mappedBy="menus")
private List<User> users;
public Menu(Integer menuid){
this.menuid=menuid;
}
public Menu(){
}
User.java :
#Entity
#Table(name = "user")
public class User implements Serializable {
#Id
#Column(name = "userid")
#GeneratedValue
private Integer userId;
#Column(name = "OUTLET_ID")
private int outletId;
#Column(name = "NAME")
private String name;
#Column(name = "USERTYPE")
private String userType;
#Column(name = "LOGINID")
private String loginId;
#Column(name = "PASSWORD")
private String password;
#Column(name = "CREATEDDATE")
private String createdDate;
#Column(name = "CONTACTNUMBER")
private String contactNumber;
#Column(name = "EMAILID")
private String emailId;
#Column(name = "OUTLETTYPE")
private String outlettype;
#Transient
private String nsec;
#javax.persistence.Transient
ArrayList<Integer> menuid;
#javax.persistence.Transient
ArrayList<Long> clientid;
#javax.persistence.Transient
ArrayList<String> clientName;
#ManyToMany(fetch=FetchType.EAGER) #JsonIgnore
#JoinTable(name="user_menu",joinColumns={#JoinColumn(name="userid")},
inverseJoinColumns={#JoinColumn(name="menuid")})
public List<Menu> menus;
#ManyToMany(fetch=FetchType.EAGER) #JsonIgnore
#JoinTable(name="user_client",joinColumns={#JoinColumn(name="userid")},
inverseJoinColumns={#JoinColumn(name="outletid")})
public List<Client> clients;
public User() {
}
I have user,menu and third mapping table user_menu which is created automatically, I successfully get result when fire following query in mysql
select * from menu m inner join user_menu um on m.menuid = um.menuid where um.userid = 41;
I want to write this query in hibernate how to this stuff ???
Finally I find my answer, here is my hql query,
String sql = "select m.menuid as menuid,m.parentid as parentid,m.menuname as menuname,m.url as url,m.status as status,m.usertype as usertype,m.isParent as isParent,m.childMenu as childMenu from Menu m join m.users u where u.userId = "+userid +"";
q = session.createQuery(sql).setResultTransformer(Transformers.aliasToBean(Menu.class));