3

I'm having trouble posting a JSON object from my UI to a Spring Boot controller.

Here is my controller, I have commented out the controller code and just return a new object. It seems that the JSON is not being parsed to the domain object correctly:

PersonnelController:

@Controller
@RequestMapping(value = "/Personnel")
public class PersonnelController {

    @RequestMapping(value = "update", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
    @ResponseBody
    public Personnel updateJson(@RequestBody Personnel personnel) {

        System.out.println("update personnel json : " + personnel.toString());
        return new Personnel();
    }
}

My controller is not a REST controller and I'm using content negotiation to be able to use Spring model and REST API together.

These are my classes :

User:

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class User extends AbstractDomainClass {

    @Column(unique = true)
    private String username;

    @Transient
    private String password;

    private String encryptedPassword;

    private boolean enabled = true;

    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable
    @JsonBackReference(value = "roles")
    private List<Role> roles = new ArrayList<>();
}

Personnel:

@Entity
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
@JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id")
public class Personnel extends User {

    private String firstName;
    private String lastName;
    private long nationalId;
    private long perssonnelId;

    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private LocalDate birthDate;

    @ManyToOne(fetch = FetchType.LAZY)
    private Company company;
}

Company:

@Entity
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Company extends AbstractDomainClass {

    @Column(unique = true)
    private String name;
    private String description;
    private String address;
    private String adminName;

    @OneToMany(fetch = FetchType.LAZY , cascade = CascadeType.PERSIST , orphanRemoval = true)
    @JoinTable
    @JsonBackReference
    private List<Personnel> personnels = new ArrayList<>();

    @OneToOne(fetch = FetchType.EAGER , cascade = CascadeType.ALL)
    private User admin;

}

Role:

@Entity 
@JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id")
public class Role extends AbstractDomainClass {

    @Column(unique = true)
    private String roleName;

    @ManyToMany(fetch = FetchType.EAGER , mappedBy = "roles")
    private List<User> users = new ArrayList<>();

    @ManyToMany
    @Fetch(FetchMode.SELECT)
    private List<Permission> permissions = new ArrayList<>();
}

(I have omitted getters and setters.)

This is the JSON I'm posting to the controller:

JSON

and this is the Spring Boot error:

WARN 10289 --- [nio-8080-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot construct instance of `navid.usermanagementsys.domain.Company` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('{"id":26,"version":0,"dateCreated":"2018-08-08T16:02:15.000+0000","name":"company1","description":"Description Description Description Description","address":"IRAN","adminName":"Company admin","admin":{"id":25,"version":0,"dateCreated":"2018-08-08T16:02:15.000+0000","username":"company","password":null,"encryptedPassword":"$2a$10$kw5T5CCep.WwC5kj7Szgyu6akB7Zbx.jgqIz5dQtAx6Oz4F8ywIWq","enabled":true,"dateLastUpdated":"2018-08-08T16:02:15.000+0000"},"dateLastUpdated":"2018-08-08T16:02:15.000+0000"}');
nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `navid.usermanagementsys.domain.Company` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value** ('{"id":26,"version":0,"dateCreated":"2018-08-08T16:02:15.000+0000","name":"company1","description":"Description Description Description Description","address":"IRAN","adminName":"Company admin","admin":{"id":25,"version":0,"dateCreated":"2018-08-08T16:02:15.000+0000","username":"company","password":null,"encryptedPassword":"$2a$10$kw5T5CCep.WwC5kj7Szgyu6akB7Zbx.jgqIz5dQtAx6Oz4F8ywIWq","enabled":true,"dateLastUpdated":"2018-08-08T16:02:15.000+0000"},"dateLastUpdated":"2018-08-08T16:02:15.000+0000"}')
at [Source: (PushbackInputStream); line: 1, column: 152] (through reference chain: navid.usermanagementsys.domain.Personnel["company"])

I have spent hours searching for a solution and I have tried creating constructor with no args but nothing solved my problem.

DaveyDaveDave
  • 9,821
  • 11
  • 64
  • 77
Navid
  • 157
  • 2
  • 2
  • 14
  • Have you looked into https://stackoverflow.com/questions/45110371/no-string-argument-constructor-factory-method-to-deserialize-from-string-value ? – mrkernelpanic Aug 09 '18 at 11:26
  • @mrkernelpanic yes i'm not using ObjectMapper as far as I know spring annotations take care of serializeing/deserializing – Navid Aug 09 '18 at 12:43
  • 1
    Spring MVC uses Jacksons Objectmapper internally... Give it a try. – mrkernelpanic Aug 09 '18 at 12:47
  • @mrkernelpanic sorry but I'm new to Spring boot , the question you mentioned says I should try mapper.configure(DeserializationConfig.Feature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true) ,I'm not sure where should I use this?Should I create a bean for this? – Navid Aug 09 '18 at 12:55
  • I resolved this error by adding a constructor that accepts only a String arg ( public Company( String company){ System.out.println("company : " + company); }) and the json string is passed corectly to this constructor , but now the problem is that object Company is not deserialized correctly , when I try to print the deserialized company in controller it gives NULL value – Navid Aug 09 '18 at 19:09
  • @mrkernelpanic I changed the @JsonBackReference and used it in Personnel calss on company attribute.Now I have this error : **Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `java.lang.Integer` from String ": not a valid Integer value; nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException : (through reference chain: navid.usermanagementsys.domain.Personnel["company"])** – Navid Aug 10 '18 at 11:01

0 Answers0