JPA- Compound Primary Key using #EmbededId - java

Goal: To impolement an #Entity where the id is a compound primary key using #EmbededId.
Problem: Based on my current implementation, I am getting the following result:
[
{
"id": 1,
"name": "Recipe 1",
"instruction": "Test Instruction",
"note": "Note 1",
"show": true,
"createDate": null,
"modify_date": null,
"ingredient": [
{},
{}
]
}
]
but I want to have this:
[
{
"id": 1,
"name": "Recipe 1",
"instruction": "Test Instruction",
"note": "Note 1",
"show": true,
"createDate": null,
"modify_date": null,
"ingredient": [
{ingredient_id: 1,
amount: 10},
{ingredient_id: 2,
amount: 20}
]
}
]
Can someone please help me too see where I have done wrong in my recipeIngredient class? Thanks in advance.
The following are my implementation:
The schema:
RecipeIngredientId.java
#Embeddable
public class RecipeIngredientId implements Serializable {
#Column(name = "recipe_id", nullable = false)
private int recipeId;
#Column(name = "ingredient_id", nullable = false)
private int ingredientId;
public RecipeIngredientId() {}
public RecipeIngredientId(int recipeId, int ingredientId) {
this.recipeId = recipeId;
this.ingredientId = ingredientId;
}
}
RecipeIngredient.java
#Entity
#Table(name = "recipe_ingredient")
public class RecipeIngredient implements Serializable
{
#EmbeddedId
private RecipeIngredientId id;
#ManyToOne
#JoinColumn(name="ingredient_id", insertable = false, updatable = false)
private Ingredient ingredient;
#ManyToOne
#JoinColumn(name = "recipe_id", insertable = false, updatable = false)
private Recipe recipe;
private double amount;
public RecipeIngredient() {}
public RecipeIngredient(Recipe recipe, Ingredient ingredient, double amount){
this.recipe = recipe;
this.ingredient = ingredient;
this.amount = amount;
}
}
Recipe.java:
#Entity
public class Recipe {
private int id;
#NotNull
private String name;
private String instruction;
private String note;
#NotNull
private boolean show;
#CreationTimestamp
#Temporal(TemporalType.DATE)
#Column(name = "create_date")
private Date createDate;
#UpdateTimestamp
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "modify_date")
private Date modify_date;
private Set<RecipeIngredient> recipeIngredients;
public Recipe() {}
public Recipe(String name, String instruction, String note, boolean show) {
this.name = name;
this.instruction = instruction;
this.note = note;
this.show = show;
}
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getInstruction() {
return instruction;
}
public void setInstruction(String instruction) {
this.instruction = instruction;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
public boolean isShow() {
return show;
}
public void setShow(boolean show) {
this.show = show;
}
public Date getCreateDate() {
return createDate;
}
public void setCreateDate(Date createDate) {
this.createDate = createDate;
}
public Date getModify_date() {
return modify_date;
}
public void setModify_date(Date modify_date) {
this.modify_date = modify_date;
}
#OneToMany(mappedBy = "recipe", cascade = CascadeType.ALL)
public Set<RecipeIngredient> getIngredient() {
return recipeIngredients;
}
public void setIngredient(Set<RecipeIngredient> recipeIngredients) {
this.recipeIngredients = recipeIngredients;
}
}
Ingredient.java
#Entity
public class Ingredient {
private int id;
#NotNull
#Column(unique=true)
private String name;
private Set<RecipeIngredient> recipeIngredients;
public Ingredient() {}
public Ingredient(String name) {
this.name = name;
}
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#OneToMany(mappedBy = "ingredient", cascade = CascadeType.ALL)
public Set<RecipeIngredient> getRecipeIngredients() {
return recipeIngredients;
}
public void setRecipeIngredients(Set<RecipeIngredient> recipeIngredients) {
this.recipeIngredients = recipeIngredients;
}
}

This is a case of "derived identity". RecipeIngredient should look like this:
#Entity
#Table(name = "recipe_ingredient")
public class RecipeIngredient implements Serializable
{
#EmbeddedId
private RecipeIngredientId id;
#MapsId("ingredientId") // maps ingredientId attribute of embedded id
#ManyToOne
#JoinColumn(name="ingredient_id", insertable = false, updatable = false)
private Ingredient ingredient;
#MapsId("recipeId") // maps recipeId attribute of embedded id
#ManyToOne
#JoinColumn(name = "recipe_id", insertable = false, updatable = false)
private Recipe recipe;
private double amount;
public RecipeIngredient() {}
public RecipeIngredient(Recipe recipe, Ingredient ingredient, double amount){
this.recipe = recipe;
this.ingredient = ingredient;
this.amount = amount;
}
}
Note the MapsId annotations on the two fields whose primary keys make up the entity's composite key.
Derived identities are discussed in the JPA 2.1 spec in section 2.4.1.

Related

Criteria query returning infinite nested result

I have 3 entities Movie, Show and Theatre with below relationship
Relations
#Entity
#Table(name = "theatre")
public class Theatre {
#Id
#Column(name = "id", nullable = false)
private Long id;
#Column(name = "name")
private String name;
#Column(name = "town")
private String town;
#OneToMany(mappedBy = "theatre", orphanRemoval = true)
private List<Show> shows = new ArrayList<>();
public List<Show> getShows() {
return shows;
}
public void setShows(List<Show> shows) {
this.shows = shows;
}
public String getTown() {
return town;
}
public void setTown(String town) {
this.town = town;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
#Entity
#Table(name = "show")
public class Show {
#Id
#Column(name = "id", nullable = false)
private Long id;
#ManyToOne
#JoinColumn(name = "theatre_id")
private Theatre theatre;
#ManyToOne
#JoinColumn(name = "movie_id")
private Movie movie;
public Movie getMovie() {
return movie;
}
public void setMovie(Movie movie) {
this.movie = movie;
}
public Theatre getTheatre() {
return theatre;
}
public void setTheatre(Theatre theatre) {
this.theatre = theatre;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
#Entity
#Table(name = "movie")
public class Movie {
#Id
#Column(name = "id", nullable = false)
private Long id;
#Column(name = "name")
private String name;
#OneToMany(mappedBy = "movie", orphanRemoval = true)
private List<Show> shows = new ArrayList<>();
public List<Show> getShows() {
return shows;
}
public void setShows(List<Show> shows) {
this.shows = shows;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
Now when I try to fetch list of Theatres for a movie name I'm getting infinite nested result. As a result I'm getting StackOverflow error as well.
Is criteria query not suitable here? Or the relationship is wrong? Or criteria query is wrong itself.
Criteria query
public List<Theatre> findTheatresByMovieAndDate(String movieName) {
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Theatre> query = builder.createQuery(Theatre.class);
Root<Theatre> fromTheatres = query.from(Theatre.class);
Join<Theatre, Show> shows = fromTheatres.join("shows");
Join<Show, Movie> movie = shows.join("movie");
List<Predicate> conditions = new ArrayList<>();
conditions.add(builder.equal(movie.get("name"), movieName));
TypedQuery<Theatre> typedQuery = entityManager.createQuery(query
.select(fromTheatres)
.where(conditions.toArray(new Predicate[] {}))
.orderBy(builder.asc(fromTheatres.get("id")))
.distinct(true)
);
return typedQuery.getResultList();
}
Thanks in advance

ModelMapper fail to convert java.util.list to java.util.list on DeleteMapping

good day everyone,
i have this project where i use the ModelMapper to mat my entities to DTOs and vise-versa, and also have a class with #ElementCollection relation.
the mapper seems to work fine for all other methods and it just output the entity as i want, however when it comes to delete mapping i get the following error printed along with a 500 http status. here's the error:
"ModelMapper mapping errors:\r\n\r\n1) Converter org.modelmapper.internal.converter.CollectionConverter#ddb7bc7 failed to convert java.util.List to java.util.List.\r\n\r\n1 error"
here is code:
the entity class:
#Entity
#Table(name = "quiz_engines")
#EntityListeners(AuditingEntityListener.class)
#JsonIgnoreProperties(
value = {"lastModified"},
allowGetters = true
)
public class Engine implements Model {
#Id
#Column(name = "engine_id", unique = true, nullable = false)
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne(fetch = FetchType.LAZY,optional = false, targetEntity = com.QCMGenerator.QCMGenerator.Model.Test.class)
#JoinColumn(name = "test_id", referencedColumnName = "test_id", nullable = false, updatable = false)
#OnDelete(action = OnDeleteAction.NO_ACTION)
#JsonIgnore
private Test test;
#Column(name = "quiz_name", nullable = false)
#NotNull
private String name;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "last_modified", nullable = false)
#LastModifiedDate
private Date lastModified;
#ElementCollection
#CollectionTable(name = "engine_constraints", joinColumns = #JoinColumn(name = "engine_id"))
private List<EngineConstraint> constraints;
public Engine() {
}
public Engine(#NotNull String name, List<EngineConstraint> constraints) {
this.name = name;
this.constraints = constraints;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Test getTest() {
return test;
}
public void setTest(Test test) {
this.test = test;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getLastModified() {
return lastModified;
}
public void setLastModified(Date lastModified) {
this.lastModified = lastModified;
}
public List<EngineConstraint> getConstraints() {
return constraints;
}
public void setConstraints(List<EngineConstraint> constraints) {
this.constraints = constraints;
}
}
the DTO class:
public class EngineDTO implements ModelDTO {
private Long id;
#JsonIgnore
private TestDTO test;
private String name;
private Date lastModified;
private List<EngineConstraint> constraints;
public EngineDTO() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public TestDTO getTest() {
return test;
}
public void setTest(TestDTO test) {
this.test = test;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getLastModified() {
return lastModified;
}
public void setLastModified(Date lastModified) {
this.lastModified = lastModified;
}
public List<EngineConstraint> getConstraints() {
return constraints;
}
public void setConstraints(List<EngineConstraint> constraints) {
this.constraints = constraints;
}
}
the Delete Controller:
#DeleteMapping("/{engineID}")
public ResponseEntity<NonPaginatedResponse> deleteEngine(
#PathVariable(value = "testID") Long testID,
#PathVariable(value = "engineID") Long engineID
){
if(!testRepo.existsById(testID)){
throw new ResourceNotFoundException("No test with the ID '"+testID+"' was found...");
}
return engineRepo.findById(engineID).map(engineFound -> {
engineRepo.delete(engineFound);
return ResponseEntity.status(HttpStatus.OK).body(
ResponseBodyBuilder.getSingleResponse(
convertToDTO(engineFound),
new ModelDTO[]{ convertToDTO(testRepo.findById(testID).get()) },
"delete"
)
);
}
).orElseThrow(
() -> new ResourceNotFoundException("No Engine with the ID '"+engineID+"' was found...")
);
}
hope you guys can help with this one, thank for your time everyone and have a good day.

An issue with getting user roles in a Spring Rest application

I have a RestController class with the following :
#RestController
public class UserRestController
{
#Autowired
UserService userService;
#Autowired
private SecurityService securityService;
#Autowired
private UserValidator userValidator;
// Get a Single User
#GetMapping("/api/users/{id}")
public User getUserById(#PathVariable(value = "id") Long userId) {
return userService.getUserById(userId);
}
This is getUserById function in UserService :
public User getUserById(#PathVariable(value = "id") Long userId) {
return userRepository.findById(userId).orElseThrow(() -> new ResourceNotFoundException("User", "id", userId));
}
This is the result of a GET request on localhost:8080/api/users/11 :
{
"id": 11,
"name": null,
"email": null,
"password": "$2a$10$HykDWcHU3vO9YAcdXiWieua9YyYMkwrNIk7WgpmVzVwENb71fDCsW",
"status": null,
"tel": null,
"confirmation": null,
"birth_date": null,
"createdAt": "2018-05-22T09:09:12.000+0000",
"updatedAt": "2018-05-22T09:09:12.000+0000",
"username": "ouissal#gmail.com"
}
This is the result of a GET request on localhost:8080/users/11
{
"name": null,
"email": null,
"password": "$2a$10$HykDWcHU3vO9YAcdXiWieua9YyYMkwrNIk7WgpmVzVwENb71fDCsW",
"status": null,
"tel": null,
"confirmation": null,
"birth_date": null,
"createdAt": "2018-05-22T09:09:12.000+0000",
"updatedAt": "2018-05-22T09:09:12.000+0000",
"username": "ouissal#gmail.com",
"_links": {
"self": {
"href": "http://localhost:8080/users/11"
},
"user": {
"href": "http://localhost:8080/users/11"
},
"roles": {
"href": "http://localhost:8080/users/11/roles"
}
}
}
I do not have anything mapped for /users in my controller, how can I get the roles using my controller?
edit
This is my User class :
#Entity
#Table(name = "user")
#EntityListeners(AuditingEntityListener.class)
#JsonIgnoreProperties(value = {"createdAt", "updatedAt"},
allowGetters = true)
public class User implements Serializable{
private static final long serialVersionUID = 1L;
public User() {
super();
// TODO Auto-generated constructor stub
}
#Id
#Column(name = "user_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(name = "user_name")
//#NotBlank
private String name;
#Column(name = "user_email")
//#NotBlank
private String email;
#Column(name = "user_password")
#NotBlank
private String password;
#Column(name = "user_status")
private String status;
#Column(name = "user_tel")
private String tel;
#Column(name = "user_confirmation")
private String confirmation;
#Column(name = "user_birth_date")
#Temporal(TemporalType.DATE)
private Date birth_date;
#Column(nullable = false, updatable = false)
#Temporal(TemporalType.TIMESTAMP)
#CreatedDate
private Date createdAt;
#Column(nullable = false)
#Temporal(TemporalType.TIMESTAMP)
#LastModifiedDate
private Date updatedAt;
#JsonBackReference
#ManyToMany
#JoinTable(name = "user_role", joinColumns = #JoinColumn(name = "user_id"), inverseJoinColumns = #JoinColumn(name = "role_id"))
private Set<Role> roles;
#Column(name = "username")
#NotBlank
private String username;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getTel() {
return tel;
}
public void setTel(String tel) {
this.tel = tel;
}
public String getConfirmation() {
return confirmation;
}
public void setConfirmation(String confirmation) {
this.confirmation = confirmation;
}
public Date getBirth_date() {
return birth_date;
}
public void setBirth_date(Date birth_date) {
this.birth_date = birth_date;
}
public Date getCreatedAt() {
return createdAt;
}
public Date getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(Date updatedAt) {
this.updatedAt = updatedAt;
}
public Set<Role> getRoles() {
return roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
}
and this is my role class :
#Entity
#Table(name = "role")
public class Role {
#Id
#Column(name = "role_id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "role_name")
private String name;
#ManyToMany(mappedBy = "roles")
#JsonManagedReference
private Set<User> users;
public Role() {
super();
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<User> getUsers() {
return users;
}
public void setUsers(Set<User> users) {
this.users = users;
}
}
Properties annotated with JsonBackReference will not be included in your serialized content.
To include the roles swap the JsonBackReference and JsonManagedReference annotations in Role and User.
This will include Roles into User but not the other way round.
For more information you can check this answer

Handling Jackson Parent-Child Serialization

I'm using Spring MVC (am new to this), Hibernate and Jackson for my project and am using JSON for data exchange between the server and client.
I have a couple of classes "Employee" and "Address" with a ManyToOne / OneToMany relationship.
I faced the cyclic reference error, however, I was able to resolve that using #JsonManagedReference and #JsonBackReference.
But the problem is, during serialization (I'm querying the DB to get all the employees), Jackson is completely ignoring the Address property and serializing just 3 fields (other fields have been ignored specifically which you can see in the code).
Here's the JSON returned
[
{
"id": 1,
"name": "xxx",
"age": 100
},
{
"id": 2,
"name": "yyy",
"age": 100
}
]
The Employee Class:
#Entity
#Table(name = "e_employee", catalog = "emploman")
public class Employee implements java.io.Serializable {
private int id;
private String name;
private int age;
private Address address;
private String modifiedBy;
private Date modifiedTime;
private transient int addressId;
public Employee() {
}
public Employee(int id, String name, int age, Address address, String modifiedBy, Date modifiedTime) {
this.id = id;
this.name = name;
this.age = age;
this.address = address;
this.modifiedBy = modifiedBy;
this.modifiedTime = modifiedTime;
}
public Employee(String name, int age, Address address, String modifiedBy, Date modifiedTime) {
this.name = name;
this.age = age;
this.address = address;
this.modifiedBy = modifiedBy;
this.modifiedTime = modifiedTime;
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", unique = true, nullable = false)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#Column(name = "name", nullable = false, length = 100)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Column(name = "age", nullable = false)
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "address", nullable = false)
#JsonBackReference("employee-address")
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
#Column(name = "modified_by", nullable = false, length = 50)
#JsonIgnore
public String getModifiedBy() {
return modifiedBy;
}
#JsonIgnore
public void setModifiedBy(String modifiedBy) {
this.modifiedBy = modifiedBy;
}
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "modified_time", nullable = false, length = 19)
#JsonIgnore
public Date getModifiedTime() {
return modifiedTime;
}
#JsonIgnore
public void setModifiedTime(Date modifiedTime) {
this.modifiedTime = modifiedTime;
}
#JsonIgnore
#Transient
public int getAddressId() {
return addressId;
}
#JsonIgnore
public void setAddressId(int addressId) {
this.addressId = addressId;
}
}
The Address Class:
#Entity
#Table(name = "e_address", catalog = "emploman")
public class Address implements java.io.Serializable {
private int id;
private String country;
private String state;
private String city;
private String streetAddress;
private String pinCode;
private String modifiedBy;
private Date modifiedTime;
private Set<Employee> employees;
public Address() {
}
public Address(int id, String country, String state, String city, String streetAddress, String pinCode, String modifiedBy, Date modifiedTime, Set<Employee> employees) {
this.id = id;
this.country = country;
this.state = state;
this.city = city;
this.streetAddress = streetAddress;
this.pinCode = pinCode;
this.modifiedBy = modifiedBy;
this.modifiedTime = modifiedTime;
this.employees = employees;
}
public Address(String country, String state, String city, String streetAddress, String pinCode, String modifiedBy, Date modifiedTime, Set<Employee> employees) {
this.country = country;
this.state = state;
this.city = city;
this.streetAddress = streetAddress;
this.pinCode = pinCode;
this.modifiedBy = modifiedBy;
this.modifiedTime = modifiedTime;
this.employees = employees;
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#Column(name = "country", nullable = false, length = 100)
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
#Column(name = "state", nullable = false, length = 100)
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
#Column(name = "city", nullable = false, length = 100)
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
#Column(name = "street_address", nullable = false, length = 500)
public String getStreetAddress() {
return streetAddress;
}
public void setStreetAddress(String streetAddress) {
this.streetAddress = streetAddress;
}
#Column(name = "pincode", nullable = false, length = 15)
public String getPinCode() {
return pinCode;
}
public void setPinCode(String pinCode) {
this.pinCode = pinCode;
}
#Column(name = "modified_by", nullable = false, length = 50)
public String getModifiedBy() {
return modifiedBy;
}
public void setModifiedBy(String modifiedBy) {
this.modifiedBy = modifiedBy;
}
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "modified_time", nullable = false, length = 19)
public Date getModifiedTime() {
return modifiedTime;
}
public void setModifiedTime(Date modifiedTime) {
this.modifiedTime = modifiedTime;
}
#OneToMany(mappedBy = "address", fetch = FetchType.LAZY)
#JsonManagedReference(value = "employee-address")
public Set<Employee> getEmployees() {
return employees;
}
public void setEmployees(Set<Employee> employees) {
this.employees = employees;
}
}
So, basically, the json response I'm expecting is something like below:
[
{
"id": 1,
"name": "xxx",
"age": 100,
"address": {
"country": "xxx",
"city": "abc"
}
}
]
Could anyone please help?
Update 1
I've tried getting Addresses from the DB, and employees related to that address is successfully being fetched
[
{
"id": 1,
"country": "xxx",
"state": "yyy",
"city": "zzz",
"streetAddress": "abc",
"pinCode": "12345",
"modifiedBy": "xxx",
"modifiedTime": 1400930509000,
"employees": [
{
"id": 2,
"name": "xxx",
"age": 190
},
{
"id": 1,
"name": "xxx",
"age": 200
}
]
}
]
Thanks people.
I was able to resolve this issue by using JsonIdentityInfo on my classes (both parent and child) along with a plugin called jackson-datatype-hibernate through which I enabled a feature called FORCE_LAZY_LOADING
If it helps anyone, below is the code for both the above configurations:
Create a class as below to enable jackson-datatype-hibernate
public class HibernateAwareObjectMapper extends ObjectMapper {
public HibernateAwareObjectMapper() {
Hibernate4Module hbm = new Hibernate4Module();
hbm.enable(Hibernate4Module.Feature.FORCE_LAZY_LOADING);
registerModule(hbm);
}
}
Tell Spring to use the above ObjectMapper than the default provided by Jackson:
<mvc:annotation-driven>
<mvc:message-converters>
<!-- Use the HibernateAware mapper instead of the default -->
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="com.adwitiya.o2plus.utilities.HibernateAwareObjectMapper" />
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
As for the JsonIdentityInfo, below is the code. Notice the use of JsonIgnoreProperties (I've used this mainly for all the sets as it creates a recursive big tree and I wanted to avoid that)
#Entity
#Table(name = "o2_branch", catalog = "o2plus"
)
#JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class, property = "id")
#JsonIgnoreProperties(value = {"active", "modifiedBy", "modifiedTimestamp", "members", "staff"})
public class Branch implements java.io.Serializable {
private Long id;
private Address address;
private String name;
private String contactNumber;
private Integer capacity;
private String manager;
private boolean active;
private String modifiedBy;
private Date modifiedTimestamp;
private Set<Member> members = new HashSet<Member>(0);
private Set<Staff> staff = new HashSet<Staff>(0);
Hope it helps more people.
One possible problem that can cause this behavior is that this is a lazy-fetched field. And transaction may be finished before serializing to json (depends on your code). Entity may be detached by the time Jackson gets it and getter will return null (or empty list, not sure). You can check this by making field eager-fetched or calling getter before entity will be detached (while transaction is still active).
In our case it was an container-managed EJB transaction and mapper was invoked from Jersey servlet.

How to join Maps

How to join newMap detals in custMap.
Map<String, Customer> custMap= new HashMap<String,Customer>();
Map<String, DoCustomer> newMap= new HashMap<String,DoCustomer>();
for (Map.Entry<String, DoCustomer> cust: newMap.entrySet()) {
custMap.put(cust.getKey(),cust.getValue());
}
public class DoCustomer {
private Long id;
private String custName;
private String description;
private String status;
private List<DoCustomerBranch> doCustomerBranch=new ArrayList<DoCustomerBranch>
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getCustName() {
return custName;
}
public void setCustName(String custName) {
this.custName = custName;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
getter/setters of doCustomerBranch
}
#Entity
#Table(name = "CUSTOMER")
public class Customer implements Serializable{
private static final long serialVersionUID = 1L;
private Long id;
private String custName;
private String description;
private String createdBy;
private Date createdOn;
private String updatedBy;
private Date updatedOn;
private Set<CustomerBranch> customerBranch=new HashSet<CustomerBranch>
#Id
#GeneratedValue(generator = "CUSTOMER_SEQ")
#SequenceGenerator(name = "CUSTOMER_SEQ", sequenceName = "CUSTOMERN_SEQ", allocationSize = 1)
#Column(name = "ID")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Column(name = "CUST_NAME",nullable=false)
public String getCustName() {
return custName;
}
public void setCustName(String custName) {
this.custName = custName;
}
#Column(name = "DESCRIPTION")
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
#Column(name = "CREATED_BY", length = 50)
public String getCreatedBy() {
return createdBy;
}
public void setCreatedBy(String createdBy) {
this.createdBy = createdBy;
}
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "CREATED_ON")
public Date getCreatedOn() {
return createdOn;
}
public void setCreatedOn(Date createdOn) {
this.createdOn = createdOn;
}
#Column(name = "UPDATED_BY", length = 50)
public String getUpdatedBy() {
return updatedBy;
}
public void setUpdatedBy(String updatedBy) {
this.updatedBy = updatedBy;
}
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "UPDATED_ON")
public Date getUpdatedOn() {
return updatedOn;
}
public void setUpdatedOn(Date updatedOn) {
this.updatedOn = updatedOn;
}
#OneToMany(cascade = { CascadeType.PERSIST, CascadeType.REMOVE }, fetch = FetchType.LAZY, mappedBy = "customer")
public Set<CustomerBranch> getCustomerBranch() {
return customerBranch;
}
public void setCustomerBranch(Set<CustomerBranch> customerBranch) {
this.customerBranch = customerBranch;
}
}
CustomerBranch
#Entity
#Table(name = "CUSTOMER_BRANCH")
public class CustomerBranch implements Serializable{
#Id
#GeneratedValue(generator = "CUSTOMER_BRANCH_SEQ")
#SequenceGenerator(name = "CUSTOMER_BRANCH_SEQ", sequenceName = "CUSTOMER_BRANCH_SEQ", allocationSize = 1)
#Column(name = "ID")
private Long id;
private String branchName;
private String branchAddress;
private Customer customer;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Column(name = "BRANCH_NAME",nullable=false)
public String getBranchName() {
return branchName;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "MOBEE_CUSTOMER")
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
}
The problem with your code is that you want to put a DoCustomer in a Customer container. It only works if DoCustomer is a subclass of Customer.
Edit 1: You could use BeanUtils to convert a DoCustomer into a Customer. Here is a good tutorial.
Do you mean:
custMap.putAll(newMap)
As everyone else has pointed out, we need to know what DoCustomer is to be able to help.
But, from what you have given us, I'd suggest casting each DoCustomer to a Customer or, more correctly, making a new Customer from the fields of each DoCustomer.
Something like:
custMap.put(cust.getKey(), new Customer(cust.getValue().getId(), cust.getValue().getCustName(), and so on..));
inside your for loop.
I can see the customer class defined you have provided doesn't have a constructor, so naturally you would have to add one to it

Categories