I have mapped entities which I send in JSON format to the service. Here is my entities
#Entity
#Table(name = "company")
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Company implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#Column
private String name;
#OneToMany(mappedBy = "company")
#Cascade(value = CascadeType.ALL)
private Collection<Employee> employees;
My Employee class
#Entity
#Table(name = "employee")
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Employee implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
Integer id;
#Column
String name;
#ManyToOne()
#Cascade(value = org.hibernate.annotations.CascadeType.ALL)
#JoinColumn(name = "company_id", referencedColumnName = "id")
private Company company;
But I'm getting not appropriate json format.
{
"id": 1,
"name": "Tim",
"company": {
"id": 1,
"name": "Microsoft",
"employees": [1, {
"id": 5,
"name": "Jack",
"company": 1
}, {
"id": 6,
"name": "Jack",
"company": 1
}, {
"id": 7,
"name": "Jack",
"company": 1
}, {
"id": 8,
"name": "Tommy",
"company": 1
}]
}
}
But like I said I don't need "employees" object in "company". How to exclude it in my JSON file?
You can use the Jackson's bi-directional references to exclude "employees" object from "company". Here is an example based on your code that demonstrate the approach:
public class JacksonReferences {
#JsonIdentityInfo(generator = ObjectIdGenerators.None.class, property = "id")
static public class Company {
public Integer id;
public String name;
#JsonManagedReference
public Collection<Employee> employees;
public Company(Integer id, String name, Collection<Employee> employees) {
this.id = id;
this.name = name;
this.employees = employees;
}
}
#JsonIdentityInfo(generator = ObjectIdGenerators.None.class, property = "id")
static public class Employee {
public Integer id;
public String name;
#JsonBackReference
public Company company;
public Employee(Integer id, String name, Company company) {
this.id = id;
this.name = name;
this.company = company;
}
}
public static void main(String[] args) throws IOException {
Company company1 = new Company(1, "Microsoft", new ArrayList<Employee>());
Company company2 = new Company(2, "Google", new ArrayList<Employee>());
Employee employee1 = new Employee(1, "John", company1);
company1.employees.add(employee1);
Employee employee2 = new Employee(2, "Tim", company1);
company1.employees.add(employee2);
Employee employee3 = new Employee(3, "Bob", company2);
company2.employees.add(employee3);
ObjectMapper mapper = new ObjectMapper();
System.out.println("JSON for company #1:");
System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(company1));
System.out.println("JSON for employee #1:");
System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(employee1));
System.out.println("JSON for company #2:");
System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(company2));
}
}
The output is:
JSON for company #1:
{
"id" : 1,
"name" : "Microsoft",
"employees" : [ {
"id" : 1,
"name" : "John"
}, {
"id" : 2,
"name" : "Tim"
} ]
}
JSON for employee #1:
{
"id" : 1,
"name" : "John"
}
JSON for company #2:
{
"id" : 2,
"name" : "Google",
"employees" : [ {
"id" : 3,
"name" : "Bob"
} ]
}
Related
I want to create a spring boot rest controller with this specification :
Customers of an electricity and gas supply company can choose to receive their monthly bills either by email or by regular mail, neither or both.
My goal is to create java hibernate entities to manage these customers and their choices of sending bills.
A utility customer is identified by their email and can have multiple choice change events that change the customer choice status.
Each choice made by a customer generates a choice change event.
These my classes:
#Entity
#Table(name = "customers")
public class Customer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Email(message="this field must respect the email format !")
private String email;
#OneToMany(mappedBy = "customer")
#MapKey(name="type") //don't need this if you want just a list
private Map<String, Choice> choices;
}
#Entity
#Table(name = "choices")
public class Choice {
#Id
#OneToOne
private Customer customer;
#Id
#Enumerated(EnumType.STRING)
private ChoiceType type;
#Column(name="enabled")
private boolean enabled;
}
#IdClass(EmployeeId.class)
public class ChoiceId implements Serializable {
private Integer customer;
private ChoiceType type;
}
public enum ChoiceType {
MAIL,
EMAIL;
}
#Entity
#Table(name = "customers")
public class Customer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String email;
#OneToMany(mappedBy = "customer",cascade = CascadeType.ALL,fetch = FetchType.EAGER)
private List<Choice> choices;
//Getters and Setters
}
#Entity
#Table(name = "choices")
#IdClass(ChoiceId.class)
public class Choice {
#Id
#OneToOne
private Customer customer;
#Id
#Enumerated(EnumType.STRING)
private ChoiceType type;
#Column(name="enabled")
private boolean enabled;
//Getters and Setter
}
public class ChoiceId implements Serializable {
private Integer customer;
private ChoiceType type;
//Getters and Setters
}
public enum ChoiceType {
MAIL,
EMAIL;
}
Services:
CustomerServiceImpl
public CustomerDto addCustomer(CustomerDto customer) {
if(customer.getChoices() !=null) {
for(int i=0; i < customer.getChoices().size(); i++) {
ChoiceDto choice = customer.getChoices().get(i);
choice.setCustomer(customer);
customer.getChoices().set(i,choice);
}
} else {
customer.setChoices(Collections.<ChoiceDto>emptyList());
}
ModelMapper modelMapper = new ModelMapper();
Customer customerEntity = modelMapper.map(customer, Customer.class);
Customer newCustomer = customerRepository.save(customerEntity);
CustomerDto customerDto = modelMapper.map(newCustomer, CustomerDto.class);
return customerDto;
}
ChoiceServiceImpl
public ChoiceDto addChoice(ChoiceDto choiceDto, String email) {
Customer customerWithChoice = customerRepository.findByEmail(email);
ModelMapper modelMapper = new ModelMapper();
CustomerDto customerDto = modelMapper.map(customerWithChoice, CustomerDto.class);
choiceDto.setCustomer(customerDto);
Choice choiceEntity = modelMapper.map(choiceDto, Choice.class);
Choice newChoice = choiceRepository.save(choiceEntity);
ChoiceDto newChoiceDto = modelMapper.map(newChoice, ChoiceDto.class);
return newChoiceDto;
}
I want to get these results :
Post(create customer):
{
"id": "1289",
"email": "customer#eamil.com",
"choices": []
}
If two events are created in this order:
Post(create choices):create of two choices in this order
{
"user": {
"id": "1289"
},
"choices": [
{
"id": "MAIL",
"enabled": true
}
]
}
{
"user": {
"id": "1289"
},
"choices": [
{
"id": "MAIL",
"enabled": false
},
{
"id": "EMAIL",
"enabled": true
}
]
}
GET particular customer :
{
"id": "1289",
"email": "customer#eamil.com",
"choices": [
{
"id": "MAIL",
"enabled": false
},
{
"id": "EMAIL",
"enabled": true
}
]
}
But it doesn't give me the same result ? How can i resolve this problem in my entities or service implementation
I send a request with a body:
{
"name" : "French fries",
"ingredients" : [
{
"id" : 1
}
]
}
And receive:
{
"id" : 1,
"name" : "French fries",
"ingredients" : [
{
"id" : 1,
"name" : null
}
]
}
The id references an ingredient that already exists:
{
"id" : 1,
"name" : "potato"
}
```.
<br/>As you can see, the name of the ingredient in null.
Here's my model:
```java
#Entity
#Table(name = "dishes")
#Data
public class Dish {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#JsonView(Views.Full.class)
private Long id;
#Column(unique = true)
#JsonView(Views.Partial.class)
private String name;
#ManyToMany(cascade = CascadeType.MERGE)
#JoinTable(
name = "dish_ingredients",
joinColumns = #JoinColumn(name = "dish_id"),
inverseJoinColumns = #JoinColumn(name = "ingredient_id"))
#JsonView(Views.Partial.class)
private List<Ingredient> ingredients = new ArrayList<>();}
#Data
#Table(name = "ingredients")
#Entity
public class Ingredient {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#JsonView({Views.Full.class, Views.Partial.class})
private Long id;
#Column(unique = true)
#JsonView(Views.Public.class)
private String name;
}
Here's what I do in service:
public Dish createDish(Dish dish) {
return dishRepository.saveAndFlush(dish);
}
Controller:
#PostMapping("dishes")
public Dish createDish(#RequestBody #JsonView(Views.Partial.class) Dish dish) {
return itemService.createDish(dish);
}
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
I have a SpringBoot REST API where one or multiple User are part of one or multiple Team (Equipe), but they have a Role for each Team.
When I request my UserRepository.findAll(), I would like to get all my users and their teams and roles.
But when I request my TeamRepository.findAll(), I would like to get all my teams and their users and their roles.
But I don't know how to get a bidirectionnal request. I tried with #jsonmanagedreference and #jsonbackreference but it only allows me to get the teams from the user, and not the opposite.
Currently I have
[
{
"id": 1,
"prenom": "TestPrenom1",
"nom": "TestNom1",
"roleUserEquipe": []
}
{
"id": 2,
"prenom": "TestPrenom2",
"nom": "TestNom2",
"roleUserEquipe": []
}
]
But what I want is
[
{
"id": 1,
"prenom": "TestPrenom1",
"nom": "TestNom1",
"roleUserEquipe": [
{
"role": "Role1",
"team": {
"id": 1,
"nom": "Team1"
}
}
]
}
{
"id": 2,
"prenom": "TestPrenom2",
"nom": "TestNom2",
"roleUserEquipe": [
{
"role": "Role2",
"team": {
"nom": "Team1"
}
}
]
}
]
And when I request my teams I have
[
{
"id": 1,
"nom": "Team1",
"roleUserEquipe": [
{}
]
},
{
"id": 2,
"nom": "Team2",
"roleUserEquipe": [
{}
]
}
]
But I would like
[
{
"id": 1,
"nom": "Team1",
"roleUserEquipe": [
{
"role": "Role1",
"user": {
"id": 1,
"prenom": "TestPrenom1",
"nom": "TestNom1",
}
},
{
"role": "Role2",
"user": {
"id": 2,
"prenom": "TestPrenom2",
"nom": "TestNom2",
}
}
]
},
{
"id": 2,
"nom": "Team2",
"roleUserEquipe": []
}
]
My User.java
#Entity
#JsonIdentityInfo(generator= ObjectIdGenerators.PropertyGenerator.class, property="id")
public class User implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
private String prenom;
private String nom;
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<RoleUserEquipe> roleUserEquipe = new HashSet<>();
//GETTERS AND SETTERS AND CONSTRUCTORS
}
My Equipe.java (Team)
#Entity
#JsonIdentityInfo(generator= ObjectIdGenerators.PropertyGenerator.class, property="id")
public class Equipe implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
private String nom;
#OneToMany(mappedBy = "equipe", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<RoleUserEquipe> roleUserEquipe = new HashSet<>();
//GETTERS AND SETTERS AND CONSTRUCTORS
}
My RoleUserEquipe.java
#Entity
public class RoleUserEquipe implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "equipe_id")
private Equipe equipe;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "user_id")
private User user;
private String role;
//GETTERS AND SETTERS AND CONSTRUCTORS
}
EDIT :
When debugging, the subobjects are OK: they contain the values that I need.
Only when returning the JSON Response, they lose their values
I am not sure if this would work, but try removing the new keywords in:
#OneToMany(mappedBy = "equipe", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<RoleUserEquipe> roleUserEquipe = new HashSet<>();
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<RoleUserEquipe> roleUserEquipe = new HashSet<>();
to
#OneToMany(mappedBy = "equipe", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<RoleUserEquipe> roleUserEquipe;
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<RoleUserEquipe> roleUserEquipe;
You didn't show us, how you convert your domain objects into resource/DTO objects.
Are you using the Spring ConversionService framework?
If so, show us the converter you wrote. Maybe your converter doesn't take the roles into account?
I have this Product entity :
#Entity
public class Product implements Serializable{
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "category_id")
#JsonBackReference
private ProductCategory productCategory;
}
And Category Entity :
#Entity
public class ProductCategory implements Serializable{
#OneToMany(fetch = FetchType.LAZY, mappedBy="productCategory" ,cascade = CascadeType.ALL)
#JsonManagedReference
#OrderBy("id desc")
private Set<Product> products = new HashSet<Product>();
}
Rest API :
#Query("select p,productCategory.id,productCategory.name from Product p inner join p.productCategory productCategory")
public Page<Product> getProductsWithCategory(Pageable pageable);
This returns the following JSON :
"content": [
[
{
"id": 2,
"sku": "REF_25471",
"name": "Serrure Washington"
},
1,
"Hello 1"
],
I want to add the category object in the JSON like following :
"content": [
{
"id": 1,
"name": "Hello 1",
"products": [
{
"id": 4,
"sku": "REF_25472",
"name": "Serrure Washington",
"productCategory": [
{
"id": 1,
"name": "Hello 1"
}
]
}
]
}
]