Reputation: 11
I'm working on a simple store project in spring. First, I implemented Item to Order mapping as another entity called Position. It had a sequentially generated id before, but to my knowledge composite key (order_id, item_id) was a better solution. I've read a lot of internet articles regarding this topic, but I'm in a dead-end right now. The application launches correctly and generates all the tables correctly, but after inserting throws an error.
2020-07-02 11:38:01.864 ERROR 4676 --- [nio-8080-exec-5] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.orm.jpa.JpaSystemException: Could not set field value [2] value by reflection : [class com.wave.greenboxrest.model.PositionId.itemId] setter of com.wave.greenboxrest.model.PositionId.itemId; nested exception is org.hibernate.PropertyAccessException: Could not set field value [2] value by reflection : [class com.wave.greenboxrest.model.PositionId.itemId] setter of com.wave.greenboxrest.model.PositionId.itemId] with root cause
And another one: java.lang.NullPointerException: null
I tried to make sure there are getters and setters on every field but it seems that's not the reason.
OrderController::createOrder method, after inserting the error occurs.
@PostMapping("/create")
public void createOrder(@RequestBody OrderCreateDto orderDto){
Set<Position> positions = new HashSet<>();
Order order = new Order();
for(PositionCreateDto positionDto: orderDto.positions){
Position position =
new Position(itemRepository.findById(positionDto.itemId).get(), positionDto.weight);
position.setOrder(order);
positions.add(position);
}
order.setPersonName(orderDto.personName);
order.setAddress(orderDto.address);
order.setPhoneNumber(orderDto.phoneNumber);
order.setPositions(positions);
orderRepository.saveAndFlush(order);
}
@Entity(name = "positions")
public class Position {
@EmbeddedId
private PositionId id;
@JsonIgnore
@NotNull
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "order_id")
@MapsId("orderId")
private Order order;
@NotNull
@OneToOne(cascade = CascadeType.ALL)
@MapsId("itemId")
private Item item;
@NotEmpty
private Double weight;
public Position() {
}
public Position(@NotNull Item item, @NotEmpty Double weight) {
this.item = item;
this.weight = weight;
}
public PositionId getId() {
return id;
}
public void setId(PositionId id) {
this.id = id;
}
public void setOrder(Order order) {
this.order = order;
}
public Order getOrder() {
return order;
}
public Item getItem() {
return item;
}
public void setItem(Item item) {
this.item = item;
}
public Double getWeight() {
return weight;
}
public void setWeight(Double weight) {
this.weight = weight;
}
@JsonProperty("subtotal")
public Double calculateSubtotal(){
return item.getPrice() * weight;
}
}
@Embeddable
public class PositionId implements Serializable {
private Long orderId;
private Long itemId;
public PositionId(){
}
public PositionId(Long orderId, Long itemId) {
this.orderId = orderId;
this.itemId = itemId;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PositionId that = (PositionId) o;
return orderId.equals(that.orderId) &&
itemId.equals(that.itemId);
}
@Override
public int hashCode() {
return Objects.hash(orderId, itemId);
}
public Long getOrderId() {
return orderId;
}
public void setOrderId(Long orderId) {
this.orderId = orderId;
}
public Long getItemId() {
return itemId;
}
public void setItemId(Long itemId) {
this.itemId = itemId;
}
}
Could anyone guide me how to get through the error? Also is the createOrder method implemented correctly?
Upvotes: 0
Views: 1229
Reputation: 11
Finally, I've solved the issue! The trick was to instantiate PositionId when creating a Position.
public Position(Order order, Item item, Double weight) {
this.order = order;
this.item = item;
this.weight = weight;
this.id = new PositionId(order.getId(), item.getId());
}
I was almost sure, that it is being done for me under the hood. Apparently I was wrong.
Upvotes: 1
Reputation: 111
It seems that hibernate could not map itemId column,so I guess that the itemId column will be "item_id", so try to modify your PositionId class to be like that
@Embeddable
public class PositionId implements Serializable {
@Column(name = "order_id")
private Long ordered;
@Column(name = "item_id")
private Long itemId;
public PositionId(){
}
public PositionId(Long orderId, Long itemId) {
this.orderId = orderId;
this.itemId = itemId;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PositionId that = (PositionId) o;
return orderId.equals(that.orderId) &&
itemId.equals(that.itemId);
}
@Override
public int hashCode() {
return Objects.hash(orderId, itemId);
}
public Long getOrderId() {
return orderId;
}
public void setOrderId(Long orderId) {
this.orderId = orderId;
}
public Long getItemId() {
return itemId;
}
public void setItemId(Long itemId) {
this.itemId = itemId;
}
}
Upvotes: 0