Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't POST a collection

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"
    }
  }
}
like image 936
zachariahyoung Avatar asked Jun 22 '14 23:06

zachariahyoung


1 Answers

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 Appointments back to inlining related Products.

like image 118
Oliver Drotbohm Avatar answered Oct 21 '22 18:10

Oliver Drotbohm