Ошибка синтаксического анализа JSON: невозможно создать экземпляр пользовательского объекта при работе с отношением один к одному - PullRequest
0 голосов
/ 04 февраля 2019

Я разрабатываю REST API с использованием Java и Spring Boot.

Существуют две сущности с отношение один к одному :

Пользователь:

@Entity
@Table(name = "users")
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;

    @Column(name = "first_name", nullable = false)
    private String firstName;

    @Column(name = "last_name", nullable = false)
    private String lastName;

    @Column(name = "email", nullable = false, unique = true)
    private String email;

    @OneToOne(fetch = FetchType.LAZY,
            cascade =  CascadeType.ALL,
            mappedBy = "employee")
    @JsonBackReference
    private Company company;

    // constructors, getters & setters...

И Компания:

@Entity
@Table(name = "companies")
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Company {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;

    @Column(name = "company_name", nullable = false)
    private String companyName;

    @Column(name = "company_info", nullable = false)
    private String companyInfo;

    @CreationTimestamp
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "created_at", nullable = false)
    private Date createdAt;

    @OneToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "employee_id", nullable = false)
    @JsonManagedReference
    private User employee;

   // constructors, getters & setters...

Я хочу иметь возможность создавать Компании с помощью метода POST , поэтому я создал один в CompanyController (я опускаю методы GET в контроллере, поскольку они работают должным образом):

@RestController
@RequestMapping(value = "/api/v1")
public class CompanyController {

    private static final Logger logger = LoggerFactory.getLogger(CompanyController.class);

    @Autowired
    private CompanyRepository companyRepository;

    @PostMapping(path = "company", produces = "application/JSON")
    public ResponseEntity<?> createCompany(@RequestBody Company company){
        logger.info("Request to save new Company: {}", company);

        Company result = companyRepository.save(company);
        return ResponseEntity.ok().body(result);
    }

Метод createCompany отлично работает, когда я отправляю запрос с JSON, как показано ниже:

{
"companyName" : "Big Client Company 2",
"companyInfo" : "unspecified",
"employee" : {
    "id": 17,
    "firstName": "someName",
    "lastName": "someLastName",
    "email": "someEmail@a.ru"
  }
}

Однако я хочу иметь возможность отправлять JSON без всего тела поля сотрудника, но спросто идентификатор:

{
"companyName" : "Big Client Company 2",
"companyInfo" : "unspecified",
"employee" : 17
}

Когда я делаю это, я получаю ошибку:

Ошибка синтаксического анализа JSON: Невозможно создать экземпляр model.User (хотя существует хотя бы один Создатель)): нет int / Int-аргумент конструктор / фабричный метод для десериализации из числового значения (17)

Так что вопрос есть ли способ сделать это без изменения Класс компании «сотрудник» в строку (и избавление от отношения «один к одному»)?

Я пытался найти примеря пишу собственные десериализаторы JSON, но мне не удалось ни одного подходящего для меня.

Ответы [ 2 ]

0 голосов
/ 05 февраля 2019

Вы можете использовать пользовательскую десериализацию:

public class CompanyDeserializer extends StdDeserializer<Company> { 

@Autowired
private UserRepository userRepository;

public CompanyDeserializer() { 
    this(null); 
} 

public CompanyDeserializer(Class<?> vc) { 
    super(vc); 
}

@Override
public Company deserialize(JsonParser jp, DeserializationContext ctxt) 
  throws IOException, JsonProcessingException {
    JsonNode node = jp.getCodec().readTree(jp);
    Company c = new Company();
    //Set the rest of the attributes.
    Long empId = (Long) ((IntNode) node.get("employee")).numberValue();
    c.setEmployee(userRepository.findById(empId).orElse(null)));
    return c;
}

}

0 голосов
/ 04 февраля 2019

Проблема в том, что у вашего пользователя есть обязательные поля, которые необходимо указать при их создании (firstName, lastName и email).

У вас нет возможности создать пользователя без нихиспользуя определения, которые у вас есть.

Вы можете использовать nullable = true в этих полях, но у вас могут возникнуть несоответствия в данных, которые вы хотите сохранить в своей БД.Если оставить эти поля пустыми, я бы предложил этот подход.

Кроме того, обратите внимание, что смешивание уровня контроллера REST и уровня хранилища обычно является плохой практикой.Вы должны разделить эти слои сервисным слоем.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...