Problem with proxy when using #IdClass in Hibernate - spring

For legacy reasons I have composite keys in my database, I use #IdClass to map them (before I used #Embeddedid but it had it's own bugs). However I have problem whenever I'm trying to save composite key entity that contains proxy as id field.
I made very simple example to isolate this problem (example uses Spring Data, but I think its irrelevant).
p.s. I know that calling .save is not necessary, but it should not cause exception.
#Entity
public class Image {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String fileName;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
}
#Entity
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
#Entity
#IdClass(ProductImage.ProductImageId.class)
public class ProductImage {
public static class ProductImageId implements Serializable {
private static final long serialVersionUID = 8542391285589067304L;
private Long product;
private Long image;
public ProductImageId() {
}
public Long getProduct() {
return product;
}
public void setProduct(Long product) {
this.product = product;
}
public Long getImage() {
return image;
}
public void setImage(Long image) {
this.image = image;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ProductImageId that = (ProductImageId) o;
return Objects.equals(product, that.product) &&
Objects.equals(image, that.image);
}
#Override
public int hashCode() {
return Objects.hash(product, image);
}
}
#ManyToOne(fetch = FetchType.LAZY)
#Id
private Product product;
#ManyToOne(fetch = FetchType.LAZY)
#Id
private Image image;
private Integer number;
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
public Image getImage() {
return image;
}
public void setImage(Image image) {
this.image = image;
}
public Integer getNumber() {
return number;
}
public void setNumber(Integer number) {
this.number = number;
}
}
List<ProductImage> productImages = productImageRepository.findAll();
productImages.get(0).setNumber(456);
productImageRepository.save(productImages.get(0));
Caused by: java.lang.IllegalArgumentException: Cannot convert value of type 'com.example.springbootnewplayground.Product$HibernateProxy$AJ38NiN6' to required type 'java.lang.Long' for property 'product': PropertyEditor [org.springframework.beans.propertyeditors.CustomNumberEditor] returned inappropriate value of type 'com.example.springbootnewplayground.Product$HibernateProxy$AJ38NiN6'
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:258) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.beans.AbstractNestablePropertyAccessor.convertIfNecessary(AbstractNestablePropertyAccessor.java:585) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
... 69 common frames omitted

Related

org.neo4j.driver.v1.exceptions.ServiceUnavailableException: Connection to the database terminated

I want to connect Spring Boot with neo4j database, however, it returns an error like that. It says that the connection has been terminated. The error is as follow:
org.neo4j.driver.v1.exceptions.ServiceUnavailableException: Connection to the database terminated.
This is my Controller
#RequestMapping("/neo4j/Movie")
public class MovieController {
private final MovieRepository movieRepository;
public MovieController(MovieRepository movieRepository) {
this.movieRepository = movieRepository;
}
#GetMapping("/graph")
public List<Movie> graph() {
return (List<Movie>) movieRepository.findAll();
}
}
This is my Repository
#Repository
public interface MovieRepository extends Neo4jRepository<Movie,Long> {
#Query("MATCH(m:Movie)<-[relation:ActedIn]-(b:Actor) RETURN m,relation,b")
Collection<Movie> graph();
}
And the application.properties
spring.data.neo4j.username=neo4j
spring.data.neo4j.password=neo4j
spring.data.neo4j.uri=bolt://localhost:7687
NodeEntity of moview
#NodeEntity
public class Movie {
#Id
private int id;
private String title;
private String genre;
// #JsonIgnoreProperties("movie")
#Relationship(type = "ActedIn")
private List<Actor> actors;
// #Relationship(type = "ACTED_IN" , direction = Relationship.INCOMING)
// private List<Actress> actresses = new ArrayList<>();
public Movie() {
}
public List<Actor> getActors() {
return actors;
}
public void setActors(List<Actor> actors) {
this.actors = actors;
}
public Movie(int id, String title, String genre, List<Actor> actors) {
this.id = id;
this.title = title;
this.genre=genre;
this.actors=actors;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getGenre() {
return genre;
}
public void setGenre(String genre) {
this.genre=genre;
}
}
And NodeEntity of Actor
public class Actor {
#GraphId
private Long id;
private String name;
private int age;
public Actor() {
}
public Actor(Long id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
I also tried springboot + neo4j projects downloaded from github, and also followed the instructions from neo4j website, but the projects still failed on my computer, so is there any super tutorials for neo4j and springboot?

Null value in primary key of hibernate entity

I faced with problem of null value in PK.
Here's an entity:
#Entity
#Table(name="space")
public class Space implements Serializable {
#Id
#GeneratedValue
#Column(nullable = false, unique = true)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="user_id")
private UserAccount user;
private String name;
private String description;
private Date createdTime;
private Date modifiedTime;
#OneToMany(mappedBy="space")
private Set<SpaceAccess> spaceAccesses = new HashSet<>();
public Set<SpaceAccess> getSpaceAccesses() {
return spaceAccesses;
}
public void setSpaceAccesses(Set<SpaceAccess> spaceAccesses) {
this.spaceAccesses = spaceAccesses;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Space() {}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public UserAccount getUser() {
return user;
}
public void setUser(UserAccount user) {
this.user = user;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Date getCreatedTime() {
return createdTime;
}
public void setCreatedTime(Date createdTime) {
this.createdTime = createdTime;
}
public Date getModifiedTime() {
return modifiedTime;
}
public void setModifiedTime(Date modifiedTime) {
this.modifiedTime = modifiedTime;
}
}
I wrote strategy to generate PK properly but I always get Null in id field when I create new instance of the Space:
Space space = new Space();
Here's content of the object:
What i should do to generate id of instance properly using hibernate/spring mechanisms?
application.properties:
spring.datasource.url="some_url"
spring.datasource.username=name
spring.datasource.password=password
spring.jpa.generate-ddl=true
P.S. I use spring-boot-starter-data-jpa with version: 2.3.4.RELEASE.
Use:
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}

JAVA 8 - Stream features giving error while retriving data from 3 POJO class

I am having 3 POJO class for products, attribute & value. All three POJOs are have relationship with other POJO class. Now, I want to retrive value for the
each and every products.
It was working perfectly with the older approach but now i want to modify my code with new JAVA 8 features.
Please find my code below.
listProducts.stream().forEachOrdered(listproducts ->
listproducts.getProductAttr()
.stream().forEachOrdered(attr ->
(((Collection<ProductAttrValue>) attr.getProductAttrValue()
.stream().filter(attrlabel ->
attrlabel.getLabel().equalsIgnoreCase("source"))))
.stream().forEachOrdered(attrval ->
{
System.out.println(attrval.getValue());
}
)
)
);
Please find the error message that I am getting.
Exception in thread "main" java.lang.ClassCastException:
java.util.stream.ReferencePipeline$2 cannot be cast to java.util.Collection
at Hibernate.Testing.App.lambda$1(App.java:81)
at java.util.Iterator.forEachRemaining(Unknown Source)
at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Unknown
Source)
at java.util.stream.ReferencePipeline$Head.forEachOrdered(Unknown Source)
at Hibernate.Testing.App.lambda$0(App.java:81)
at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(Unknown Source)
at java.util.stream.ReferencePipeline$Head.forEachOrdered(Unknown Source)
at Hibernate.Testing.App.main(App.java:80)
If am not doing type casting .stream().forEachOrdered(attr -> ((Collection<ProductAttrValue>) attr.getProductAttrValue() am getting the below errors.
Please find my Product POJO class
public class Product {
private String name;
private long std_delivery_Time;
private int min_order_Quantity;
private String status;
private long catalog_Id;
private Date expiration_Date;
private int rank;
private String product_Type;
private int is_Visible;
private String product_Group;
private String code;
#Id
#Column(name = "ID")
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setId(long id) {
this.id = id;
}
public long getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
#OneToMany( mappedBy = "product", cascade = CascadeType.ALL)
private List<ProductAttr> productAttr;
public List<ProductAttr> getProductAttr() {
return productAttr;
}
public void setProductAttr(List<ProductAttr> productAttr) {
this.productAttr = productAttr;
}
}
ProductAttr class
public class ProductAttr {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID", updatable=false, nullable=false)
private long id;
#Column(name = "NAME")
private String name;
#Column(name = "PRODUCT_ID")
private long product_id;
public ProductAttr() {
super();
// TODO Auto-generated constructor stub
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getProduct_id() {
return product_id;
}
public void setProduct_id(long product_id) {
this.product_id = product_id;
}
public long getId() {
return id;
}
#ManyToOne
#JoinColumn(name = "PRODUCT_ID", referencedColumnName = "ID",
insertable = false, updatable = false)
private Product product;
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
#OneToMany( mappedBy = "productAttr", cascade = CascadeType.ALL)
private Set<ProductAttrValue> productAttrValue;
public Set<ProductAttrValue> getProductAttrValue() {
return productAttrValue;
}
public void setProductAttrValue(Set<ProductAttrValue>
productAttrValue) {
this.productAttrValue = productAttrValue;
}
}
ProductValue class
public class ProductAttrValue {
#Id
#Column(name = "ATTR_ID", updatable=false, nullable=false)
private long attr_id;
#Column(name = "LABEL")
private String label;
#Column(name = "VALUE")
private String value;
public long getAttr_id() {
return attr_id;
}
public void setAttr_id(long attr_id) {
this.attr_id = attr_id;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public void setValue(String value) {
this.value = value;
}
public String getValue() {
return value;
}
#ManyToOne
#JoinColumn(name = "ATTR_ID", referencedColumnName = "ID", insertable
= false, updatable = false)
private ProductAttr productAttr;
public ProductAttr getProductAttr() {
return productAttr;
}
public void setProductAttr(ProductAttr productAttr) {
this.productAttr = productAttr;
}
public ProductAttrValue() {
super();
// TODO Auto-generated constructor stub
}
}
Your indentation suggests a wrong mindset. These stream() operation are not on the same level. You have a nested operation:
listProducts.stream().forEachOrdered(listproducts ->
listproducts.getProductAttr().stream().forEachOrdered(attr ->
attr.getProductAttrValue().stream()
.filter(av -> av.getLabel().equalsIgnoreCase("source"))
/*.stream()*/.forEachOrdered(av -> System.out.println(av.getValue()))
)
);
(I changed the misleading name attrlabel and attrval to av, as these aren’t labels or values; you’re invoking .getLabel() and .getValue() subsequently on these variables, so I used av for “ProductAttrValue”)
The filter operation is the only operation that is not nesting, as it is an intermediate operation chained to the stream and the terminal operation just has to be chained to the resulting stream. There is no stream() invocation necessary at that place (the one marked with /*.stream()*/).
That said, you should avoid such nested operation.
You can use
listProducts.stream()
.flatMap(listproducts -> listproducts.getProductAttr().stream())
.flatMap(attr -> attr.getProductAttrValue().stream())
.filter(av -> av.getLabel().equalsIgnoreCase("source"))
.forEachOrdered(av -> System.out.println(av.getValue()));
instead.
All stream methods return another stream. To convert back to a list you need to use a Collector:
<your stream>.collect(Collectors.toList());

could not resolve property: product_id of: Comment

Getting an error on server startup a query that finds all comments posted by a user about a specific product.
Caused by: java.lang.IllegalArgumentException: org.hibernate.QueryException: could not resolve property: product_id of: haughton.dvdstore.model.Comment [select c from haughton.dvdstore.model.Comment c where c.product_id = :id]
Repo class
#Repository
public interface CommentDao extends CrudRepository<Comment,Long> {
#Query("select c from Comment c where c.product_id = :id")
List<Comment> allCommentsByProductId(#Param("id") Long id);
}
Comment class
#Entity
public class Comment {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne
#JoinColumn(name = "product_id")
private Product product;
#ManyToOne
#JoinColumn(name = "user_id")
private User user;
private String text;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
My product class
#Entity
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private String description;
private int quantityInStock;
Date date;
private double price;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public int getQuantityInStock() {
return quantityInStock;
}
public void setQuantityInStock(int quantityInStock) {
this.quantityInStock = quantityInStock;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
}
User class
#Entity
public class User implements UserDetails {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(unique = true)
#Size(min = 8, max = 20)
private String username;
#Column(length = 100)
private String password;
#Column(nullable = false)
private boolean enabled;
#OneToOne
#JoinColumn(name = "role_id")
private Role role;
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority(role.getName()));
return authorities;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Override
public String getPassword() {
return password;
}
#Override
public String getUsername() {
return username;
}
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return true;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isEnabled() {
return enabled;
}
public static PasswordEncoder getPasswordEncoder() {
return PASSWORD_ENCODER;
}
}
It should have been #Query("select c from Comment c where c.product.id = :id")

Repeated column in mapping for entity: Shipper column: SHIPPER_ID (should be mapped with insert="false"

I have been going around in circles with this error and not sure why I am getting this.
Here is the mapping of Shipper class
#Entity
#Table(schema="SALONBOOKS",name="SHIPPER")
#AttributeOverride(name="id", column=#Column(name="SHIPPER_ID"))
public class Shipper extends SalonObject {
private static final long serialVersionUID = 1L;
private ShipperType name;//ShipperType.WALKIN;
#Column(name="SHIPPER_NAME")
#Enumerated(EnumType.STRING)
public ShipperType getName() {
return name;
}
public void setName(ShipperType name) {
this.name = name;
}
#Override
public Long getId(){
return id;
}
}
Here is Order class which references Shipper
#Entity
#Table(schema="SALONBOOKS",name="ORDER")
#AttributeOverride(name="id", column=#Column(name="ORDER_ID"))
public class Order extends SalonObject {
private static final long serialVersionUID = 1L;
private BigDecimal total= new BigDecimal(0.0);
private int numOfItems=0;
private BigDecimal tax= new BigDecimal(0.0);;
private String currency="USD";
private BigDecimal subTotal= new BigDecimal(0.0);
private PaymentMethod paymentMethod;
private Shipper shipper;
private OrderStatusType status;
private Appointment appointment ;
private Person person;
#Column(name="TOTAL")
public BigDecimal getTotal() {
return total;
}
public void setTotal(BigDecimal total) {
this.total = total;
}
#Column(name="NUM_OF_ITEMS")
public int getNumOfItems() {
return numOfItems;
}
public void setNumOfItems(int numOfItems) {
this.numOfItems = numOfItems;
}
#Column(name="TAX")
public BigDecimal getTax() {
return tax;
}
public void setTax(BigDecimal tax) {
this.tax = tax;
}
#Column(name="CURRENCY")
public String getCurrency() {
return currency;
}
public void setCurrency(String currency) {
this.currency = currency;
}
#Column(name="SUBTOTAL")
public BigDecimal getSubTotal() {
return subTotal;
}
public void setSubTotal(BigDecimal subTotal) {
this.subTotal = subTotal;
}
#ManyToOne
#JoinColumn(name="PAYMENT_METHOD_ID", insertable=false,updatable=false)
public PaymentMethod getPaymentMethod() {
return paymentMethod;
}
public void setPaymentMethod(PaymentMethod paymentMethod) {
this.paymentMethod = paymentMethod;
}
#ManyToOne
#JoinColumn(name="SHIPPER_ID", insertable=false,updatable=false)
public Shipper getShipper() {
return shipper;
}
public void setShipper(Shipper shipVia) {
this.shipper = shipVia;
}
#Column(name="STATUS")
#Enumerated(EnumType.STRING)
public OrderStatusType getStatus() {
return status;
}
public void setStatus(OrderStatusType status) {
this.status = status;
}
#ManyToOne
#JoinColumn(name="APPOINTMENT_ID", insertable=false,updatable=false)
public Appointment getAppointment() {
return appointment;
}
public void setAppointment(Appointment appointment) {
this.appointment = appointment;
}
#ManyToOne
#JoinColumn(name="PERSON_ID", insertable=false,updatable=false)
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
#Override
public Long getId(){
return id;
}
}
each of these extends:
#MappedSuperclass
public abstract class SalonObject implements Entity, Serializable {
private static final long serialVersionUID = 1L;
protected Long id;
protected DateTime createDate;
protected DateTime updateDate;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Override
public boolean equals(Object obj) {
if (obj instanceof SalonObject
&& obj !=null){
return ObjectUtils.equals(this.id, ((SalonObject) obj).getId()) ;
}
return false;
}
#Column(name="CREATE_DATE")
public DateTime getCreateDate() {
return createDate;
}
public void setCreateDate(DateTime dateTime) {
this.createDate = dateTime;
}
#Column(name="UPDATE_DATE")
public DateTime getUpdateDate() {
return updateDate;
}
public void setUpdateDate(DateTime updateDate) {
this.updateDate = updateDate;
}
}
The stackTrace is ::
Caused by: org.hibernate.MappingException: Repeated column in mapping for entity: salonbooks.model.Shipper column: SHIPPER_ID (should be mapped with insert="false" update="false")
at org.hibernate.mapping.PersistentClass.checkColumnDuplication(PersistentClass.java:709)
at org.hibernate.mapping.PersistentClass.checkPropertyColumnDuplication(PersistentClass.java:731)
at org.hibernate.mapping.PersistentClass.checkColumnDuplication(PersistentClass.java:753)
at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:506)
at org.hibernate.mapping.RootClass.validate(RootClass.java:270)
at org.hibernate.cfg.Configuration.validate(Configuration.java:1358)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1849)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1928)
at org.springframework.orm.hibernate4.LocalSessionFactoryBuilder.buildSessionFactory(LocalSessionFactoryBuilder.java:343)
at salonbooks.core.HibernateConfiguration.sessionFactory(HibernateConfiguration.java:109)
removing the following method from Shipper and from Order worked to resolve this error
#Override
public Long getId(){
return id;
}
Because you are using property access, by overriding the base method (containing the mapping configuration) you will replace your base method mapping configuration with no config at all.
Using field access wouldn't have caused this issue, but the override would have been useless anyway. The id field should have private access too, so this method wouldn't compile if you change the access modifier.

Resources