I'm using Spring Boot 2.2, Spring Data REST, Spring HATEOAS.
I'm facing a strange problem. I've a RestController accepting this object:
#Data
public class DocumentJSON {
#Valid
private Document document;
private List<DocumentRow> rows = new ArrayList<>();
private List<DocumentVat> vats = new ArrayList<>();
private Set<DocumentPayment> payments = new HashSet<>();
private boolean updateContactDetail = false;
}
and DocumentPayment is:
#Data
#EqualsAndHashCode(callSuper = true, onlyExplicitlyIncluded = true)
#NoArgsConstructor
#AllArgsConstructor
#Builder
#ToString(callSuper = true)
public class DocumentPayment extends AbstractEntity {
#ToString.Exclude
#JsonDeserialize(using = DocumentUriDeserializer.class)
#NotNull
#OnDelete(action = OnDeleteAction.CASCADE)
#ManyToOne(fetch = FetchType.LAZY, optional = false)
private Document document;
#NotNull
#Column(nullable = false, columnDefinition = "DATE")
private Instant date;
//Optional contact (the receipt has not a contact)
#ToString.Exclude
#ManyToOne(fetch = FetchType.LAZY)
private Contact contact;
#NotBlank
#Column(nullable = false)
private String description;
#ToString.Exclude
#JsonDeserialize(using = FinancialAccountUriDeserializer.class)
#NotNull(message = "{documentpayment.financialaccount.missing}")
#ManyToOne(fetch = FetchType.LAZY, optional = false)
private FinancialAccount financialAccount;
#Enumerated(EnumType.STRING)
#NotNull
#Column(nullable = false, length = 30)
private PaymentType paymentType;
//The amount, negative for payment to suppliers
#NotNull
#ColumnDefault("0.00")
#Column(nullable = false, scale = 2, columnDefinition = "DECIMAL(12,2)")
private BigDecimal amount = BigDecimal.ZERO;
//The amount paid
#NotNull
#ColumnDefault("0.00")
#Column(nullable = false, columnDefinition = "DECIMAL(12,2)")
private BigDecimal paid = BigDecimal.ZERO;
#JsonProperty(access = JsonProperty.Access.READ_ONLY)
#Generated(value = GenerationTime.ALWAYS)
#Column(columnDefinition = "DECIMAL(12,2) AS (amount-paid) VIRTUAL NOT NULL")
private BigDecimal due;
#ToString.Exclude
#JsonDeserialize(using = StoreUriDeserializer.class)
//#NotNull(message = "{documentpayment.store.missing}")
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "store_id", updatable = false)
private Store store;
}
The client is sending a Json like this:
{
"document": {
"date": "2019-10-18T00:00:00.000Z",
"type": "SALES_RECEIPT",
"store": "http://95.255.117.252:8082/api/v1/stores/1",
"rounding": 0,
"amount": 19.23,
"taxAmount": 0.77,
"totalAmount": 20
},
"rows": [
{
"index": 1,
"productType": "FRAME",
"qty": 1,
"rowGroup": null,
"unitPrice": 9.615,
"percentageDiscount": 0,
"purchaseUnitPrice": null,
"amount": 9.615,
"description": "Prodotto1",
"taxRate": "http://95.255.117.252:8082/api/v1/taxRates/2",
"note": false
},
{
"index": 1,
"productType": "OPHTHALMIC_LENS",
"qty": 1,
"rowGroup": null,
"unitPrice": 9.615,
"percentageDiscount": 0,
"purchaseUnitPrice": null,
"amount": 9.615,
"description": "Lente",
"taxRate": "http://95.255.117.252:8082/api/v1/taxRates/2",
"note": false
}
],
"payments": [
{
"date": "2019-10-18T00:00:00.000Z",
"financialAccount": "http://95.255.117.252:8082/api/v1/financialAccounts/1",
"paymentType": "CASH",
"amount": "10"
},
{
"date": "2019-10-18T00:00:00.000Z",
"financialAccount": "http://95.255.117.252:8082/api/v1/financialAccounts/3",
"paymentType": "CREDIT_CARD",
"amount": "10"
}
],
"updateContactDetail": false
}
but when I debug in the first line of the REST controller I see only 1 payment.
Changing the property payments in DocumentJSON from Set<DocumentPayment> to List<DocumentPayment>, I get 2 payments as expected with the same JSON.
Am I missing something or Spring/Jackson are not able to deserialize in the right way a Set<>?
Related
i have this four classes:
#Entity
#Table(name = "products")
public class Product extends RegionDiscriminator {
#Column(nullable = false, name = "product_id")
private Long productId;
#Column(nullable = false, name = "name")
private String name;
#Column(nullable = false, name = "category_id")
private Long categoryId;
#Column(nullable = false, name = "unit")
private String unit;
#OneToMany(mappedBy = "product", cascade = CascadeType.ALL, orphanRemoval = true)
private List<SkuGroup> skuGroups = new ArrayList<>();
#OneToMany(mappedBy = "product", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Tax> taxes = new ArrayList<>();
#Column(nullable = false, name = "active")
private boolean active;
}
#Entity
#Table(name = "sku_groups")
public class SkuGroup extends RegionDiscriminator {
#Column(nullable = false, name = "name")
private String name;
#ManyToOne
#JoinColumn(name = "product_id")
private Product product;
#OneToMany(mappedBy = "skuGroup", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Sku> skus = new ArrayList<>();
#OneToMany(mappedBy = "skuGroup", cascade = CascadeType.ALL, orphanRemoval = true)
#OrderBy("period DESC")
private List<Cluster> clusters = new ArrayList<>();
}
#Entity
#Table(name = "skus")
public class Sku extends GrowthEntity {
#Column(nullable = false, name = "sku_id")
private Long skuId;
#Column(nullable = false, name = "name")
private String name;
#Column(nullable = false, name = "min_weight_unit")
private BigDecimal minWeightUnit;
#Column(name = "upc")
private String upc;
#OneToMany(mappedBy = "sku", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Tier> tiers = new ArrayList<>();
#OneToMany(mappedBy = "sku", cascade = CascadeType.ALL, orphanRemoval = true)
#Size(max = 10)
#OrderBy("creationTimestamp DESC")
private List<Price> prices = new ArrayList<>();
#ManyToOne
#JoinColumn(name = "sku_group_id")
private SkuGroup skuGroup;
#OneToMany(mappedBy = "sku", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Discount> discounts = new ArrayList<>();
#Column(nullable = false, name = "active")
private boolean active;
#OneToOne(mappedBy = "sku")
private SkuCost cost;
#OneToOne(mappedBy = "sku")
private SkuBenchmark benchmark;
#OneToMany(mappedBy = "sku", cascade = CascadeType.REMOVE, orphanRemoval = true)
private List<PricingProcessDetail> pricingProcessDetails;
}
#Entity
#Table(name = "prices")
public class Price extends GrowthEntity {
#Column(nullable = false, name = "retail_price")
private BigDecimal retailPrice;
#Column(nullable = false, name = "tax_price")
private BigDecimal taxPrice;
#Column(nullable = false, name = "pricing_price")
private BigDecimal pricingPrice;
#Column(nullable = false, name = "sale_price")
private BigDecimal salePrice;
#ManyToOne
#JoinColumn(name = "sku_id")
private Sku sku;
#ManyToMany(cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
})
#JoinTable(name = "price_discount",
joinColumns = #JoinColumn(name = "price_id"),
inverseJoinColumns = #JoinColumn(name = "discount_id")
)
private List<Discount> discounts = new ArrayList<>();
#ManyToMany(cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
})
#JoinTable(name = "price_tax",
joinColumns = #JoinColumn(name = "price_id"),
inverseJoinColumns = #JoinColumn(name = "tax_id")
)
private List<Tax> taxes = new ArrayList<>();
#OneToMany(mappedBy = "price", cascade = CascadeType.ALL, orphanRemoval = true)
private List<PriceTier> tiers = new ArrayList<>();
}
This are the methods executed by my service:
#Transactional
public Product updateProduct(final ProductDTO productDTO) {
final Product product = productDao.findByProductId(productDTO.getProductId())
.orElseThrow(() -> new GrowthNotFoundException(format("Product with id %s not found",
productDTO.getProductId())));
product.update(productDTO);
return save(product);
}
public Product update(final ProductDTO productDTO) {
categoryId = productDTO.getCategory() != null ? productDTO.getCategory().getId() : null;
name = productDTO.getName();
unit = productDTO.getUnit();
active = productDTO.isActive();
this.updateTaxes(productDTO);
this.updateSkuGroups(productDTO);
return this;
}
private void updateTaxes(final ProductDTO productDTO) {
List<Tax> newTaxes = buildTaxes(productDTO);
List<Tax> currentTaxes = new ArrayList<>(taxes);
if (!currentTaxes.equals(newTaxes)) {
taxes.clear();
taxes.addAll(newTaxes);
}
}
private void updateSkuGroups(final ProductDTO productDTO) {
Map<Long, Sku> skusMap = allSkus().stream()
.collect(Collectors.toMap(Sku::getSkuId, Function.identity()));
Map<String, List<SkuDTO>> newSkuGroups = ProductDTO.groupSkus(productDTO.getSkus());
Map<String, SkuGroup> currentSkuGroups = skuGroups.stream().collect(
Collectors.toMap(SkuGroup::getName, skuGroup -> skuGroup));
newSkuGroups.forEach((group, skus) -> {
if (currentSkuGroups.containsKey(group)) {
SkuGroup skuGroup = currentSkuGroups.get(group);
skuGroup.update(
skus.stream().map(skuDTO -> createOrUpdateSku(skusMap, skuDTO, skuGroup))
.collect(Collectors.toList()));
} else {
SkuGroup skuGroup = SkuGroup.create(group, this);
skuGroup.update(
skus.stream().map(skuDTO -> createOrUpdateSku(skusMap, skuDTO, skuGroup))
.collect(Collectors.toList()));
skuGroups.add(skuGroup);
}
});
currentSkuGroups.forEach((group, skuGroup) -> {
if (!newSkuGroups.containsKey(group)) {
skuGroups.remove(skuGroup);
}
});
}
private Sku createOrUpdateSku(Map<Long, Sku> skusMap, SkuDTO skuDTO, SkuGroup skuGroup) {
if (skusMap.containsKey(skuDTO.getId())) {
return skusMap.get(skuDTO.getId()).update(skuDTO, skuGroup);
} else {
return Sku.create(skuDTO, skuGroup);
}
}
public static Sku create(final SkuDTO skuDTO, final SkuGroup skuGroup) {
Sku sku = Sku.builder()
.withSkuId(skuDTO.getId())
.withMinWeightUnit(skuDTO.getMinWeightUnit())
.withUpc(skuDTO.getUpc())
.withName(skuDTO.getName())
.withSkuGroup(skuGroup)
.isActive(skuDTO.isActive())
.build();
sku.createTiers(skuDTO.getTiers(), skuDTO.getPrice());
sku.createPrice(skuDTO);
return sku;
}
public Sku update(final SkuDTO skuDTO, final SkuGroup theSkuGroup) {
minWeightUnit = skuDTO.getMinWeightUnit();
upc = skuDTO.getUpc();
name = skuDTO.getName();
skuGroup = theSkuGroup;
active = skuDTO.isActive();
this.updateTiers(skuDTO.getTiers(), skuDTO.getPrice());
this.updatePriceFromRetailPrice(skuDTO.getPrice());
return this;
}
This is an example of ProductDTO:
{
"productId": 16825,
"name": "Producto prueba pricing 30",
"category": {
"id": 100515,
"name": "Categoria prueba 13"
},
"iva": null,
"unit": "UNID",
"activeStartDate": "2022-11-22 12:18:08",
"activeEndDate": "2022-11-22 12:18:08",
"skus": [
{
"id": 22937,
"upc": "BOG-FRU1-CAT4252-16825:17883:17882:22937",
"name": "Producto prueba pricing 30 (Caja x 12) - 30 unidades 160g",
"owner": {
"id": 1,
"name": "Frubana"
},
"price": 999,
"stepUnit": 1,
"minWeightUnit": 1,
"conversion": {
"conversionTypeX": "UNID",
"conversionValueX": null,
"conversionTypeY": null,
"conversionValueY": null
},
"slot": false,
"cooled": false,
"activeStartDate": "2022-10-19 12:17:04",
"activeEndDate": "2022-10-19 12:17:04",
"tiers": null,
"group": "(Caja x 24)",
"active": true
},
{
"id": 22938,
"upc": "BOG-FRU1-CAT4252-16825:17885:17884:22938",
"name": "Producto prueba pricing 30 (Caja x 24) - 30 unidades de 150g",
"owner": {
"id": 1,
"name": "Frubana"
},
"price": 888,
"stepUnit": 1,
"minWeightUnit": 1,
"conversion": {
"conversionTypeX": "UNID",
"conversionValueX": null,
"conversionTypeY": null,
"conversionValueY": null
},
"slot": false,
"cooled": false,
"activeStartDate": "2022-10-19 12:17:04",
"activeEndDate": "2022-10-19 12:17:04",
"tiers": null,
"group": "(Caja x 12)",
"active": true
},
{
"id": 22939,
"upc": "BOG-FRU1-CAT4252-16825:17887:17886:22939",
"name": "Producto prueba pricing 30 (Caja x 24) - 30 unidades de 160g",
"owner": {
"id": 1,
"name": "Frubana"
},
"price": 777,
"stepUnit": 1,
"minWeightUnit": 2,
"conversion": {
"conversionTypeX": "UNID",
"conversionValueX": null,
"conversionTypeY": null,
"conversionValueY": null
},
"slot": false,
"cooled": false,
"activeStartDate": "2022-10-19 12:17:04",
"activeEndDate": "2022-10-19 12:17:04",
"tiers": null,
"group": "(Caja x 24)",
"active": true
}
],
"image": "/cmsstatic/products/sku_sin_imagen.png",
"active": true
}
My goal is to assign the SKUs to their respective SKU Groups based on the name, eliminating the groups that are left empty and creating the new ones that are necessary.
The code works for the first part, but fails when the reassignment needs the creation of a new group.
ERROR: null value in column "sku_id" violates not-null constraint
I have following relationship in my spring boot:
public class Clazz {
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Id
#Column(name = "id")
private Integer id;
#Column(name = "lesson_id")
#NotNull(message = "{lesson.is_required}")
private Integer lessonId;
#Column(name = "level_id")
#NotNull(message = "{level.is_required}")
private Integer levelId;
#Column(name = "name")
#NotEmpty(message = "{name.is_required}")
private String name;
#OneToOne
#JoinColumn(name = "lesson_id", referencedColumnName = "id", insertable = false, updatable = false)
private Lesson lesson;
#OneToOne
#JoinColumn(name = "level_id", referencedColumnName = "id", insertable = false, updatable = false)
private Level level;
}
Now my Lesson entity has Level entity:
public class Lesson {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Column(name = "name")
#NotEmpty(message = "{name.is_required}")
private String name;
#Column(name = "description")
private String description = "";
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "lesson_id")
Collection<Level> levels = new ArrayList<>();
}
And finally my Level class:
public class Level {
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Id
#Column(name = "id", insertable = false, updatable = false)
private Integer id;
#Column(name = "lesson_id")
private Integer lessonId;
#Column(name = "name")
private String name;
#Column(name = "step")
private Integer step;
#Column(name = "description")
private String description="";
}
With this relationship defined, when I fetch data, getting some extra info in my results:
[
{
"id": 2,
"lessonId": 1,
"levelId": 1,
"name": "English Class March",
"branch": {
"id": 1,
"name": "3 mikr branch",
"email": "",
"phone": "",
"address": "3 mikr, foo, bar"
},
"lesson": {
"id": 1,
"name": "math",
"description": "math lesson",
"levels": [
{
"id": 1,
"lessonId": 1,
"name": "First level",
"step": 1,
"description": "1st level descr"
}
]
},
"level": {
"id": 1,
"lessonId": 1,
"name": "First level",
"step": 1,
"description": "1st level descr"
}
}
]
How can I tell JPA not to fetch sub-entities, ideally I do not need levels in lesson field of result.
Use #JsonIgnore. It can be used at setter,getter or field.
Please refer the code below.
public class Lesson {
#Id #Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Column(name = "name")
#NotEmpty(message = "{name.is_required}")
private String name;
#Column(name = "description")
private String description = "";
#JsonIgnore // Add this to ignore the property in json output
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "lesson_id")
Collection<Level> levels = new ArrayList<>();
}
I have 4 tables
Area: it is a catalog where there are all the departments of an organization (parent)
SubAreas: It is a catalog where there are all the subAreas that belong to before catalog (Area), that is (child)
personal: Catalog where all the employees of the organization exist
personal Area: It is a table where there are all the relationships between the tables previously described
The business logic is simple, an employee can belong to one of several areas and only one subarea for each area to which they belong.
Here my relationships
These are my entities
Personal
#Entity
#Table(name = "personal", catalog = "almacen", schema = "")
public class Personal {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id")
private Long id;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 30)
#Column(name = "curp")
private String curp;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 200)
#Column(name = "nombre")
private String nombre;
#JsonIgnore
#OneToMany(mappedBy = "personal")
private Set<PersonalArea> registrations = new HashSet<>();
}
PersonalArea
#Getter
#Setter
#Entity
#Table(name = "personal_area", catalog = "almacen", schema = "")
#XmlRootElement
public class PersonalArea {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#NotNull
private Long id;
#ManyToOne
#JoinColumn(name = "personal_id")
private Personal personal;
#ManyToOne
#JoinColumn(name = "area_id")
private Area area;
#ManyToOne
#JoinColumn(name = "subarea_id")
private subArea subArea;
private Date fechaCreacion;
}
Area
#Getter
#Setter
#Entity
#Table(name = "area", catalog = "almacen", schema = "")
#XmlRootElement
public class Area {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#NotNull
private Long id;
private String nombreArea;
#JsonIgnore
#OneToMany(mappedBy = "area")
private Set<PersonalArea> registrations = new HashSet<>();
}
SubArea
#Getter
#Setter
#Entity
#Table(name = "sub_area", catalog = "almacen", schema = "")
public class subArea {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#NotNull
private Long id;
private Long idArea;
private String nombre;
#JsonIgnore
#OneToMany(mappedBy = "personal")
private Set<PersonalArea> registrations = new HashSet<>();
}
Actually I get something like this
As you can see, the json has two times the same personal who belongs to two areas and one subarea for each area... It's ok, but I don't want this json
{
"items": [{
"id": 1,
"personal": {
"id": 1,
"curp": "AEMM680119HHGRRR03",
"nombre": "MARIO RUBIZEL",
"primerApellido": "ARTEAGA",
"segundoApellido": "MORALES",
"telefono": "7711263949",
"fechaCreacion": null,
"fechaModificacion": null
},
"area": {
"id": 2,
"nombreArea": "PERSONAL ADMINISTRATIVO"
},
"subArea": {
"id": 1,
"idArea": 2,
"nombre": "CONTROL ESCOLAR"
},
"fechaCreacion": "2021-06-24T16:26:49.000+00:00"
},
{
"id": 2,
"personal": {
"id": 1,
"curp": "AEMM680119HHGRRR03",
"nombre": "MARIO RUBIZEL",
"primerApellido": "ARTEAGA",
"segundoApellido": "MORALES",
"telefono": "7711263949",
"fechaCreacion": null,
"fechaModificacion": null
},
"area": {
"id": 5,
"nombreArea": "PERSONAL EXTERNO"
},
"subArea": {
"id": 2,
"idArea": 5,
"nombre": "FOTOCOPIADO"
},
"fechaCreacion": "2021-06-24T16:26:49.000+00:00"
}
]
}
I need my json something like this: Show just once personal and areas y subareas as child
{
"items": [{
"id": 1,
"personal": {
"id": 1,
"curp": "AEMM680119HHGRRR03",
"nombre": "MARIO RUBIZEL",
"primerApellido": "ARTEAGA",
"segundoApellido": "MORALES",
"telefono": "7711263949",
"fechaCreacion": null,
"fechaModificacion": null
},
"area": [{
"id": 1,
"nombreArea": "DIRECTOR",
"subArea": {
"id": 1,
"idArea": 2,
"nombre": "CONTROL ESCOLAR"
}
},
{
"id": 5,
"nombreArea": "PERSONAL EXTERNO",
"subArea": {
"id": 2,
"idArea": 5,
"nombre": "FOTOCOPIADO"
}
}
],
"fechaCreacion": "2021-06-24T16:26:49.000+00:00"
}
]
}
thanks in advance
This is my entity class , which I am using to save the details of customer along with the purchase detail and product purchased and payment module , Its finely saving in DB but while retrieving getting result as null .
#Entity
#Table(name = "productpurchasedata")
public class Test {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int customerid;
#ManyToOne(cascade = { CascadeType.ALL })
#JoinColumn(name = "customerid", insertable = false, updatable = false)
private CustomerProductSave customerProductSave;
#ManyToOne(cascade = { CascadeType.ALL })
#JoinColumn(name = "customerid", insertable = false, updatable = false)
private PurchaseDetails purchasedetails;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "customerid")
private List<ProductPurchased> productpurchased;
#ManyToOne(cascade = { CascadeType.ALL })
#JoinColumn(name = "customerid", insertable = false, updatable = false)
private PaymentHistory paymenthistory;
Here I am able to save the data which result in something like this :-
{
"customerid": 1,
"customerProductSave": {
"customerids": 2,
"name": "nitesh",
"mailid": "niteshbhushan95#gmail.com",
"address": "hyd",
"city": "telanagana",
"state": "telanagana",
"postalcode": "847226",
"mobileno": 6300769631
},
"purchasedetails": {
"purchasedate": "22-07-2021",
"modeofpayment": "paytm",
"emiapplicable": false,
"totalamount": 21000,
"purchaseId": 4
},
"productpurchased": [
{
"purchaseid": 5,
"purchaseamount": 2000,
"purchasedproductid": 1,
"productquantity": 0
},
{
"purchaseid": 6,
"purchaseamount": 2000,
"purchasedproductid": 1,
"productquantity": 0
}
],
"paymenthistory": {
"transactionid": 3,
"paymentstatus": "paid"
}
}
Now when I am trying to retrieve the data by customerid it is not accepting , it giving message as null , I am not pretty much may be some mistake in mapping
try using fetch = FetchType.EAGER instead of fetch = FetchType.LAZY at all mappings
purchase detail and product purchased and payment module
I am developing simple API for practice project Online Shopping system. Since I am very new in working with APIs, I am having a trouble with my Entities and relationships. First, I give all my schema and classes before introduce the problem.
Here is a link for my database schema.
These are #Entity classes:
----
#Entity
#Table(name = "Customer")
public class Customer {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private int id;
#Column(name = "name")
private String name;
#Column(name = "country")
private String country;
#OneToMany(mappedBy = "customer", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Order> orders = new ArrayList<>();
// constructor, getters, setters ....
#Entity
#Table(name = "Order")
public class Order {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private int id;
#Column(name = "date")
private Date date;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "cust_id", nullable = false)
#JsonIgnore
private Customer customer;
#OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Detail> details = new ArrayList<>();
#OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Invoice> invoices = new ArrayList<>();
//constructor, setters, getters ....
#Entity
#Table(name = "Product")
public class Product {
#Id
#GeneratedValue
#Column(name = "id")
private int id;
#Column(name = "name")
private String name;
#Column(name = "description")
private String description;
#Column(name = "price")
private Double price;
#OneToMany(mappedBy = "product", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Detail> orderDetails = new ArrayList<>();
//cons, setters, getters ...
#Entity
#Table(name = "Detail")
public class Detail {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "ord_id", nullable = false)
#JsonIgnore
private Order order;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "pr_id", nullable = false)
#JsonIgnore
private Product product;
#Column(name = "quantity")
private int quantity;
//similar classes for Invoice and Payment (no problem with them)
Here is my Sample Repository class:
#Repository
public interface ProductRepository extends JpaRepository<Product, Integer> {
}
Also here is my controller class:
#RestController
public class OnlineShoppingApiController {
#Autowired
ProductRepository productRepository;
#Autowired
OrderRepository orderRepository;
#Autowired
CustomerRepository customerRepository;
#Autowired
DetailRepository detailRepository;
#Autowired
InvoiceRepository invoiceRepository;
#Autowired
PaymentRepository paymentRepository;
#GetMapping("/products")
public List<Product> getProductsList(){
return productRepository.findAll();
}
#GetMapping("/customers")
public List<Customer> getCustomersList(){
return customerRepository.findAll();
}
#GetMapping("/orders")
public List<Order> getOrdersList(){
return orderRepository.findAll();
}
#GetMapping("/invoices")
public List<Invoice> getInvoicesList(){
return invoiceRepository.findAll();
}
#GetMapping("/payments")
public List<Payment> getPaymentsList(){
return paymentRepository.findAll();
}
#GetMapping("/details")
public List<Detail> getDetailsList(){
return detailRepository.findAll();
}
I am doing the same approach for all APIs and relationships.
When I call for /products in postman, I am getting result JSON like this:
[{
"id": 3,
"name": "pname_816",
"description": "pdesc_871_871_871_87",
"price": 1.41,
"orderDetails": [
{
"id": 9,
"quantity": 831
},
{
"id": 51,
"quantity": 701
},
{
"id": 87,
"quantity": 310
}
]
},
{
"id": 4,
"name": "pname_395",
"description": "pdesc_495_495_495_49",
"price": 26.65,
"orderDetails": [
{
"id": 85,
"quantity": 853
}
]
}]
Same fine results for /details, /invoices, and /payments.
The problem is if I send GET request for /customers, the result:
{
"timestamp": "2018-04-05T11:53:39.558+0000",
"status": 500,
"error": "Internal Server Error",
"message": "Could not write JSON: could not extract ResultSet; nested exception is com.fasterxml.jackson.databind.JsonMappingException: could not extract ResultSet (through reference chain: java.util.ArrayList[0]->com.example.project.pojo.Customer[\"orders\"])",
"path": "/customers"
}
And if i send request for /orders, the result is:
{
"timestamp": "2018-04-05T11:54:37.316+0000",
"status": 500,
"error": "Internal Server Error",
"message": "could not extract ResultSet; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet",
"path": "/orders"
}
The same approach is not working for all. I cannot understand where the problem is. Please help me to find it.
Thanks for the answer
I have finally found the answer by myself. Here the problem is not with Annotation or key referencing but with the naming the Entities.
Since order is reserved keyword for MySql, naming the entity and variables like this causes unexpected problems.
So I have just changed the Entity name to Orders in schema and code and working fine.
Hope this post will help for others too