Child object is null during Jackson serialization? - json

I captured the json response and I see that it is
{"page":"1","total":"2","records":"15","rows":[{"id":1,"firstName":"John","lastName":"Smith","username":"john","password":"21232f297a57a5a743894a0e4a801fc3","role":null},{"id":2,"firstName":"Jane","lastName":"Adams","username":"jane","password":"ee11cbb19052e40b07aac0ca060c23ee","role":null},
My User and Role classes are super simple, so I think I must be overlooking something trivial.
#Entity(name="user")
public class User implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String firstName;
private String lastName;
#Column(unique=true)
private String username;
private String password;
#JsonIgnore
#OneToMany(mappedBy="user", cascade={CascadeType.PERSIST, CascadeType.MERGE},fetch =FetchType.EAGER)
private List<Role> roles = new ArrayList<Role>();
public List<Role> getRoles() {
return roles;
}
public void setRoles(List<Role> roles) {
this.roles = roles;
}
#ManyToOne
private Role role;
public User() {}
public User(String username, String password, String firstName, String lastName, Role role) {
this.username = username;
this.password = password;
this.firstName = firstName;
this.lastName = lastName;
this.role = role;
}
public User(String username, String firstName, String lastName, Role role) {
this.username = username;
this.firstName = firstName;
this.lastName = lastName;
this.role = role;
}
public User(String username) {
this.username = username;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Role getRole() {
return role;
}
public void setRole(Role role) {
this.role = role;
}
}
#Entity(name="role")
public class Role implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#JsonIgnore
#ManyToOne
#JoinColumn (name = "user_id", nullable= true)
private User user;
private Integer role;
public Role() {}
public Role(Integer role) {
this.role = role;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Integer getRole() {
return role;
}
public void setRole(Integer role) {
this.role = role;
}
}
I tried also
#JsonUnwrapped #ManyToOne private Role role;
but that's even worse because in this case my json doesn't have the role at all.
{"id":1,"firstName":"John","lastName":"Smith","username":"john","password":"21232f297a57a5a743894a0e4a801fc3"},

I was manipulating the object incorrectly before passing it back as a response due to a complex legacy relationship requirement i.e. User has a role and roles.
#JsonUnwrapped can only unwrap if there are properties in the child object, so it works as expected.

Related

Creating a role in a role

I made a spring boot user management app and every time I update the user, the role doesn't overwrite.
Like this: roles=[Role{name='Role{name='ROLE_USER'}'}]}
roles=[Role{name='Role{name='Role{name='ROLE_USER'}'}'}]}
What can I change in my code to be just a Role;
User.class :
`
package com.webusermanagement.entity;
import javax.persistence.*;
import java.util.Collection;
#Entity
#Table(name="user")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "username")
private String username;
#Column(name = "password")
private String password;
#Column(name="first_name")
private String firstName;
#Column(name="last_name")
private String lastName;
#Column(name = "email")
private String email;
#Column(name="enabled")
private Boolean enabled;
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "users_roles",
joinColumns = #JoinColumn(name = "user_id"),
inverseJoinColumns = #JoinColumn(name = "role_id"))
private Collection<Role> roles;
public User(){}
public User(String username, String password, String firstName, String lastName, boolean enabled, Collection<Role> roles) {
this.username = username;
this.password = password;
this.firstName = firstName;
this.lastName = lastName;
this.enabled = enabled;
this.roles = roles;
}
public User(String username, String password, String firstName, String lastName, boolean enabled) {
this.username = username;
this.password = password;
this.firstName = firstName;
this.lastName = lastName;
this.enabled = enabled;
}
public User(String username, String password, Collection<Role> roles) {
this.username = username;
this.password = password;
this.roles = roles;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public Collection<Role> getRoles() {
return roles;
}
public void setRoles(Collection<Role> roles) {
this.roles = roles;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
#Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
", email='" + email + '\'' +
", enabled=" + enabled +
", roles=" + roles +
'}';
}
}
t`
Role.class:
`
package com.webusermanagement.entity;
import javax.persistence.*;
#Entity
#Table(name = "role")
public class Role {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
#Column(name = "name")
private String name;
public Role(){}
public Role(String name) {
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
return "Role{" +
"name='" + name + '\'' +
'}';
}
}
`
UserDAOImplementation.class
`
#Repository
public class UserDAOImplementation implements UserDAO {
#Autowired
private EntityManager entityManager;
#Override
public User findByUserName(String username) {
Session currentSession = entityManager.unwrap(Session.class);
// now retrieve/read from database using username
Query<User> theQuery = currentSession.createQuery("from User where username=:uName");
theQuery.setParameter("uName", username);
User theUser = null;
try {
theUser = theQuery.getSingleResult();
} catch (Exception e) {
theUser = null;
}
return theUser;
}
#Override
public void save(User user) {
Session currentSession = entityManager.unwrap(Session.class);
currentSession.saveOrUpdate(user);
}
#Override
public void deleteByUsername(String username) {
Session session = entityManager.unwrap(Session.class);
Query query=session.createQuery("delete from User where username=:userName");
query.setParameter("userName",username);
query.executeUpdate();
}
#Override
public List<User> findAll() {
Session session = entityManager.unwrap(Session.class);
Query query=session.createQuery("from User");
List<User>users=query.getResultList();
return users;
}
#Override
public void update(User user) {
Session currentSession = entityManager.unwrap(Session.class);
currentSession.update(user);
}
}
`

java.lang.reflection.InvocationTargetException during creation of object

I have difficult to figure out to create an object in a class for jUnit test.
In my test I have : User user = new User(); , and I receive a
java.lang.reflect.InvocationTargetException cathed into
public abstract class ReflectiveCallable {
public Object run() throws Throwable {
try {
return runReflectiveCall();
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
This is my User class:
#Entity
public class User implements Serializable{
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String firstName;
private String lastName;
private Double internalKey = (new Random()).nextDouble();
protected User() {
super();
}
public User(String firstName, String lastName) {
super();
this.firstName = firstName;
this.lastName = lastName;
}
public Long getId() {
return id;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public String getInternalKey() {
return internalKey;
}
}
What is wrong? thanks

Spring Boot: Saving a one to many json request, foreign key is not saved automatically

I have 2 entities, Role and Resource. A role can have many resources.
#Entity
public class Resource {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#Column(name="firstname")
private String firstName;
#Column(name="lastname")
private String lastName;
private String email;
#ManyToOne
#JoinColumn(name="roleId", nullable = false)
private Role role;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Role getRole() {
return role;
}
public void setRole(Role role) {
this.role = role;
}
}
#Entity
public class Role {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#Column(name = "rolename")
private String roleName;
#OneToMany(mappedBy = "role", cascade = CascadeType.ALL)
private List<Resource> resources;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public List<Resource> getResources() {
return resources;
}
public void setResources(List<Resource> resources) {
this.resources = resources;
}
}
I'm trying to save a Role object that has a resource in it. This is the body of my json in postman.
{
"roleName" : "Business Analyst",
"resources" : [{
"firstName" : "John",
"lastName" : "Doe",
"email" : "John#Doe.com"
}]
}
http post call in postman:
http://localhost:8080/app/admin/roles/role
Role Controller
#RestController
#RequestMapping(value="/admin/roles")
public class RoleController {
#Autowired
private RoleService roleService;
private static final Logger log = LoggerFactory.getLogger(RoleController.class);
#RequestMapping(value="/role", method = RequestMethod.POST)
public ResponseEntity<?> addRole(#RequestBody Role role, UriComponentsBuilder ucBuilder){
log.info("Adding Role {}" + role);
log.info("Adding Rolename:" + role.getRoleName());
roleService.addRole(role);
HttpHeaders headers = new HttpHeaders();
headers.setLocation(ucBuilder.path("/admin/roles/role/{id}").buildAndExpand(role.getId()).toUri());
return new ResponseEntity<String> (headers,HttpStatus.CREATED);
}
#RequestMapping(value="role", method = RequestMethod.GET)
public ResponseEntity<List<Role>> listAllRoles(){
List<Role> roles = roleService.getAllRoles();
return new ResponseEntity<List<Role>>(roles, HttpStatus.OK);
}
}
RoleRepository
public interface RoleRepository extends CrudRepository<Role, Integer> {
}
RoleService
public interface RoleService {
public void addRole(Role role);
}
RoleServiceImpl
#Service
public class RoleServiceImpl implements RoleService {
#Autowired
private RoleRepository roleRepository;
#Override
public void addRole(Role role) {
roleRepository.save(role);
}
}
Whats happening is, the role Business Analyst gets save in the roleName field of Role table. The id of the said row is auto generated. At the same time, the resource with firstName = John, lastName = Doe and email = John#Doe.com gets save in the Resource table.
However, the role_id is not being saved automatically in the Resource table so now it is null ( the table Resource has the role_id set to nullable ). I was expecting that when I do the json post, the data will be automatically saved in the Role table and also the Resource table. Both of these are happening except that the role_id is not being saved. What did I miss?
Change addRole like below :
public void addRole(Role role) {
for(Resource resource: role.getResources()){
resource.setRole(role);
}
roleRepository.save(role);
}

Output registered users as Json in spring mvc

I have a simple form for registration with generated id and then title, username and password. Once user is registered I want to go to Json page and be able to pull that data in there, is that even possible? if so how is it done? This is what I have at the moment but that doesn't work.
Model:
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String title;
#NotNull
#Size(min=2, max=30)
private String username;
#NotNull
#Size(min=6)
private String password;
public String getTitle() { return title; }
public String getUsername() { return username; }
public String getPassword() { return password; }
public Long getId() { return id; }
public void setId(Long id) {
this.id = id;
}
public void setUsername(String username) { this.username = username; }
public void setPassword(String password) { this.password = password; }
public void setTitle(String title) { this.title = title; }
public List<Note> getNotes() {
return notes;
}
#OneToMany
private List<Note> notes = new ArrayList<Note>();
}
Controller:
#RequestMapping(value = "/json", method = RequestMethod.GET)
#ResponseBody
public User json(){
User user = new User();
user.setId(id);
user.setTitle(title);
user.setUsername(username);
user.setPassword(password);
return user;
}
}

ResponseBody get object list from object. #JsonIgnore not working

Ok i have class User
#Entity
#Table(name = "users")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
private Long id_user;
#Column(nullable = false)
private String email;
#Column(nullable = true)
private String password;
private String firstname;
private String lastname;
private Boolean enabled;
private String phone;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id_company")
private Company company;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id_rank")
#JsonBackReference
private Authority authorities;
#OneToMany(mappedBy = "create_by")
private List<Cms> create_by;
#OneToMany(mappedBy = "modified_by")
private List<Cms> modified_by;
#OneToMany(mappedBy = "id_issuer")
private List<Ticket> id_issuer;
#OneToMany(mappedBy = "id_responsible")
private List<Ticket> id_responsible;
#OneToMany(mappedBy = "id_author")
private List<IssueMsg> id_author;
public User() {
}
public User(String email, String password, String firstname, String lastname, String phone, Company company, Authority authority) {
this.email = email;
this.password = password;
this.firstname = firstname;
this.lastname = lastname;
this.enabled = true;
this.phone = phone;
this.authorities = authority;
}
#Override
public String toString() {
return "User [id_user=" + id_user + ", email=" + email + ", password="
+ password + ", firstname=" + firstname + ", lastname="
+ lastname + ", enabled=" + enabled + ", phone=" + phone
+ "]";
}
public Long getId_user() {
return id_user;
}
public void setId_user(Long id_user) {
this.id_user = id_user;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
#JsonIgnore
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
public Boolean getEnabled() {
return enabled;
}
public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public Company getCompany() {
return company;
}
public void setCompany(Company company) {
this.company = company;
}
/**
* #return the authorities
*/
public Authority getAuthorities() {
return authorities;
}
/**
* #param authorities the authorities to set
*/
public void setAuthorities(Authority authority) {
this.authorities = authority;
}
#JsonIgnore
public List<Cms> getCreate_by() {
return create_by;
}
public void setCreate_by(List<Cms> create_by) {
this.create_by = create_by;
}
#JsonIgnore
public List<Cms> getModified_by() {
return modified_by;
}
public void setModified_by(List<Cms> modified_by) {
this.modified_by = modified_by;
}
#JsonIgnore
public List<Ticket> getId_issuer() {
return id_issuer;
}
public void setId_issuer(List<Ticket> id_issuer) {
this.id_issuer = id_issuer;
}
#JsonIgnore
public List<Ticket> getId_responsible() {
return id_responsible;
}
public void setId_responsible(List<Ticket> id_responsible) {
this.id_responsible = id_responsible;
}
#JsonIgnore
public List<IssueMsg> getId_author() {
return id_author;
}
public void setId_author(List<IssueMsg> id_author) {
this.id_author = id_author;
}
}
And class Company
#Entity
#Table(name = "companies")
public class Company implements Serializable {
private static final long serialVersionUID = 6255059577246367312L;
#Id
#GeneratedValue
private Long id_company;
private String name;
private String adress;
private String email;
private String phone;
#OneToMany(mappedBy = "company")
#JsonManagedReference
private List<User> user;
#Override
public String toString() {
return "Company [id_company=" + id_company + ", name=" + name
+ ", adress=" + adress + ", email=" + email + ", phone="
+ phone + "]";
}
public Company() {
}
public Company(Long id_company, String name, String adress, String email,
String phone) {
this.id_company = id_company;
this.name = name;
this.adress = adress;
this.email = email;
this.phone = phone;
}
public Long getId_company() {
return id_company;
}
public void setId_company(Long id_company) {
this.id_company = id_company;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAdress() {
return adress;
}
public void setAdress(String adress) {
this.adress = adress;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public List<User> getUser() {
return user;
}
public void setUser(List<User> user) {
this.user = user;
}
}
I getting all result from database, and returning this as response body.
My JSON response get user.company.user list and i don't need what. I was try add on getter company user #JsonIgnore but i getting error
com.fasterxml.jackson.databind.JsonMappingException: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: java.util.ArrayList[1]->projektzespolowy.model.User["company"]->projektzespolowy.model.Company_$$_jvstcb8_2["handler"])
I read many post about fix thix but no one help. This is possible to ignore this user list in company?
I think you are getting this exception because User#company is lazy fetched so jackson tries to serialize a hibernate proxy. Try with fetch = FetchType.EAGER on the mapping, or call user.getCompany() in the controller prior to returning the results.