SpringBoot microservice InvalidDefinitionException - java

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.

Related

Spring Boot Microservice Intellij don't work

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>

get API in spring boot with one to many relation

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:

Update Spring Embedded Entity throws Stack Overflow Entity

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);
}
}

Hibernate, Spring. Multiple representations of the same entity are being merged

I have been getting an error while trying to update a list of entities (Job):
Multiple representations of the same entity [com.introlabsystems.upworkscraper.model.entities.Skill#42] are being merged. Detached: [Skill(id=42, skillName=Web Scraping)]; Detached: [Skill(id=42, skillName=Web Scraping)]
I think it is in case that three entities have ManyToMany relationship with Skill entity.
#Entity
public class Job {
#Id
#Column(unique = true, nullable = false)
#SerializedName(value = "ciphertext")
private String id;
#Column(length = 2048)
private String title;
#Column(columnDefinition = "TEXT")
#JsonAdapter(value = DescriptionAdapter.class)
private String description;
#SerializedName(value = "subcategory2")
private String category;
#ManyToMany(cascade = {
CascadeType.MERGE
}, fetch = FetchType.EAGER)
#JoinTable(
joinColumns = {#JoinColumn(name = "job_id")},
inverseJoinColumns = {#JoinColumn(name = "skill_id")}
)
#JsonAdapter(value = SkillsAdapter.class)
private Set<Skill> skills;
private String duration;
private String engagement;
#JsonAdapter(value = AmountAdapter.class)
private String amount;
#JsonAdapter(value = AmountAdapter.class)
private String maxAmount;
private String freelancersToHire;
private String enterpriseJob;
private String proposalsTier;
private String stickyLabel;
#SerializedName(value = "tierLabel")
private String tier;
#JsonAdapter(value = DateTimeAdapter.class)
private LocalDateTime createdOn;
#JsonAdapter(value = DateTimeAdapter.class)
private LocalDateTime publishedOn;
#JsonAdapter(value = DateTimeAdapter.class)
private LocalDateTime renewedOn;
private LocalDateTime hiredOn;
#OneToOne(cascade = CascadeType.ALL)
private Contract contract;
#SerializedName(value = "type")
#JsonAdapter(value = JobTypeAdapter.class)
#Enumerated(value = EnumType.STRING)
private JobType jobType;
#Enumerated(value = EnumType.STRING)
private JobStatus jobStatus = JobStatus.OPEN;
private String projectStage;
private String ongoingProject;
private String projectType;
private String finalOutput;
private String Platform;
private String oneTimeProject;
private String jobSuccessScore;
private String includeRisingTalent;
private String englishLevel;
private String upworkHours;
private String freelancerType;
private String preferredLocation;
private String interviewing;
#OneToOne(cascade = CascadeType.ALL)
private PrivateStatus privateStatus;
}
#Data
#Entity
public class Skill {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String skillName;
}
#Data
#Entity
public class Contract {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#JsonAdapter(value = ContractJobIdAdapter.class)
#SerializedName(value = "jobInfo")
private String jobId;
private String totalCharge;
private String totalHours;
#JsonAdapter(value = AmountAdapter.class)
private String rate;
#JsonAdapter(value = DateTimeAdapter.class)
private LocalDateTime startDate;
#JsonAdapter(value = DateTimeAdapter.class)
private LocalDateTime endDate;
#ManyToOne(cascade = CascadeType.MERGE)
#SerializedName(value = "contractorInfo")
private Freelancer freelancer;
#ManyToOne(cascade = CascadeType.ALL)
private Client client;
}
#Data
#Entity
public class Freelancer {
#Id
#SerializedName(value = "ciphertext")
private String id;
#SerializedName(value = "contractorName")
private String name;
#Column(length = 2048)
private String title;
#Column(columnDefinition = "TEXT")
#JsonAdapter(value = DescriptionAdapter.class)
private String description;
#JsonAdapter(value = FreelancerLocationAdapter.class)
private String location;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(
joinColumns = {#JoinColumn(name = "freelancer_id")},
inverseJoinColumns = {#JoinColumn(name = "skill_id")}
)
#JsonAdapter(value = SkillsAdapter.class)
private Set<Skill> skills;
private String hourlyRate;
private String privateFeedbackHireAgain;
private String rating;
private String scores;
private String totalEarnings;
private String totalFeedback;
private String totalFixedJobs;
private String totalHourlyJobs;
private String totalHours;
private String totalJobsWorked;
private String topRatedStatus;
private String successScore;
#OneToMany(cascade = CascadeType.ALL)
private List<ContractHistory> contractHistories;
#ManyToMany(cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
})
#JoinTable(
joinColumns = {#JoinColumn(name = "freelancer_id")},
inverseJoinColumns = {#JoinColumn(name = "agency_id")}
)
private Set<Agency> agency;
}
#Data
#Entity
public class Agency {
#Id
#SerializedName(value = "chipertext")
private String id;
#JsonAdapter(value = AmountAdapter.class)
private String minRate;
#JsonAdapter(value = AmountAdapter.class)
private String maxRate;
private String city;
private String country;
#Column(columnDefinition = "TEXT")
#JsonAdapter(value = DescriptionAdapter.class)
private String description;
private String jobSuccessScore;
private String name;
#Column(length = 2048)
private String title;
private String topRatedStatus;
private String totalEarnings;
private String totalHours;
private String totalJobs;
private String recentEarnings;
private String averageRecentEarnings;
#JsonAdapter(value = DateTimeAdapter.class)
private LocalDateTime memberSince;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(
joinColumns = {#JoinColumn(name = "agency_id")},
inverseJoinColumns = {#JoinColumn(name = "skill_id")}
)
#JsonAdapter(value = SkillsAdapter.class)
private Set<Skill> skills;
}
I trying to save a job. Before do it I get skills from job, agency, freelancer, trying to search them in DB and substitute ids.
for (Skill skill: skills)
{
Skill skillWithID =
skillDataService.findBySkillName(skill.getSkillName())
.orElseGet(() -> skillDataService.save(skill));
skill.setId(skillWithID.getId());
}
Changed
CascadeType.MERGE
to
CascadeType.PERSIST,
CascadeType.DETACH,
CascadeType.REFRESH,
CascadeType.REMOVE
and it works
you are facing this issue because you are adding the object to the list which is already available.while performing save operation with oneToMany mapping
Now removing CascadeType.MERGE from cascade is one solution but not a best solution because after removing MERGE from Cascade you won't be able to update the mapped object ever
If you want to perform update operation also along with save for the mapped objects then before adding mapped object to list/collection just check/search within the list for the object and if the mapped object is available within the list then perform operation on that particular object.
check my other post for example

Hibernate query on many to many mapping

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));

Categories

Resources