Spring JPA #ManyToOne and #OneToMany does not update all - spring-boot

I have two classes Post and Comment, one post can have multiple comments. So I have created my classes as follows:
Post:
#Entity
#Table(name = "posts")
public class Post extends AuditModel {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotNull
#Size(max = 100)
#Column(unique = true)
private String title;
#NotNull
#Size(max = 250)
private String description;
#NotNull
#Lob
private String content;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "post")
private Set<Comment> comments = new HashSet<>();
}
Comment:
#Entity
#Table(name = "comments")
public class Comment extends AuditModel {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotNull
#Lob
private String text;
#ManyToOne(fetch = FetchType.EAGER, optional = false)
#JoinColumn(name = "post_id", nullable = false)
#OnDelete(action = OnDeleteAction.CASCADE)
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
#JsonIdentityReference(alwaysAsId = true)
#JsonProperty("post_id")
private Post post;
}
Post method:
#PostMapping("/posts")
public Post createPost(#Valid #RequestBody Post post) {
return postRepository.save(post);
}
Swagger request:
{
"id": 0,
"title": "string",
"description": "string",
"content": "string",
"comments": [
{
"id": 0,
"text": "string",
"post_id": 0
}
]
}
When I do a POST using the above schema, I am expecting that hibernate will insert data in both the tables. But instead, I get below error:
Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Unresolved forward references for: ; nested exception is com.fasterxml.jackson.databind.deser.UnresolvedForwardReference: Unresolved forward references for:
at [Source: (PushbackInputStream); line: 1, column: 117]Object id [1] (for `com.example.jpa.model.Post`) at [Source: (PushbackInputStream); line: 1, column: 115].]
Can someone please help me to understand this and how can I achieve my requirement?

Related

Multipartfile charset=UTF-8 is not supported spring boot api rest

The code was working normally and I've tried in every way to solve it and I couldn't, it may be that after I transformed the MultipartFile into an array this happened
#RestController
#RequestMapping("products")
public class ProductController {
#Autowired
private ProductService productService;
#PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
#Transactional
public ResponseEntity<ShowProductsDTO> registerProduct(
#RequestBody #Valid ProductDTO dto,
#RequestParam(name = "files", required = true) MultipartFile[] files,
UriComponentsBuilder uriBuilder) {
ShowProductsDTO showProductsDTO = null;
try {
showProductsDTO = productService.save(dto, files);
} catch (IOException e) {
e.printStackTrace();
}
var uri = uriBuilder.path("/products/{id}").buildAndExpand(showProductsDTO.id()).toUri();
return ResponseEntity.created(uri).body(showProductsDTO);
}
DTO
public record ProductDTO(
#NotBlank
String name,
#NotBlank
String description,
#NotNull
#NumberFormat
BigDecimal price,
#NumberFormat
#NotNull
Integer quantity,
#NotNull
Boolean active,
#NotNull
Long sub_category_id
) {
}
Error console
Resolved [org.springframework.web.HttpMediaTypeNotSupportedException:
Content-Type
'multipart/form-data;boundary=--------------------------816548045966415708649211;charset=UTF-8'
is not supported]
Postman body > raw > json
{
"name": "Nome do produto",
"description": "descricao do produto",
"price": "2500.00",
"quantity": "2",
"active": "true",
"sub_category_id": "1"
}
Postman > body > form-data
KEY "files", TYPE file, VALUE uma imagem minha em png
Error postman
{
"timestamp": "2023-01-11T06:15:43.455+00:00",
"status": 415,
"error": "Unsupported Media Type",
"message": "Content-Type 'multipart/form-data;boundary=--------------------------056640214920648036756520;charset=UTF-8' is not supported.",
"path": "/products"
}
Product entity
#Table(name = "products")
#Entity(name = "Product")
#Getter
#Setter
#NoArgsConstructor
#EqualsAndHashCode(of = "id")
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(length = 100, unique = true, nullable = false)
private String name;
#Column(nullable = false, columnDefinition = "TEXT")
private String description;
#Column(length = 8, nullable = false, columnDefinition = "NUMERIC(8,2)")
private BigDecimal price;
#Column(nullable = false, columnDefinition = "INT")
private Integer quantity;
#Column(nullable = false, columnDefinition = "BOOLEAN")
private Boolean active;
#CollectionTable(name = "products_files",
joinColumns =
#JoinColumn(name = "product_id", referencedColumnName = "id"))
private List<String> productFiles;
#JoinColumn(name = "sub_category_id")
#ManyToOne(fetch = FetchType.EAGER)
private SubCategory subCategory;
how do I fix this error?
Change your attribute to #PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
and call your api using Postman body > raw > json.
The thing is, Content-Type: form-data handles file requests.

DTO and Entities mapping

I am building a Spring Rest Application, I need help with DTO's and parsing a result to a endpoint
This is json that I return at the moment to the endpoint:
{
"id": 1,
"name": "Ella - IPA Is Dead",
"description": "2015 IPA is Dead Series. Supremely floral, this hugely under-rated hop is related to Galaxy and was first cultivated in the Australian state of Victoria.",
"method": {
"mash_temp": [
{
"temp": {
"value": 65
}
}
]
}
}
I don't want to return "method" from this json, I just need "id", "name", "description", "mash_temp" - so it should look like this:
{
"id": 1,
"name": "Ella - IPA Is Dead",
"description": "2015 IPA is Dead Series. Supremely floral, this hugely under-rated hop is related to Galaxy and was first cultivated in the Australian state of Victoria. Initially given the same name as a certain Eurolager, their lawyers got involved and the St- prefix was dropped. Ella displays subtle notes of spice, but is fundamentally a truly floral bouquet, redolent of the Southern Hemisphere.",
"mash_temp": [
{
"temp": {
"value": 65
}
}
]
}
Those are the entities that I am using now:
Beer Entity:
#Entity
public class Beer implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "beer_id", unique = true, nullable = false)
private Integer id;
#Column(name = "name", nullable = false)
private String name;
#JsonProperty("description")
#Column(name = "description", nullable = false, columnDefinition = "TEXT")
private String description;
#JsonProperty("method")
#OneToOne(cascade = CascadeType.ALL)
private Method method;
}
Method Entity:
#Entity
public class Method implements Serializable
{
#JsonIgnore(value = true)
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#JsonProperty("mash_temp")
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "mash_temp")
private List<MashTemp> mash_temp = new ArrayList<>();
}
MashTemp Entity:
#Entity
public class MashTemp implements Serializable
{
#JsonIgnore(value = true)
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#OneToOne(cascade = CascadeType.ALL)
private Temp temp;
#ManyToOne
private Method method;
}
Temp Entity:
#Entity
public class Temp implements Serializable
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private Integer value;
#JsonIgnore(value = true)
private String unit;
#OneToOne
private MashTemp mashTemp;
}
Does anyone know how to create DTO's from this Entities but without "method" field?
Also this is my Controller:
#GetMapping("/beers")
public ResponseEntity<Set<Beer>> getAllBeers()
{
return new ResponseEntity<>(beerService.getAllBeers(), HttpStatus.OK);
}
#GetMapping("/beers/{id}")
public ResponseEntity<Beer> getById(#PathVariable Integer id) {
Beer beer = beerService.findById(id);
return new ResponseEntity<>(beer, HttpStatus.OK);
}
Have a look at the #JsonUnwrapped annotation (https://fasterxml.github.io/jackson-annotations/javadoc/2.8/com/fasterxml/jackson/annotation/JsonUnwrapped.html). You can put it on the method field in the Beer class, and then the properties of the Method class are serialized directly on the same level as the ones from Beer.

Caused by: javax.persistence.NonUniqueResultException: query did not return a unique result: 2 For Save data

I can not save Data. When I saved post request got error?
#Entity
#Table(name = "ALKP")
public class ALKP {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String title;
#Column(name = "KEYWORD")
private String keyword;
private String code;
private Long slNo;
private String fullName;
private boolean isActive;
#CreationTimestamp
#Column(name = "created_at",updatable = false)
private LocalDate createDate;
#UpdateTimestamp
#Column(name = "updated_at")
private LocalDateTime updateDateTime;
#ManyToOne
#JoinColumn(name="parentId")
public ALKP parentId;
#OneToMany(mappedBy="parentId")
public Set<ALKP> subALKP = new HashSet<>();
Data ::
PostMan Body Request Data
{
"title": "FeMale",
"keyword": "GENDER_FEMALE",
"slNo": 2,
"active": true,
"code": "MC-00209",
"fullName": "FEMALE",
"parentId":700
}
"message": "detached entity passed to persist error in Spring Boot when consuming a rest service",
When I saved data it can not be catch Parent ALKP . I think It can be
parentId:{
"id":700
}
seems your ALKP enity have same parentId. or your defined the association mab be wrong.
#ManyToOne
#JoinColumn(name="parentId")
public ALKP parentId;
#OneToMany(mappedBy="parentId")
public Set<ALKP> subALKP = new HashSet<>();
Above both are pointng same ALKP and its Id then how can you get one and many object in same enity?

One to Many bidirectional

I have problems with Many to One relationship because I don't show correctly the entity.
Could anyone helps to me ?
I attached my code.
Invoice
#Entity
#Table(name = "invoices")
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,property = "id")
public class Invoice {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String clave;
#OneToMany(mappedBy = "invoice", cascade = CascadeType.REMOVE, fetch = FetchType.LAZY, orphanRemoval = true)
private List<InvoiceLine> lines;
InvoiceLines
#Entity
#Table(name = "invoice_lines")
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,property = "id")
public class InvoiceLine {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "product", nullable = false)
private String product;
#ManyToOne
#JoinColumn(name = "invoice_id", referencedColumnName = "id", nullable = false)
private Invoice invoice;
Controller
#RestController
public class InvoiceController{
#Autowired
private InvoiceRepository invoiceRepository;
#Autowired
private InvoiceLineRepository invoiceLineRepository;
#GetMapping("/")
public Iterable<Invoice> findAllnvoices(){
return invoiceRepository.findAll();
}
#GetMapping("/invoiceLine")
public Iterable<InvoiceLine> findAllInvoiceLine(){
return invoiceLineRepository.findAll();
}
#GetMapping("/{id}")
public Optional<Invoice> findTagByInvoice(#PathVariable("id") Long id){
return invoiceRepository.findById(id);
}
}
The response when I call a endpoint invoiceLine :
[
{
"id": 1,
"product": "Tag1-ES",
"invoice": {
"id": 1,
"clave": "Tag1",
"lines": [
1,
{
"id": 2,
"product": "Tag1-FR",
"invoice": 1
},
{
"id": 3,
"product": "Tag1-IT",
"invoice": 1
}
]
}
},
2,
3
]
My question :Why is not showing correctly the response the ManyToOne entity if I have all correct ?
If I understood your problem correctly after the comments, you are bothered by the "numbers" that are displayed. Those numbers are used to avoid infinite recursion, and they refer to entities that were already displayed.
So the number "2" would be this actually:
{
"id": 2,
"product": "Tag1-FR",
"invoice": 1
}
If a representation like that is not used, then the whole invoice and it's items would be repeated infinitely.
There are several different ways to avoid this behavior, such as using #JsonIgnore or #JsonBackReference and #JsonManagedReference. Take a look at this explanation about their differences
Difference between #JsonIgnore and #JsonBackReference, #JsonManagedReference

Add entity with OneToOne Relation using JPA and REST

I am using Spring JPA Restful, and I don't understand how to insert an entity with a foreign key.
Activity Entity:
#Entity
#Table(name= "Activity")
public class Activity implements Serializable{
#Id
#GeneratedValue(generator = "uuid")
#GenericGenerator(name="uuid", strategy = "uuid2")
#Column(name = "uuid", nullable = false, unique = true)
private UUID uuid;
#OneToOne(fetch = FetchType.EAGER, cascade=CascadeType.MERGE)
#JoinColumn(name="type", nullable = false)
private ActivityType type;
#Column(nullable = false)
private String label;
ActivityType Entity:
#Entity
#Table(name= "ActivityType")
public class ActivityType implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(nullable = false, unique = true)
private String code;
#Column(nullable = false
private String label;
Is it possible to insert Activity simply? With something like this JSON where ActivityType's id "1" exists:
createActivity:
{"label":"LABEL","type":1}
With this code I have to do:
createActivity:
{"label":"LABEL","type":{"id":1}}
which return value is:
{
"uuid": "a54b27aa-8d49-41fd-8976-70c019c40e3b",
"type": {
"id": 1,
"code": null,
"label": null
},
"label": "LABEL",
"details": null
}
I use the library gson for parsing domain classes into JSON.
//... code for making your activity, let's say you have an Activity object myActivity
Just add the following code where you want to parse your object into JSON.
Gson gson = new GSON();
String json = gson.toJson(myActivity);

Resources