Spring Requestbody JSON Deserializer not mapping the value - spring

I have a problem where JSON data is not mapping to the Entity and it displays "selectedOption" as null.
Following Spring REST Contoller Method saves the order.
#RequestMapping(value = "/saveOrder")
public Long saveOrder(#RequestBody CustOrder order) {
return shopService.saveCustomerOrder(order);
}
Following is the JSON which is being sent to the method
{
"order":[
{
"selectedOption":{
"id":6,
"productOptionDescription":"Groß, Ø30cm:",
"optionPrice":null,
"optionPriceForSmall":null,
"optionPriceForNormal":6.7,
"optionPriceForFamily":null,
"optionPriceForParty":null,
"isDefault":true
}
}
]
}
Entity CustOrder
#Entity
public class CustOrder {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
#OneToMany
#JoinColumn( name="custorder_id")
private Set<OrderItem> order=new HashSet<>();
}
Entity Order Item
#Entity
public class OrderItem {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
#OneToOne
private ProductOption selectedOption;
}
I am struggling to understand why selectedOption is null.
Could someone help me with this.
Below is the screenshot from REST Controller Method (Eclipse)

Related

Spring Boot List of Object Bean Validation

I have a Bean,
#Data
#NoArgsConstructor
public final class PersonRequest {
#NotNull
#JsonProperty("nameList")
private List<Person> nameList;
}
and Person POJO,
#Data
public class Sensor {
#NotNull
#JsonProperty("id")
private int id;
#NotNull
#JsonProperty("name")
#Min(1)
private String name;
}
I am sending JSON request and added #Valid in my controller. I am sending request as below,
{
"nameList": [
{
"id": 1,
"name": "John"
},
{
"id": 2,
"name": "Alex"
}
]
}
When i send request without id and name not validating. I tried using #Valid private List<Person> nameList; also but no luck. I use Spring boot 2.3.2.
UPDATED:
when i add one more attribute, this also say bad request when i pass date in request.
#NotNull
#JsonProperty("startTime")
#DateTimeFormat(pattern = "yyyy-MM-dd'T'hh:mm:ss", iso =
DateTimeFormat.ISO.DATE_TIME)
#Valid
private LocalDateTime startTime;
The #Valid annotation in your controller triggers the validation of the PersonRequest object, passed as request body. To validate also the Person objects contained in PersonRequest, you need to annotate that field with #Valid too.
#Data
#NoArgsConstructor
public final class PersonRequest {
#NotNull
#JsonProperty("nameList")
#Valid
private List<Person> nameList;
}

When does the hibernate session gets closed

I have created the following entities.
#Entity
public class Student {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
#OneToMany(mappedBy = "student")
private List<Book> books;
}
#Entity
public class Book {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
#ManyToOne
#JoinColumn(name = "STUDENT_ID")
private Student student;
}
My controller looks like this
#RestController
public class Controller {
MyService myService;
public Controller(MyService myService) {
this.myService = myService;
}
#GetMapping("student")
public List<Book> getBooksForStudent(Long id) {
return myService.getBooks(id);
}
}
The service is as follows.
public class MyService {
#Autowired
private StudentRepo studentRepo;
public List<Book> getStudent(Long id) {
Optional<Student> studentOptional = studentRepo.findById(id);
return studentOptional.map(Student::getBooks).orElseThrow(IllegalArgumentException::new);
}
}
I am getting the list of books as expected. But as I'm having lazy loaded list for books I should be getting a LazyInitializationException. I have not added transnational to the method and I'm returning the list of books from the entity itself without mapping it to a DTO. Why is the hibernate session not getting closed after the end of the method?
#RestController is transactional by default. Spring boot automatically registers an OpenEntityManagerInViewInterceptor when you use a web application/you use JPA. Refer #RestController methods seem to be Transactional by default, Why?

Ignoring Nested properties in Jackson OnDemand

I am working on a spring boot application with Hibernate as ORM and Jackson as JSON serialiser .
I have three model objects and CRUD operations for all three models.
Class Student{
private Teacher teacher; // Teacher of the student — to be fetched eagerly
+Getter/Setter
}
class Teacher {
private List<Subject> subject; // List of subjects associated to that user— to be fetched eagerly
+Getter/Setter
}
class Subject {
private long subjectId
//Other subject properties
+ Getter/Setter
}
Whenever I trigger a get request for student info I get the teacher info which is correct where as I also receive Subject info as well which is unnecessary for me. In the same time when I request for Teacher info, I need Subject info should be associated to that for sure. If I use #JsonBackReference for subject I am losing it all the time. I am not sure how to achieve this.
Thanks in advance for your help!!
You can also annotate like this
Class Student{
#JsonIgnoreProperties("subject")
private Teacher teacher; // Teacher of the student — to be fetched eagerly
}
You can use JSON Views
From the spring blog:
public class View {
interface Summary {}
}
public class User {
#JsonView(View.Summary.class)
private Long id;
#JsonView(View.Summary.class)
private String firstname;
#JsonView(View.Summary.class)
private String lastname;
private String email;
private String address;
private String postalCode;
private String city;
private String country;
}
public class Message {
#JsonView(View.Summary.class)
private Long id;
#JsonView(View.Summary.class)
private LocalDate created;
#JsonView(View.Summary.class)
private String title;
#JsonView(View.Summary.class)
private User author;
private List<User> recipients;
private String body;
}
and in the controller
#RestController
public class MessageController {
#Autowired
private MessageService messageService;
#JsonView(View.Summary.class)
#RequestMapping("/")
public List<Message> getAllMessages() {
return messageService.getAll();
}
#RequestMapping("/{id}")
public Message getMessage(#PathVariable Long id) {
return messageService.get(id);
}
}
PS: No link to http://fasterxml.com/ as it's currently down.

Spring Data Rest #EmbeddedId cannot be constructed from Post Request

I have a JPA entity Person and an entity Team. Both are joined by an entity PersonToTeam. This joining entity holds a many-to-one relation to Person and one to Team. It has a multi-column key consisting of the ids of the Person and the Team, which is represented by an #EmbeddedId. To convert the embedded id back and forth to the request id I have a converter. All this follows the suggestion on Spring Data REST #Idclass not recognized
The code looks like this:
#Entity
public class PersonToTeam {
#EmbeddedId
#Getter
#Setter
private PersonToTeamId id = new PersonToTeamId();
#ManyToOne
#Getter
#Setter
#JoinColumn(name = "person_id", insertable=false, updatable=false)
private Person person;
#ManyToOne
#Getter
#Setter
#JoinColumn(name = "team_id", insertable=false, updatable=false)
private Team team;
#Getter
#Setter
#Enumerated(EnumType.STRING)
private RoleInTeam role;
public enum RoleInTeam {
ADMIN, MEMBER
}
}
#EqualsAndHashCode
#Embeddable
public class PersonToTeamId implements Serializable {
private static final long serialVersionUID = -8450195271351341722L;
#Getter
#Setter
#Column(name = "person_id")
private String personId;
#Getter
#Setter
#Column(name = "team_id")
private String teamId;
}
#Component
public class PersonToTeamIdConverter implements BackendIdConverter {
#Override
public boolean supports(Class<?> delimiter) {
return delimiter.equals(PersonToTeam.class);
}
#Override
public Serializable fromRequestId(String id, Class<?> entityType) {
if (id != null) {
PersonToTeamId ptid = new PersonToTeamId();
String[] idParts = id.split("-");
ptid.setPersonId(idParts[0]);
ptid.setTeamId(idParts[1]);
return ptid;
}
return BackendIdConverter.DefaultIdConverter.INSTANCE.fromRequestId(id, entityType);
}
#Override
public String toRequestId(Serializable id, Class<?> entityType) {
if (id instanceof PersonToTeamId) {
PersonToTeamId ptid = (PersonToTeamId) id;
return String.format("%s-%s", ptid.getPersonId(), ptid.getTeamId());
}
return BackendIdConverter.DefaultIdConverter.INSTANCE.toRequestId(id, entityType);
}
}
The problem with this converter is, that the fromRequestId method gets a null as id parameter, when a post request tries to create a new personToTeam association. But there is no other information about the payload of the post. So how should an id with foreign keys to the person and the team be created then? And as a more general question: What is the right approach for dealing many-to-many associations in spring data rest?
After running into the same issue I found a solution. Your code should be fine, except I return new PersonToTeamId() instead of the DefaultIdConverter if id is null in fromRequestId().
Assuming you are using JSON in your post request you have to wrap personId and teamId in an id object:
{
"id": {
"personId": "foo",
"teamId": "bar"
},
...
}
And in cases where a part of the #EmbeddedId is not a simple data type but a foreign key:
{
"id": {
"stringId": "foo",
"foreignKeyId": "http://localhost:8080/path/to/other/resource/1"
},
...
}

retrieving data from database as json in spring boot

I have a MySQL database and I want to retrieve some data as json.
And I have an entity Offre wich has #OneToMany relation with the AssociationCandidatOffre entity.
and I have an api which calles this method in my repository :
offreRepository.findAll();
Offre entity :
#Entity
public class Offre implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "CODE_OFFRE")
private Long codeOffre;
private String titre;
#OneToMany(mappedBy = "offre")
private Collection<AssociationCandidatOffre> associationCandidatOffres;
public Collection<AssociationCandidatOffre> getAssociationCandidatOffres() {
return associationCandidatOffres;
}
public void setAssociationCandidatOffres(Collection<AssociationCandidatOffre> associationCandidatOffres) {
this.associationCandidatOffres = associationCandidatOffres;
}
//... getters/setters
}
AssociationCandidatOffre entity :
#Entity
public class AssociationCandidatOffre implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long idAssociation;
private String lettreMotivation;
private String tarifJournalier;
private Date dateDisponibilite;
#ManyToOne
private Candidat candidat;
#ManyToOne
private Offre offre;
#JsonIgnore
#XmlTransient
public Candidat getCandidat() {
return candidat;
}
#JsonSetter
public void setCandidat(Candidat candidat) {
this.candidat = candidat;
}
#JsonIgnore
#XmlTransient
public Offre getOffre() {
return offre;
}
#JsonSetter
public void setOffre(Offre offre) {
this.offre = offre;
}
//... getters/setters
}
the problem is when I call the api /offres to return me a json object I get this error message instead :
Failed to write HTTP message: org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: could not extract ResultSet (through reference chain: java.util.ArrayList[0]->com.***.Rekrute.entities.Offre["associationCandidatOffres"]);
nested exception is com.fasterxml.jackson.databind.JsonMappingException: could not extract ResultSet (through reference chain: java.util.ArrayList[0]->com.***.Rekrute.entities.Offre["associationCandidatOffres"])
when I use #JsonIgnore in the getAssocationCandidatOffres I dont get any errors but I want that association in the json result as well.
Normally, this shouldn't generate any error since I have #JsonIgnore in the other side of the relation which is getOffre().
how can I solve this problem ?
You can't convert a bidirectional relation of an enitity to JSON.
You get an endless loop.
JSON-Parser starts with the entity Offer and reads the associated AssociationCandidatOffre via getAssociationCandidatOffres(). For every AssociationCandidatOffre the JSON-Parser read getOffre() and starts again. The parser don't know when he must end.

Resources