I have a simple Entity with a single collection mapped.
@Entity
public class Appointment Identifiable<Integer> {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@JsonIgnore
private Integer id;
@Column(name="TRAK_NBR")
private String trackNumber;
@OneToMany(fetch =FetchType.EAGER, cascade= CascadeType.ALL)
@JoinColumn(name="CNSM_APT_VER_WRK_I", nullable = false)
private Set<Product> products = new HashSet<Product>();
}
@Entity
public class Product implements Identifiable<Integer> {
@Id
@Column(name = "CNSM_PRD_VER_WRK_I")
@GeneratedValue(strategy = GenerationType.AUTO)
@JsonIgnore
private Integer id;
@Column(name = "PRD_MDL_NBR")
private String model;
@Column(name = "PRD_SPEC_DSC")
private String description;
}
In my application when I only include a PagingAndSortingRepository for Appointment. I can call the POST command with the following payload.
{
"trackNumber" : "XYZ123",
"products": [
{"model" : "MODEL",
"description" : "NAME"
}]
}
When I add a PagingAndSortingRepository for Product and try the same POST I get the following error message.
{
"cause" : {
"cause" : {
"cause" : null,
"message" : null
},
"message" : "(was java.lang.NullPointerException) (through reference chain: com..model.Appointment[\"products\"])"
},
"message" : "Could not read JSON: (was java.lang.NullPointerException) (through reference chain: com.model.Appointment[\"products\"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: com.model.AppointmentVerification[\"products\"])"
}
My GET payload with both Repositories returns this. This is my desired format. The link to products should be included
{
"trackNumber" : "XYZ123",
"_links" : {
"self" : {
"href" : "http://localhost:8080/consumerappointment/appointments/70"
},
"products" : {
"href" : "http://localhost:8080/consumerappointment/appointments/70/products"
}
}
With only the Appointment repository I get the following payload and can post the list of products.
{
"trackNumber" : "XYZ123",
"products" : [ {
"model" : "MODEL",
"description" : "NAME",
} ],
"_links" : {
"self" : {
"href" : "http://localhost:8080/consumerappointment/appointments/1"
}
}
}
Let's take a step back and make sure you understand what's happening here: if a repository is detected, Spring Data REST exposes a dedicated set of resources for it to manage the aggregates handled by the repository via HTTP. Thus, if you have repositories for multiple entities related to each other, the relationship is represented as a link. This is why you see the products inlined with only the AppointmentRepository
in place and the products
link in place once you create a ProductRepository
.
If you want to expose both repositories as resources, you need to hand the URIs of the Product
instances in the payload for the POST
to create an Appointment
. That means, instead of posting this:
{ "trackNumber" : "XYZ123",
"products": [
{ "model" : "MODEL",
"description" : "NAME"
}
]
}
you'd create a Product
first:
POST /products
{ "model" : "MODEL",
"description" : "NAME" }
201 Created
Location: …/products/4711
And then hand the ID of the product to the Appointment
payload:
{ "trackNumber" : "XYZ123",
"products": [ "…/products/4711" ]}
In case you don't want any of this (no resources exposed for Product
in the first place, use @RepositoryRestResource(exported = false)
on PersonRepository
. That would still leave you with the bean instance created for the repo, but no resources exported and the resource exposed for Appointment
s back to inlining related Product
s.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With