non fetched entity appears in JSON result - spring

I have a user entity:
#Entity(name = "users")
#DynamicUpdate
public class User implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
#JsonIgnore
#JsonIgnoreProperties("user")
private Set<Car> cars;
}
and a car entity:
#Entity(name = "cars")
#DynamicUpdate
public class Car implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "plate_number")
#JsonView(View.Summary.class)
private String plateNumber;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="user_id")
#JsonIgnore
#JsonManagedReference("user-coordinate")
#Access(value = AccessType.FIELD)
private User user;
}
when I get cars list I get this:
{
"id": 5,
"plateNumber": "aaaaada",
"user": {
"id": 110,
"name": null
}
},
But I want to get this(without user entity!):
{
"id": 5,
"plateNumber": "aaaaada",
},
I have 7 years' experience in PHP (I said it to know I am familiar with how to search and get what I want) but I am a beginner in java spring I searched a lot for the answer all I get is that it's related to Jackson but I don't know how to solve it please help me with details I will appreciate it.
Thank you

you are using #JsonManagedReference("user-coordinate") which overrides #JsonIgnore
JsonManagedReference directs Jackson to serialize the user when serializing car, so if you want user to not be serialized you need to removed it so #JsonIgnore takes place

For anyone had this problem two, I had two dependencies for JsonIgnore I was using:
org.codehaus.jackson.annotate
that was the problem I changed it to:
com.fasterxml.jackson.annotation
And the problem solved

Related

Save entity with realtion

I have two entities with one-to-mane relationship:
#Entity
public class User implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private Long id;
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
#JsonManagedReference
private List<RealEstate> realEstates = new ArrayList<>();
#Entity
public class RealEstate implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
private String name;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "user_id")
#JsonBackReference
private User user;
I try to save realEstate entity with this code:
realEstate.setUser(user);
realEstateService.saveRealEstate(realEstate);
And this response:
[
{
"id": 1,
"name" : "Bueno",
"user" : 1
}
]
By all I have is creating new record in user table and relation with this new ID.
What I do wrong? What I need to read about this?
You first need to save User entity record and then RealEstate entity record.
Please read this article to implement One To Many relationship. I am sure your issue will be resolved.
https://attacomsian.com/blog/spring-data-jpa-one-to-many-mapping

Spring boot JPA - What is the best solution for updating the intermediate table of ManyToMany relationship with extra columns in the Controller?

I am using Spring Boot for backend in my project. In the database (MySQL) I have a many-to-many relationship which has the next entities: User, interest and relUserInterest. The RelUserInterest is a intermediate table between User and Interest and has extra columns.
User Entity
#Entity
public class User {
#Id #GeneratedValue private Long id;
#NotNull
#Column (unique = true) private String email;
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
#NotNull
Set<RelUserInterest> priority = new HashSet<>();
// more attributes, constructor, get and set
}
Interest entity
#Entity
public class Interest {
#Id
#GeneratedValue
private long id;
#NotEmpty
#Column(unique = true)
private String nameInterest;
#OneToMany(mappedBy = "interest", cascade = CascadeType.ALL)
#NotNull
Set<RelUserInterest> priority = new HashSet<>();
// more attributes, constructor, get and set
}
RelUserInterest entity
#Entity
#Table(name = "rel_user_interest")
#IdClass(UserInterestId.class)
public class RelUserInterest implements Serializable {
#Id
#ManyToOne
#JoinColumn(name = "user_id", referencedColumnName = "id")
User user;
#Id
#ManyToOne
#JoinColumn(name = "interest_id", referencedColumnName = "id")
Interest interest;
int priority;
// constructor, get and set
}
So far so good. I want to update the user and their interests. My controller is this. I want to do is when I update a existing user, update the intermediate table (RelUserInterest).
#PutMapping("/update/{id}")
public ResponseEntity<?> updateUser(#Validated #RequestBody UserDTOUpdate userDTOUpdate, BindingResult result, #PathVariable Long id) {
// More code
User user = usersService.getUserById(id);
// Code updating other attributes
// Here this the problem --> I don't know how to update the attribute priority of RelUserInterest
usersService.updateUser(user);
return new ResponseEntity<>(new Mensaje("Usuario actualizado"), HttpStatus.CREATED);
}
I have found several links but I'm not sure which is the best solution and I don't know how do it with my code.
How to update ManyToMany with extra columns
Spring boot JPA many to many with extra column insert and update
issue
Spring-Data-JPA ManyToMany relationship with extra column
In the Postman i want to send the next JSON although the interest array can be different if it is necessary for the solution:
{
"age": 22,
"genre": "Male",
"userName": "Miguel",
"roles": [
"ROLE_ADMIN",
"ROLE_USER"
],
"interest": [
{
"interestID": 1,
"nameInterest": "Museum",
"priority": 9
}
]
}
Question
So, the question is: How can I update the attribute priority of the RelUserEntity table? I suppose that making an intermediate table repository is a mistake. I'm a little lost. I hope you can help me. Thank you.

#OneToMany and #ManyToOne Jpa

In my spring JPA project I have two entities, Task and Developer. List can assign to a Developer and one Task can have just one Developer. I mapped them:
Developer
#Entity
#Table(name = "DEVELOPER")
public class Developer implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
#OneToMany(targetEntity = Task.class , mappedBy = "developer",cascade=CascadeType.ALL, fetch = FetchType.LAZY)
private List<Task> taskList;
Task
#Entity
#Table(name = "TASK")
public class Task implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long taskId;
private String taskTitle;
#ManyToOne
#JoinColumn(name="developer_id")
private Developer developer;
When I assign a List of Task to a Developer, JSON format is:
{
"id": 1,
"name": "John",
"taskList": [
{
"taskId":2,
"taskTitle": "Do sth"
}
]
}
But the value of Developer in above Task object is null:
{
"taskId":2,
"taskTitle": "Do sth",
"developer": null
}
I expect to this developer property is not null and Developer and task have a bidirectional relationship.
How can I solve this? I am new in Spring and Hibernate. Any help would be greatly appreciated.
might missing cascade=CascadeType.ALL in #ManyToOne annotation, and in Java doc, it says : (Optional) The operations that must be cascaded to the target of the association.By default no operations are cascaded., https://docs.jboss.org/hibernate/jpa/2.1/api/javax/persistence/ManyToOne.html
Remove cascade=CascadeType.ALL in Developer class and add #joinColumn annotation, it will work.
Developer class will look like this-
#Entity
#Table(name = "DEVELOPER")
public class Developer implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
#OneToMany(targetEntity = Task.class , mappedBy = "developer", fetch = FetchType.LAZY)
#JoinColumn(name="task_developer_id")
private List<Task> taskList;

Spring Data Rest - PUT is not working for associated reference types?

I have the following domain class implemented for a Spring Data Rest project.
#Entity
#Data
public class Address {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private long addressID;
private String houseName;
private String apartmentNumber;
#ManyToOne
private City city;
#ManyToOne
private Country country;
}
Now I am creating an Address resource by sending a POST with following JSON.
{
"houseName":"Some House",
"apartmentNumber":"13 B",
"city": "http://localhost:8080/city/1"
"country":"http://localhost:8080/countries/1"
}
When I send a PUT request to the endpoint http://localhost:8080/addresses/1 with the following JSON, the values for houseName is updated. However the city remains unchanged even though I am sending a different URI for the city.
{
"houseName":"Another House",
"apartmentNumber":"13 B",
"city": "http://localhost:8080/city/2"
"country":"http://localhost:8080/countries/1"
}
If I send a PATCH instead of PUT the city value is also updated. So how do I fix this?
UPDATE 1
Country class
#Data
#Entity
public class Country {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long countryID;
private String countryName;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "country", orphanRemoval = true)
private List<City> cities;
}
City class
#Data
#Entity
public class City {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private long cityID;
private String cityName;
#ManyToOne
#JoinColumn(name = "country_id")
private Country country;
}
I had the same problem and manage to find some information on it.
It is a change in version 2.5.7 of Spring Data Rest and is "by purpose".
The answer of Oliver Drotbohm is:
I looked into this and I'd argue you're expecting things to work in a
way they don't work. PUT requests don't consider associations to
linkable resources, i.e. related resources that are pointed to by
links. The reason for that is two-fold:
If we consider URIs for association fields in the payload to update those associations, the question comes up about what's supposed to
happen if no URI is specified. With the current behavior, linked
associations are simply not a part of the payload as they only reside
in the _links block. We have two options in this scenario: wiping the
associations that are not handed, which breaks the "PUT what you GET"
approach. Only wiping the ones that are supplied using null would sort
of blur the "you PUT the entire state of the resource".
For all the reasons mentioned in 1. there are dedicated assoctiation resources exposed that can be manipulated directly.
So it looks like that if you want to change both state of the resource
plus associations at the same time, I guess exposing a dedicated
resource to do that is the way to go.
Full answer you can find on Jira Spring site: Unable to update associated resource using PUT request on the item resource
(the question I wrote on stack overflow is here: Spring Data Rest - PUT on repository silently fails on child references)
If you're using Hibernate as your JPA provider, then you must let know how the entities are mapped in both the sides and indicate the how it is mapped in the child entity which will take care how the relationships are managed during a transaction.
EDITED and UPDATED:
// City Class
#Entity
public class City {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "city_id")
private Long cityID;
#Column(name = "city_name")
private String cityName;
#ManyToOne
private Country country;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "city", orphanRemoval = true)
private List<Address> addresses;
}
// Country Class
#Entity
public class Country {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "country_id")
private Long countryID;
#Column(name = "country_name")
private String countryName;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "country", orphanRemoval = true)
private List<City> cities = new ArrayList<>();;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "country", orphanRemoval = true)
private List<Address> addresses;
}
USE PATCH: If you're updating part of the resource, subset of the resource and relationships
USE PUT: If you're replacing the resource with an entirely new representation

Links to Embedded entities in Spring Data Rest

I have the following entities defined in my project:
Country
#Entity
#Data
public class Country {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
Long id;
#Column(nullable = false)
String name;
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
List<City> cities = new ArrayList<City>();
}
City
#Entity
#Data
public class City {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
Long id;
#Column(nullable = false)
String name;
#ManyToOne
Country country;
}
Person
#Entity
#Data
public class Person {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
Long id;
#Column
String name;
#Embedded
Address address = new Address();
}
Address
#Data
public class Address {
#Column
String line;
#ManyToOne
Country country;
#ManyToOne
City city;
}
I have also repositories defined for Person, Country and City.
When I make a GET request to /persons/1 I get the following result:
{
"name":null,
"address":{
"line":"Address1"
},
"_links":{
"self":{
"href":"http://localhost:8080/persons/1"
},
"city":{
"href":"http://localhost:8080/persons/1/city"
},
"country":{
"href":"http://localhost:8080/persons/1/country"
}
}
}
I suspect that since address is an embedded object, the generated links to country and city are wrong. They don't return anything although city and country values are present. What should the correct links be?
Are embedded objects not supported by Spring Data Rest?
Possible solutions:
move associations to the parent entity
promote the embeddable into a separate entity resource
add ResourceProcessor to remove those links
add a custom controller to handle those links
UPDATE: This seems to be already fixed in Spring-DATA-REST v2.1. See DATAREST-262.

Resources