I'm having a strange problem with a spring boot endpoint that calls JpaRepository findById(). When ever I send a GET request to the endpoint /v1/goals/{id} a stack overflow error occurs, while GET requests to /v1/goals work fine.
Edit: added the error message to the bottom
Simplified Controller class:
#RestController
public class GoalController {
private final GoalServiceImpl service;
#Autowired
GoalController(GoalServiceImpl service) { this.service = service; }
#GetMapping("/v1/goals")
ResponseEntity<List<Goal>> allGoals() { return new ResponseEntity<>(service.getGoals(), HttpStatus.OK); }
#GetMapping("/v1/goals/{id}")
ResponseEntity<String> singleGoal(#PathVariable Long id) {
return new ResponseEntity<>(service.getGoalById(id).toString(), HttpStatus.OK);
}
}
Simplified Service class:
#Service
public class GoalServiceImpl implements GoalService {
private final GoalRepository repository;
#Autowired
public GoalServiceImpl(GoalRepository repository) { this.repository = repository; }
public Goal getGoalById(Long id) {
return repository
.findById(id)
.orElseThrow(() -> new GoalNotFoundException(id));
}
public List<Goal> getGoals() { return repository.findAll(); }
}
Simplified Entity class:
#NoArgsConstructor
#Data
#Entity
public class Goal {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long goalId;
#ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "user_id")
#JsonIgnore
private User user;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "goal")
#JsonIgnoreProperties(value = "goal")
private List<Milestone> milestones;
}
Simplified Milestone Entity:
#NoArgsConstructor
#Data
#Entity
public class Milestone {
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
private Long milestone_id;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "user_id")
#JsonIgnore
private User user;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "goal_id")
private Goal goal;
Simplified User Entity:
#NoArgsConstructor
#Data
#Entity
public class User {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long userId;
private String name;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "user")
#JsonIgnoreProperties(value = "user")
private List<Goal> goals;
}
Error message:
java.lang.StackOverflowError: null
at org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor.intercept(ByteBuddyInterceptor.java:56) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.proxy.ProxyConfiguration$InterceptorDispatcher.intercept(ProxyConfiguration.java:95) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at com.motivate.api.user.User$HibernateProxy$KaIclPZ9.toString(Unknown Source) ~[classes/:na]
at java.base/java.lang.String.valueOf(String.java:2951) ~[na:na]
at com.motivate.api.goal.Goal.toString(Goal.java:16) ~[classes/:na]
at java.base/java.lang.String.valueOf(String.java:2951) ~[na:na]
at java.base/java.lang.StringBuilder.append(StringBuilder.java:168) ~[na:na]
at java.base/java.util.AbstractCollection.toString(AbstractCollection.java:473) ~[na:na]
at org.hibernate.collection.internal.PersistentBag.toString(PersistentBag.java:622) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at java.base/java.lang.String.valueOf(String.java:2951) ~[na:na]
at com.motivate.api.user.User.toString(User.java:11) ~[classes/:na]
at jdk.internal.reflect.GeneratedMethodAccessor58.invoke(Unknown Source) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor.intercept(ByteBuddyInterceptor.java:56) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.proxy.ProxyConfiguration$InterceptorDispatcher.intercept(ProxyConfiguration.java:95) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at com.motivate.api.user.User$HibernateProxy$KaIclPZ9.toString(Unknown Source) ~[classes/:na]
Solution
provided by Chris and PaulD in the comments:
#GetMapping("/v1/goals/{id}")
ResponseEntity<Goal> singleGoal(#PathVariable Long id) {
return new ResponseEntity<>(service.getGoalById(id), HttpStatus.OK);
}
Remove the toString() as that causes the whole object to be serialised by lombok which doesn't take into account the jackson annotations. Change ResponseEntity to be of type Goal and pass in the whole entity.
Related
I am reading 5gb of XML file using the below code and processing that data into Database using spring dataJpa, this below is just sample logic we are closing the inpustream and aswell xsr object.
XMLInputFactory xf=XMLInputFactory.newInstance();
XMLStreamReader xsr=xf.createXMLStreamReader(new InputStreamReader(new FileInputStream("test.xml"))
i have configured the max 8GB(ie -xms7000m and -xmx8000m) of heap memory But its getting the below hibernate heap issue when saving the data. it inserted around 700000 data total of 2100000
[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.lang.OutOfMemoryError: Java heap space] with root cause
java.lang.OutOfMemoryError: Java heap space
at java.base/java.util.IdentityHashMap.resize(IdentityHashMap.java:472) ~[na:na]
at java.base/java.util.IdentityHashMap.put(IdentityHashMap.java:441) ~[na:na]
at org.hibernate.event.internal.DefaultPersistEventListener.entityIsPersistent(DefaultPersistEventListener.java:159) ~[hibernate-core-5.4.22.Final.jar:5.4.22.Final]
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:124) ~[hibernate-core-5.4.22.Final.jar:5.4.22.Final]
at org.hibernate.internal.SessionImpl$$Lambda$1620/0x00000008010a3040.applyEventToListener(Unknown Source) ~[na:na]
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:113) ~[hibernate-core-5.4.22.Final.jar:5.4.22.Final]
at org.hibernate.internal.SessionImpl.persistOnFlush(SessionImpl.java:765) ~[hibernate-core-5.4.22.Final.jar:5.4.22.Final]
at org.hibernate.engine.spi.CascadingActions$8.cascade(CascadingActions.java:341) ~[hibernate-core-5.4.22.Final.jar:5.4.22.Final]
at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:492) ~[hibernate-core-5.4.22.Final.jar:5.4.22.Final]
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:416) ~[hibernate-core-5.4.22.Final.jar:5.4.22.Final]
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:218) ~[hibernate-core-5.4.22.Final.jar:5.4.22.Final]
at org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:525) ~[hibernate-core-5.4.22.Final.jar:5.4.22.Final]
at org.hibernate.engine.internal.Cascade.cascadeCollection(Cascade.java:456) ~[hibernate-core-5.4.22.Final.jar:5.4.22.Final]
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:419) ~[hibernate-core-5.4.22.Final.jar:5.4.22.Final]
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:218) ~[hibernate-core-5.4.22.Final.jar:5.4.22.Final]
at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:151) ~[hibernate-core-5.4.22.Final.jar:5.4.22.Final]
at org.hibernate.event.internal.AbstractFlushingEventListener.cascadeOnFlush(AbstractFlushingEventListener.java:158) ~[hibernate-core-5.4.22.Final.jar:5.4.22.Final]
at org.hibernate.event.internal.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:148) ~[hibernate-core-5.4.22.Final.jar:5.4.22.Final]
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:81) ~[hibernate-core-5.4.22.Final.jar:5.4.22.Final]
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39) ~[hibernate-core-5.4.22.Final.jar:5.4.22.Final]
at org.hibernate.internal.SessionImpl$$Lambda$1597/0x0000000801076040.accept(Unknown Source) ~[na:na]
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:102) ~[hibernate-core-5.4.22.Final.jar:5.4.22.Final]
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1362) ~[hibernate-core-5.4.22.Final.jar:5.4.22.Final]
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:453) ~[hibernate-core-5.4.22.Final.jar:5.4.22.Final]
at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3212) ~[hibernate-core-5.4.22.Final.jar:5.4.22.Final]
at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2380) ~[hibernate-core-5.4.22.Final.jar:5.4.22.Final]
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:447) ~[hibernate-core-5.4.22.Final.jar:5.4.22.Final]
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:183) ~[hibernate-core-5.4.22.Final.jar:5.4.22.Final]
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$300(JdbcResourceLocalTransactionCoordinatorImpl.java:40) ~[hibernate-core-5.4.22.Final.jar:5.4.22.Final]
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:281) ~[hibernate-core-5.4.22.Final.jar:5.4.22.Final]
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:101) ~[hibernate-core-5.4.22.Final.jar:5.4.22.Final]
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:534) ~[spring-orm-5.2.10.RELEASE.jar:5.2.10.RELEASE]
As per the above trace logs it seems some issue with hibernate save casacade , but not able to figured out , below are the entity classes which uses to save the data in databse.
#Data
#EqualsAndHashCode
#Builder(toBuilder = true)
#NoArgsConstructor(access = AccessLevel.PRIVATE)
#AllArgsConstructor(access = AccessLevel.PRIVATE)
public class UMEnityPK implements Serializable {
private static final long serialVersionUID=1L;
private String batchId;
private Long batchVersion;
private BigInteger umId;
}
#Data
#Builder(toBuilder = true)
#NoArgsConstructor(access = AccessLevel.PRIVATE)
#AllArgsConstructor(access = AccessLevel.PRIVATE)
#EqualsAndHashCode(of = {"batchId", "batchVersion", "umId"})
#Entity
#Table(name ="um_base")
#IdClass(UMEnityPK.class)
public class UMBase {
#Id private String batchId;
#Id private Long batchVersion;
#Id private BigInteger umId;
private String firstName;
private String lastName;
private String umType;
private String umLevel;
#OneToMany(mappedBy = "umBase", cascade = CascadeType.ALL)
private List<UMAddress> umAddresses;
#OneToMany(mappedBy = "umBase", cascade = CascadeType.ALL)
private List<UMIdentifier> umIdentifiers;
#OneToOne(mappedBy = "umBase", cascade = CascadeType.ALL)
private UMHierarchy umHierarchy;
}
#Data
#Builder(toBuilder = true)
#NoArgsConstructor(access = AccessLevel.PRIVATE)
#AllArgsConstructor(access = AccessLevel.PRIVATE)
#EqualsAndHashCode(of = {"id"})
#Entity
#Table(name = "um_identifier")
public class UMIdentifier {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "um_address")
#SequenceGenerator(name = "um_address", sequenceName = "SEQ_UM_ADDRESS", allocationSize = 1)
private Long id;
private String idValue;
private String idType;
private String groupType;
#ManyToOne
#JoinColumns({
#JoinColumn(name = "BATCH_ID", referencedColumnName = "batchId"),
#JoinColumn(name = "BATCH_VERSION", referencedColumnName = "batchVersion"),
#JoinColumn(name = "UM_ID", referencedColumnName = "umId")
})
private UMBase umBase;
}
#Data
#Builder(toBuilder = true)
#NoArgsConstructor(access = AccessLevel.PRIVATE)
#AllArgsConstructor(access = AccessLevel.PRIVATE)
#EqualsAndHashCode(of = {"batchId", "batchVersion", "umId"})
#Entity
#Table(name ="um_hierarchy")
public class UMHierarchy {
#Id
private String batchId;
#Id private Long batchVersion;
#Id private BigInteger umId;
private String hierarchyTpe;
private String umStatusCode;
private String immediateParentId;
private Date hierarchyDate;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumns({
#JoinColumn(name = "BATCH_ID", referencedColumnName = "batchId"),
#JoinColumn(name = "BATCH_VERSION", referencedColumnName = "batchVersion"),
#JoinColumn(name = "UM_ID", referencedColumnName = "umId")
})
private UMBase umBase;
}
#Data
#Builder(toBuilder = true)
#NoArgsConstructor(access = AccessLevel.PRIVATE)
#AllArgsConstructor(access = AccessLevel.PRIVATE)
#EqualsAndHashCode(of = {"id"})
#Entity
#Table(name = "um_address")
public class UMAddress {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "um_address")
#SequenceGenerator(name = "um_address", sequenceName = "SEQ_UM_ADDRESS", allocationSize = 1)
private Long id;
private String addressType;
private String addressLine1;
private String getAddressLine2;
private String city;
private String state;
private String postalCode;
private String country;
#ManyToOne
#JoinColumns({
#JoinColumn(name = "BATCH_ID", referencedColumnName = "batchId"),
#JoinColumn(name = "BATCH_VERSION", referencedColumnName = "batchVersion"),
#JoinColumn(name = "UM_ID", referencedColumnName = "umId")
})
private UMBase umBase;
}
Is there any issues with hibernate entity mapping which eating of the memory
After checking the heap dump, the issue is with the org.hibernate.engine.StatefulPersistenceContext -> org.hibernate.util.IdentityMap memory leak , so used the below way and worked fine , create a custom JPARepository and have below sample method logic.
public <S extends T> void saveInBatch(Iterable<S> entities) {
if (entities == null) {
return;
}
EntityManager entityManager = entityManagerFactory.createEntityManager();
EntityTransaction entityTransaction = entityManager.getTransaction();
try {
entityTransaction.begin();
int i = 0;
for (S entity : entities) {
if (i % batchSize == 0 && i > 0) {
entityTransaction.commit();
entityTransaction.begin();
entityManager.clear();
}
entityManager.persist(entity);
i++;
}
entityTransaction.commit();
} catch (RuntimeException e) {
if (entityTransaction.isActive()) {
entityTransaction.rollback();
}
throw e;
} finally {
entityManager.close();
}
}
}
When dealing with converting datasets that big you need to do that in batches. Read 100 records from the xml, convert them to entities, save each of them with em.persist(record), then call em.flush() and em.clear() to remove them from Hibernate, then clear them from your local collection, then manually invoke the garbage collector using System.gc(). You may even want to use Hibernate's batch processing as described in this tutorial.
In pseudocode this would be:
boolean finished = false;
List<Entity> locals = new ArrayList<>(100);
while (!finished) {
for (int records = 0; records < 100; records++) {
Entity ent = readEntityFrom(xml);
// readEntity function must return null when no more remain to read
if (ent == null) {
finished = true;
break;
}
locals.add(ent);
}
for (Entity ent : locals) em.persist(ent);
em.flush(); // send any that are still waiting to the database
em.clear(); // remove references Hibernate holds to these entities
locals.clear(); // remove references we hold to these entities
// now all these entity references are weak and can be garbage-collected
System.gc(); // purge them from memory
}
Also you may want to manually begin and commit a transaction around each insert loop to ensure the database isn't holding everything for your entire import, or it might run out of memory instead of your java application.
I am trying to save Entity with one to many relation. It throws EntityNotFoundException when trying to save the entity
I did some research but not able to find any solution to this
Order Entity:
#Data
#Component
#Entity
#Slf4j
#Table (name = ORDER_TABLE_NAME)
public class OrderEntity {
//== Order Details
#Id
#GeneratedValue(generator = "uuid")
#GenericGenerator(name = "uuid", strategy = "uuid2")
#Column(name = ORDER_ID_COLUMN)
private String orderIdGuid;
#Column (name = ORDER_BOOKED_DATETIME_COLUMN)
private LocalDateTime orderBookedDate;
#Column(name = ORDER_STATUS_COLUMN)
private String orderStatus;
#OneToMany( cascade={CascadeType.ALL}, orphanRemoval = true)
#JoinColumn(name= ORDER_ID_COLUMN)
#Autowired
private List<ProductEntity> products;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = ORDER_ID_COLUMN)
private List<Followup> followups;
Product Entity:
#Data
#Component
#Entity
#Table (name=ORDER_PRODUCT_TABLE)
public class ProductEntity {
#Id
#GeneratedValue(generator = "uuid")
#GenericGenerator(name = "uuid", strategy = "uuid2")
#Column (name = PRODUCT_PRIMARY_ID)
private String product_primary_id;
//=== defined by constants
#Column(name = PRODUCT_NAME)
private String productName;
DAOClass:
#Component
#Data
#Slf4j
public class DAOOrderRepository {
#Autowired
OrderRepository orderRepository;
public void saveOrderEntity(OrderEntity orderEntity) {
orderEntity.setOrderUpdatedDate(LocalDate.now());
orderRepository.save(orderEntity);
}
public OrderEntity findOrderByOrderId(String orderId) {
return orderRepository.findOrderEntityByOrderIdGuid(orderId);
}
public List<OrderEntity> findAllOrdersByEmployeeId(String employeeId) {
return orderRepository.findBySalesRepEmployeeId(employeeId);
}
}
Repository:
#Repository
public interface OrderRepository extends JpaRepository<OrderEntity,String> {
List<OrderEntity> findBySalesRepEmployeeId(String employeeId);
OrderEntity findOrderEntityByOrderIdGuid(String orderIdGuid);
}
Exception:
org.springframework.orm.jpa.JpaObjectRetrievalFailureException: Unable to
find
com.app.apicore.Entities.OrderServiceEntity.ProductEntity.ProductEntity
with id 03350d2a-15cf-46da-ba2c-58aeec79db9a; nested exception is
javax.persistence.EntityNotFoundException: Unable to find
com.app.apicore.Entities.OrderServiceEntity.ProductEntity.ProductEntity
with id 03350d2a-15cf-46da-ba2c-58aeec79db9a
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:378)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:255)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:527)
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:153)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:138)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
at com.sun.proxy.$Proxy111.save(Unknown Source)
at com.app.apicore.Apis.DAOOrderRepository.saveOrderEntity(DAOOrderRepository.java:24)
Each order is a new order record. So when i try to save the order record for the first time, it saves the order data correct. It saves the order data correct for second time to. But on the third time throws exception.
When I want to use #Scheduled, it throws org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction
When I tried to use noRollbackFor=TransactionSystemException - it does not help either...
I even tried to use propagation=NEVER and then the code does not work,because it needs to be transactional. Iam getting those documents ok, but I cannot do blockDocument(document).
How to make it work?
Thank you in advance
#Component
public class ScheduleService {
#Autowired
private DocumentService documentService;
#Scheduled(cron = "0 33 13 * * ?")
public void blockPassedDocuments() {
List<Document> passedDocuments = documentService.getAllPassedDocuments();
if (passedDocuments != null) {
System.out.println("blocked docs "+ passedDocuments.size());
passedDocuments.forEach(document -> documentService.blockDocument(document));
}
}
}
#Service
#Transactional
public class DocumentService {
#Autowired
private DocumentRepository documentRepository;
#Autowired
private UserService userService;
#Autowired
private EmailService emailService;
#Transactional(noRollbackFor = TransactionSystemException.class)
public void blockDocument(Document document){
documentRepository.blockDocument(document);
}
// repository
#Override
public void blockDocument(Document document) {
DocumentState documentState = getDocumentState(3);
document.setDocumentState(documentState);
entityManager.merge(document);
}
#Entity
#Table(name = "document_state")
public class DocumentState {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#NotBlank(message = "State is mandatory")
#Size(min=1, max=60)
#Column(length = 60)
private String state;
#JsonIgnore
#OneToMany(mappedBy = "documentState", cascade= CascadeType.ALL)
private List<Document> documents;
public DocumentState(){
}
#Entity
public class Document {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(unique = true, length = 60, nullable = false)
#NotBlank(message = "Name is mandatory")
private String name;
#NotBlank(message = "Title is mandatory")
#Size(min = 3, max = 15)
#Column(length = 15, nullable = false)
private String title;
#NotBlank(message = "Description is mandatory")
#Size(min = 3, max = 255)
#Column(length = 255, nullable = false)
private String description;
#ManyToOne
#JoinColumn(name = "document_state_id", nullable = false)
private DocumentState documentState;
#JsonIgnore
#Column(name = "resource_path", length = 255, nullable = false)
private String resourcePath;
#Column(name = "upload_datetime", columnDefinition = "DATETIME", nullable = false)
#Temporal(TemporalType.TIMESTAMP)
#NotNull(message = "UploadDateTime is mandatory")
private Date uploadDatetime;
#Column(name = "approval_end_time", columnDefinition = "DATETIME", nullable = false)
#Temporal(TemporalType.TIMESTAMP)
#NotNull(message = "Approval end time is mandatory")
private Date approvalEndTime;
#Column(name = "active_start_time", columnDefinition = "DATETIME", nullable = false)
#Temporal(TemporalType.TIMESTAMP)
#NotNull(message = "Active start time is mandatory")
private Date activeStartTime;
#Column(name = "active_end_time", columnDefinition = "DATETIME", nullable = false)
#Temporal(TemporalType.TIMESTAMP)
#NotNull(message = "Active end time is mandatory")
private Date activeEndTime;
#OneToMany(mappedBy = "document", cascade= CascadeType.ALL, orphanRemoval = true)
private Set<UsersDocuments> documentsForUsers = new HashSet<>();
#ManyToOne
#JoinColumn(name="user_id")
private User user;
public DocumentState getDocumentState() {
return documentState;
}
EDIT STACK:
org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:541) ~[spring-orm-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:746) ~[spring-tx-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:714) ~[spring-tx-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:534) ~[spring-tx-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:305) ~[spring-tx-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) ~[spring-tx-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688) ~[spring-aop-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at com.patrikmaryska.bc_prace.bc_prace.service.ScheduleService$$EnhancerBySpringCGLIB$$68ed607b.blockPassedDocuments(<generated>) ~[classes/:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:567) ~[na:na]
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:84) ~[spring-context-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) ~[spring-context-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:93) ~[spring-context-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) ~[na:na]
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[na:na]
at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[na:na]
at java.base/java.lang.Thread.run(Thread.java:835) ~[na:na]
Add the #Transactional annotation on blockPassedDocuments method.
Add the #Transactional annotation on ScheduleService class.
Hi everyone I recently work with Spring Data and I have such a question.
I have my Entity that mapped like this:
#Getter
#Setter
#EqualsAndHashCode(callSuper = true)
#ToString(callSuper = true)
#Table(name = "movie")
#Entity
public class Movie extends BaseEntity {
private String name;
#Enumerated(EnumType.STRING)
#Column(columnDefinition = "enum('ACTION','DRAMA','COMEDY','FANTASY','HORROR')")
private Genre genre;
private BigDecimal budget;
#ManyToMany(mappedBy = "movies")
private Set<Actor> actors;
public Movie() {
}
}
My Actor Entity:
#Getter
#Setter
#EqualsAndHashCode(callSuper = true, exclude = "movies")
#ToString(callSuper = true, exclude = "movies")
#Table(name = "actor")
#Entity
public class Actor extends BaseEntity {
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
#Column(name = "salary")
private BigDecimal salary;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(
name = "actor_movie",
joinColumns = {#JoinColumn(name = "actor_id")},
inverseJoinColumns = {#JoinColumn(name = "movie_id")}
)
private Set<Movie> movies;
public Actor() {
}
}
And my BaseEntity;
#Data
#MappedSuperclass
public class BaseEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
}
I am using JpaRepository<Actor, Long> to get my actors from database:
#Repository
public interface ActorRepository extends JpaRepository<Actor, Long> {
}
And here is my controller:
#RestController
#RequestMapping("actor")
public class ActorController {
#Autowired
ActorRepository actorRepository;
#PostMapping
public Actor save(#RequestBody Actor actor) {
actorRepository.save(actor);
return actor;
}
#GetMapping
public Iterable<Actor> findAllActors() {
return actorRepository.findAll();
}
#GetMapping("{id}")
public Actor findActor(#PathVariable Long id) {
return actorRepository.findById(id).orElseThrow(NotFoundException::new);
}
#PutMapping("{id}")
public Actor update(#RequestBody Actor actor, #PathVariable Long id) {
actor.setId(id);
return actorRepository.save(actor);
}
#DeleteMapping("{id}")
public ResponseEntity<Actor> delete(#PathVariable Long id) {
actorRepository.deleteById(id);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
}
So when I'm trying to get my actor by id it gets a so many times:
And finally it fails with StackOverFlowError:
java.lang.StackOverflowError: null
at java.lang.ClassLoader.defineClass1(Native Method) ~[na:1.8.0_172]
at java.lang.ClassLoader.defineClass(ClassLoader.java:763) ~[na:1.8.0_172]
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) ~[na:1.8.0_172]
at java.net.URLClassLoader.defineClass(URLClassLoader.java:467) ~[na:1.8.0_172]
at java.net.URLClassLoader.access$100(URLClassLoader.java:73) ~[na:1.8.0_172]
at java.net.URLClassLoader$1.run(URLClassLoader.java:368) ~[na:1.8.0_172]
at java.net.URLClassLoader$1.run(URLClassLoader.java:362) ~[na:1.8.0_172]
at java.security.AccessController.doPrivileged(Native Method) ~[na:1.8.0_172]
at java.net.URLClassLoader.findClass(URLClassLoader.java:361) ~[na:1.8.0_172]
at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_172]
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349) ~[na:1.8.0_172]
at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_172]
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:737) ~[jackson-databind-2.9.9.jar:2.9.9]
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155) ~[jackson-databind-2.9.9.jar:2.9.9]
at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serializeContents(CollectionSerializer.java:145) ~[jackson-databind-2.9.9.jar:2.9.9]
at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:107) ~[jackson-databind-2.9.9.jar:2.9.9]
at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:25) ~[jackson-databind-2.9.9.jar:2.9.9]
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:727) ~[jackson-databind-2.9.9.jar:2.9.9]
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:719) ~[jackson-databind-2.9.9.jar:2.9.9]
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155) ~[jackson-databind-2.9.9.jar:2.9.9]
Why is this happens? And how it can be fixed?
model classes
#Entity
#Table(name="RequisitionRequest")
public class Requisition {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String requestedPerson;
private String contactDetails;
private String appliedDate;
private String branch;
private String department;
private String status;
#OneToMany(cascade = CascadeType.ALL,fetch = FetchType.EAGER,mappedBy = "RequisitionRequest")
private List<Nationality> nationality;
//getters and setters
}
class Nationality
#Entity
#Table(name="nationality")
public class Nationality {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String nationality;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "nationality_id", nullable = false)
private Requisition requisition;
//getters and setters
}
repository classes
#Repository
public interface NationalityRepository extends JpaRepository<Nationality,Long>{
}
#Repository
public interface RequisitionRepository extends JpaRepository<Requisition,Long> {
}
service class
#Service
public class RequisitionServiceImpl implements RequisitionService {
#Autowired
RequisitionRepository requisitionRepository;
#Override
public void save(Requisition requisition) {
requisitionRepository.save(requisition);
}
}
controller class
#RestController
public class RequisitionController {
#Autowired
RequisitionService requisitionService;
#Autowired
RequisitionRepository requisitionRepository;
#PostMapping("/requisition/")
#CacheEvict(value = "requisitions", allEntries=true)
public ResponseEntity<Requisition> addRequisition(#RequestBody Requisition requisition) {
System.out.print(requisition);
Requisition requisitionR = new Requisition();
Requisition response = new Requisition();
requisitionR.setBranch(requisition.getBranch());
requisitionR.setDepartment(requisition.getDepartment());
requisitionR.setExpectedDateofJoin(requisition.getExpectedDateofJoin());
//requisitionR.setNationality(requisition.getNationality());
requisitionRepository.save(requisitionR);
return new ResponseEntity<Requisition>(response, HttpStatus.OK);
}
i am learning spring boot,just writing sample program to learn spring boot+jpa+one-to-many relation.when execute this above code getting error like
Caused by: org.hibernate.AnnotationException: mappedBy reference an unknown target entity property: officekitRecruitment.model.Nationality.RequisitionRequest in officekitRecruitment.model.Requisition.nationality
at org.hibernate.cfg.annotations.CollectionBinder.bindStarToManySecondPass(CollectionBinder.java:769) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.cfg.annotations.CollectionBinder$1.secondPass(CollectionBinder.java:719) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.cfg.CollectionSecondPass.doSecondPass(CollectionSecondPass.java:54) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1655) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1623) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:278) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:847) ~[hibernate-entitymanager-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:874) ~[hibernate-entitymanager-5.0.12.Final.jar:5.0.12.Final]
I tried the solutions already mentionned in this site but it doesn't work for me.
Can anybody helps me to resolve this issue
You should refer to the name of the Field in mapped entity on your MappedBy parameter.
Like that
mappedBy = "requisition"