Reputation: 41
I'm creating eCommerce for merchants using spring boot with JPA. I have an issue while creating the order service. I want to only pass the ID of the nested objects in the request body instead of sending the full nest objects because the size will be extremely big.
Here is my code. Merchant can do many orders
Order
@Entity
@Table(name = "Orders")
@XmlRootElement
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Order extends BasicModelWithIDInt {
@Basic(optional = false)
@Column(name = "Quantity")
private Integer quantity;
@Basic(optional = false)
@Size(min = 1, max = 150)
@Column(name = "Notes")
private String notes;
@JoinColumn(name = "ProductID", referencedColumnName = "ID")
@ManyToOne(optional = false, fetch = FetchType.LAZY)
@JsonIgnoreProperties
private Product productID;
@JoinColumn(name = "MerchantID", referencedColumnName = "ID")
@ManyToOne(optional = false, fetch = FetchType.LAZY)
private Merchent merchent;
@JoinColumn(name = "OrderSatusID", referencedColumnName = "ID")
@ManyToOne(optional = false, fetch = FetchType.EAGER)
private OrderStatus orderStatus;
// Getters and Setters
}
Order Holder
public class OrderHolder {
@NotNull
private Order order;
public Order getOrder() {
return order;
}
public void setOrder(Order order) {
this.order = order;
}
}
OrderRepo
public interface OrderRepo extends JpaRepository<Order, Integer> {
}
Order Controller
@RestController
@RequestMapping(value = "order", produces = MediaType.APPLICATION_JSON_VALUE)
public class OrderRestController extends BasicController<OrderHolder>{
@Autowired
private OrderRepo orderRepo;
@PostMapping("create")
public ResponseEntity<?> create(@RequestBody @Valid OrderHolder orderHolder, Principal principal) throws GeneralException {
log.debug( "create order {} requested", orderHolder.toString());
Order order = new Order();
order = orderHolder.getOrder();
System.out.println("###############"+order);
try {
order = orderRepo.save(order);
log.info( "Order {} has been created", order );
} catch (Exception e) {
log.error( "Error creating Order: ", e );
e.printStackTrace();
throw new GeneralException( Errors.ORDER_CREATION_FAILURE, e.toString() );
}
return ResponseEntity.ok( order );
}
}
I need request body to look like the below instead of including the full Merchant and Product objects inside the request.
Upvotes: 0
Views: 1716
Reputation: 155
I would like to share something regarding this. I have searched a lot on internet and tried lot of things, but the solution given here suited well for this scenario.
https://www.baeldung.com/jackson-deserialization
You need to create a Custom-deserializer for your model by extending StdDeserializer from com.fasterxml.jackson.databind.deser.std.StdDeserializer, where you just want to pass id's and not the whole object in the request.
I have given below example for User Model with Address object.
User(long userId, String name, Address addressId)
Address(long addressId, String wholeAddress)
Writing Deserializer for User class
public class UserDeserializer extends StdDeserializer<User> {
public User() {
this(null);
}
public User Deserializer(Class<?> vc) {
super(vc);
}
@Override
public User deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {
JsonNode node = p.getCodec().readTree(p);
long id = 0;
long addressId = (Long) ((IntNode) node.get("addressId")).numberValue().longValue();
return new User(id, name, new Address(addressId, null)
}
Now you have to use
@JsonDeserialize(using = UserDeserializer.class)
public Class User {
...
}
POST request
Before custom deserialization
{
"name" : "Ravi",
"addressId" : { "id" : 1}
}
After custom Deserialization
{
"name" : "Ravi",
"addressId" : 1
}
Also while GET /user/:id call you will get the whole obj like
{
"name" : "Ravi",
"addressId" : { "id" : 1, "wholeAddress" : "Some address"}
}
Upvotes: 0
Reputation: 646
You can make use of JsonView to return only id of product and merchant
public class OrderView {}
...
public class Product{
@Id
@JsonView(OrderView.class)
private Integer id
private String otherFieldWithoutJsonView
...
}
and then in your controller
@PostMapping("create")
@JsonView(OrderView.class) // this will return the product object with one field (id)
public ResponseEntity<?> create(@RequestBody @Valid OrderHolder orderHolder, Principal principal) throws GeneralException {
...
}
hope this can help you
Upvotes: 2
Reputation: 3671
Just have a separate contract class.
public class OrderContract {
private int merchantID;
private String notes;
....
//getter, setters
}
public class OrderHolder {
@NotNull
private OrderContract orderContract;
public OrderContract getOrderContract() {
return orderContract;
}
public void setOrder(OrderContract orderContract) {
this.orderContract = orderContract;
}
}
And before making a call to the Repository , translate from OrderContract to Order.
Upvotes: 1