SpringBoot #OneToMany infinite loop with Lombok - eclipse

My project using SpringBoot, it has bidirectional mapping #OneToMany
#Entity
#Table(name = "T_S")
#Getter
#Setter
#EqualsAndHashCode
#NoArgsConstructor
#AllArgsConstructor
#ToString
public class S implements Serializable {
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
#JoinColumn(name = "something", referencedColumnName = "A_ID", nullable = false, insertable = false, updatable = false)
#OptimisticLock(excluded = false)
private Set<A> act = new HashSet<>();
....something...
}
#Entity
#Table(name = "T_A")
#Getter
#Setter
#EqualsAndHashCode
#NoArgsConstructor
#AllArgsConstructor
#ToString
public class A{
#ManyToOne(optional = true, fetch = FetchType.LAZY)
#JoinColumn(name = "A_ID", insertable = false, updatable = false)
private S sub;
}
whe i get data from repository it make infinitive loop. How to fix it ?

If you have bidirectional relationships Lombok equals,
hashCode and toString will create a StackOverflowError.
So remove #ToString and #EqualsAndHashCode.
I'm general equals and hashCode should be implemented on a unique business key when using JPA.
Another way would be to exclude certain attributes from Lombok.

Please use #ToString.Exclude on that attribute which makes an infinite loop.
#Entity
#Table(name = "T_S")
#Getter
#Setter
#EqualsAndHashCode
#NoArgsConstructor
#AllArgsConstructor
#ToString
public class S implements Serializable {
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
#JoinColumn(name = "something", referencedColumnName = "A_ID", nullable = false, insertable = false, updatable = false)
#OptimisticLock(excluded = false)
private Set<A> act = new HashSet<>();
....something...
}
#Entity
#Table(name = "T_A")
#Getter
#Setter
#EqualsAndHashCode
#NoArgsConstructor
#AllArgsConstructor
#ToString
public class A{
#ToString.Exclude -----------------> here is the change
#ManyToOne(optional = true, fetch = FetchType.LAZY)
#JoinColumn(name = "A_ID", insertable = false, updatable = false)
private S sub;
}

I have fixed this issue by override three method hashCode ,toString, equals in entity A
#Override
public int hashCode() {
//something
}
#Override
public String toString() {
//something
}
#Override
public boolean equals(Object obj) {
//something
}

Do Not use Lombok with JPA Entity. The toString() goes on Infinite loop.
Other ways, override the toString of Many Entity to return "".

Related

Exclude some fields of REST Data with Panache

Just having a look at REST Data with Panache wondering if it is possible to exclude some entity fields from beeing exposed by the rest resource, as we need the generated REST resources only for read access pattern.
However, in the docs https://quarkus.io/guides/rest-data-panache I did not find a way to do it.
Looks like it is using Jackson for JSON, so #JsonIgnore should work for you.
#JSonIgnore can be used at the field level, or you can add it on the Getter or Setter if you want only specific parts to be ignored.
#Entity
#Table(name = "order_item")
public class OrderItem extends PanacheEntityBase {
#Id
#GenericGenerator(name = "uuid", strategy = "org.hibernate.id.UUIDGenerator")
#GeneratedValue(generator = "uuid")
#Column(name = "id", length = 36, nullable = false)
#Getter
#Setter
private String id;
#Getter
#Setter
#ManyToOne(targetEntity = Order.class)
#JsonIgnore
#JoinColumn(name = "order_id")
private Order orderId;
#Getter
#Setter
#JsonIgnore
#ManyToOne(targetEntity = Item.class)
#JoinColumn(name = "item_id")
private Item itemId;
#Getter
#Setter
#Column(name = "quantity", nullable = false)
private Integer quantity;
#Getter
#Setter
#Column(name = "price_total", nullable = false)
private Double priceTotal;
#Getter
#Setter
#Column(name = "note", columnDefinition = "text")
private String note;
}
Or you can use #JsonIgnoreProperties at the top level of the class:
#Entity
#JsonIgnoreProperties(value = { "creator", "created" }, allowSetters = false, allowGetters = true)
public class UpdateUserDeviceTokenRequest extends PanacheEntity {
#NotNull
#NotEmpty
#NotBlank
public String userDeviceToken;
#ManyToOne()
#JoinColumn(name = "creatorUser", insertable = true, updatable = false)
public AppUser creator;
#Column(insertable = true, updatable = false)
public LocalDateTime created;
public UpdateUserDeviceTokenRequest() {
}
#PrePersist
void onCreate() {
this.created = LocalDateTime.now();
}
public UpdateUserDeviceTokenRequest(#NotNull #NotEmpty #NotBlank String userDeviceToken) {
super();
this.userDeviceToken = userDeviceToken;
}
}
Please see https://github.com/quarkusio/quarkus/issues/10339 for possible issue that might arise

Unable to delete entity using Spring Data Jpa

I have a bi-directional mapping between Customer, Order and LineItems. When trying to delete using deleteById method of Spring Data JPA, the entities are not getting deleted and I do not see any exception.
#Entity
#Table(name = "customers")
#NoArgsConstructor
#AllArgsConstructor
#Builder
#Data
public class Customer implements UserDetails {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#NotEmpty(message = "customer name cannot be empty")
private String name;
#Column(unique = true)
#Email(message = "customer email address should be valid email address")
private String email;
#OneToMany(mappedBy = "customer", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JsonManagedReference
private Set<Order> orders;
private String password;
#Data
#NoArgsConstructor
#Builder
#AllArgsConstructor
#EqualsAndHashCode(exclude = {"customer", "lineItems"})
#ToString(exclude = {"customer", "lineItems"})
#Entity
#Table(name = "orders")
public class Order {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Min(value = 2000, message = "Min order value should be 2000 INR")
#Max(value = 10_000, message = "Max order value can be 10000 INR")
private double price;
#PastOrPresent(message = "Order date cannot be in future")
private LocalDate date;
#ManyToOne
#JoinColumn(name="customer_id", nullable = false)
#JsonBackReference
private Customer customer;
#OneToMany(mappedBy = "order",
cascade = CascadeType.ALL,
fetch = FetchType.LAZY,
orphanRemoval = true
)
private Set<LineItem> lineItems;
//scaffolding code
// set the bidirectional mapping
public void addLineItem(LineItem lineItem){
if(this.lineItems == null){
this.lineItems = new HashSet<>();
}
this.lineItems.add(lineItem);
lineItem.setOrder(this);
}
}
#Data
#NoArgsConstructor
#EqualsAndHashCode(exclude = "order")
#ToString(exclude = "order")
#Builder
#AllArgsConstructor
#Entity
#Table(name="line_items")
public class LineItem {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private int qty;
private double price;
private String name;
#JsonIgnore
#ManyToOne
#JoinColumn(name="order_id", nullable = false)
private Order order;
}
this.orderRepository.deleteById(orderId);
Error:
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.classpath.ordersapi.model.Customer.orders, could not initialize proxy - no Session\r\n\tat org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:612)\r\n\tat org.hibernate.collection.internal

Hibernate #OneToMany where discriminatorValue = 'SOMETHING'

Table pdp_billable_field_state carries configuration for various fields.
Owner of configuration can be any number of Entity`s
This configuration is same for each entity that matches the #DiscriminatorValue
#Getter
#Setter
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "entity_type")
#Table(name = "pdp_billable_field_state")
public abstract class EntityFieldStateJpa extends AuditableJPA {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#ManyToOne
#JoinColumn(name = "status_id")
private StatusJpa status;
#Column(name = "field", columnDefinition= "varchar(255)")
private String field;
private boolean disabled;
private boolean hidden;
}
#DiscriminatorValue("PURCHASE")
public class PurchaseEntityFieldStateJpa extends EntityFieldStateJpa {}
#Getter
#Setter
#Entity
#Builder
#AllArgsConstructor
#NoArgsConstructor
#Table(name = "pdp_purchase")
public class PurchaseJpa {
// omitted
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.REFRESH)
// i do not have a join_column since all records with entity_type PURCHASE map to all purchases, as these are configurations used by all purchases. Should i try and introduce #JoinTable maybe?
#Where(clause = "entity_type='PURCHASE'")
private List<PurchaseEntityFieldStateJpa> fieldStates;
}

JPA #ManyToOne CascadeType.PERSIST

Hallo I have an entity with a #ManyToOne Relations ship
#Entity
public class TerminEntity extends AbstractEntity implements Serializable {
#ManyToOne(cascade = CascadeType.PERSIST)
#JoinColumn(name = "PERSON_ID")
private PersonEntity person;
#MappedSuperclass
public abstract class AbstractEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "termineIdGenerator")
#SequenceGenerator(name="termineIdGenerator", sequenceName = "SEQ_TERMINVERWALTUNG")
private Long id;
When I try to persist a TerminEntity with an PersonEntity which is not already present in the database I get
java.lang.IllegalStateException: During synchronization a new object was found through a relationship that was not marked cascade PERSIST: TerminEntity(person=PersonEntity
Why? What is wrong with the #ManyToOne(cascade = CascadeType.PERSIST) annotation?
Running on Oracle Weblogic 12c
I don't know why but after changing the annotation to
#ManyToOne(optional = false, cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH })
#JoinColumn(name = "PERSON_ID", referencedColumnName = "ID", nullable = false)
the persist works.

JPArepository method with ManyToOne not return related data

I have two entities using a OneToMany and ManyToOne relationship:
#Entity
#Table(name = TableName.PERSON)
public class Person {
#Id
#Column(name = FieldName.DB_KEY)
public String dbKey;
#Column(name = FieldName.ENTITY_ID)
public String entityId;
#Column(name = FieldName.SORT_KEY)
public String sortKey;
#JoinColumn(name = FieldName.ENTITY_ID, referencedColumnName =
FieldName.ENTITY_ID, insertable = false, updatable = false)
#ManyToOne(fetch = FetchType.EAGER)
#JoinFetch(value = JoinFetchType.INNER)
public WLEntity entity;
}
#Entity
#Table(name = TableName.WL_ENTITY)
public class WLEntity {
#Id
#Column(name = FieldName.ENTITY_ID)
public String entityId;
#Column(name = FieldName.HAS_ADDRESS)
public boolean hasAddress;
#OneToMany(mappedBy = "entity", targetEntity = PersonIndex.class, cascade = CascadeType.ALL)
public List<Person> persons;
}
And a JPA-Repository defining one findBy... Method:
#Repository
public interface PersonRepository extends JpaRepository<Person, String> {
List<Person> findBySortKeyStartingWith(String sortKey);
}
If I call this method I can see in the console:
SELECT t1.DB_KEY, t1.ENTITY_ID, t1.SORT_KEY, t0.ENTITY_ID, t0.HAS_ADDRESS FROM WL_ENTITY t0, PERSON t1 WHERE (t1.SORT_KEY LIKE ? AND (t0.ENTITY_ID = t1.ENTITY_ID))
So the join I want is correct executed, but in the returned data the entity field is still null but all other fields are filled:
List<Person> persons = personRepository.findBySortKeyStartingWith("Sort");
Person person = persons.get(0);
person.entity == null but person.entityId is correctly filled.
So what I have to do, to get person.entity filled?
I use spring boot with eclipselink jpa 2.6.4