I tried to implement a REST service with Java, Hibernate, and Spring, which returns JSON.
I have map a many to many relation. I have a supplier that has a list of ingredients, and each ingredient has a list of suppliers.
I created the table:
CREATE TABLE supplier_ingredient (
supplier_id BIGINT,
ingredient_id BIGINT
)
ALTER TABLE supplier_ingredient ADD CONSTRAINT supplier_ingredient_pkey
PRIMARY KEY(supplier_id, ingredient_id);
ALTER TABLE supplier_ingredient ADD CONSTRAINT
fk_supplier_ingredient_ingredient_id FOREIGN KEY (ingredient_id)
REFERENCES ingredient(id);
ALTER TABLE supplier_ingredient ADD CONSTRAINT
fk_supplier_ingredient_supplier_id FOREIGN KEY (supplier_id) REFERENCES
supplier(id);
Then I have an Ingredient model:
.....
.....
@ManyToMany(mappedBy = "ingredients")
@OrderBy("created DESC")
@BatchSize(size = 1000)
private List<Supplier> suppliers = new ArrayList<>();
....
....
Then I have a Supplier model:
....
@ManyToMany
@JoinTable( name = "supplier_ingredient ",
joinColumns = @JoinColumn(name = "supplier_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(name = "ingredient_id", referencedColumnName = "id"),
foreignKey = @ForeignKey(name = "fk_supplier_ingredient_supplier_id"))
@OrderBy("created DESC")
@Cascade(CascadeType.SAVE_UPDATE)
@BatchSize(size = 1000)
private List<Ingredient> ingredients = new ArrayList<>();
....
Endpoint:
@RequestMapping(value = "/{supplierId:[0-9]+}", method = RequestMethod.GET)
@ResponseStatus(value = HttpStatus.OK)
@ResponseBody
public SupplierObject get(@PathVariable Long supplierId) {
Supplier supplier = supplierService.get(supplierId);
SupplierObject supplierObject = new SupplierObject (supplier);
return SupplierObject;
}
Service
....
public Supplier get(Long supplierId) {
Supplier supplier = supplierDao.getById(supplierId); (it does entityManager.find(entityClass, id))
if (supplier == null) throw new ResourceNotFound("supplier", supplierId);
return supplier;
}
....
SupplierObject
@JsonIgnoreProperties(ignoreUnknown = true)
public class SupplierObject extends IdAbstractObject {
public String email;
public String phoneNumber;
public String address;
public String responsible;
public String companyName;
public String vat;
public List<Ingredient> ingredients = new ArrayList<>();
public SupplierObject () {
}
public SupplierObject (Supplier supplier) {
id = supplier.getId();
email = supplier.getEmail();
responsible = supplier.getResponsible();
companyName = supplier.getCompanyName();
phoneNumber = supplier.getPhone_number();
ingredients = supplier.getIngredients();
vat = supplier.getVat();
address = supplier.getAddress();
}
}
And IdAbstractObject
public abstract class IdAbstractObject{
public Long id;
}
My problem is, when I call the endpoint:
http://localhost:8080/supplier/1
I got an error:
"Could not write JSON: failed to lazily initialize a collection of role: myPackage.ingredient.Ingredient.suppliers, could not initialize proxy - no Session; nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: myPackage.ingredient.Ingredient.suppliers, could not initialize proxy
- no Session (through reference chain: myPackage.supplier.SupplierObject["ingredients"]->org.hibernate.collection.internal.PersistentBag[0]->myPackage.ingredient.Ingredient["suppliers"])"
I followed this:
Avoid Jackson serialization on non fetched lazy objects
Now I haven't the error but in json returned, the ingredients field is null:
{
"id": 1,
"email": "[email protected]",
"phoneNumber": null,
"address": null,
"responsible": null,
"companyName": "Company name",
"vat": "vat number",
"ingredients": null
}
but in debug I can see ingredients....