1

In my Spring Boot application generated with JHipster (v6.0.1) Kotlin blueprint (v0.8.0) I have the following POST request handler

    @PostMapping("/book")
    fun createBook(@RequestBody createBookVM: CreateBookVM): ResponseEntity<Book> {
        val author = authorRepository.getOne(createBookVM.authorId)
        val userLogin = SecurityUtils.getCurrentUserLogin().orElseThrow { RuntimeException("User not logged in") }
        val user = userRepository.findOneByLogin(userLogin).orElseThrow { RuntimeException("IMPOSSIBLE: user does not exist in DB") }
        val book= Book()
        book.author = author // FIXME
        book.user = user
        log.debug("Author object with id : {}", author.id) // THIS WORKS
        val result = bookRepository.save(book)
        return ResponseEntity.created(URI("/api/books/" + result.id))
            .headers(HeaderUtil.createEntityCreationAlert(applicationName, true, ENTITY_NAME, result.id.toString()))
            .body(result)
    }

The problem is that the author is not added to the book (book.author will be null). However, I can access the values of author as shown with the logging statement. Adding user to book also works fine.

I suppose the problem is that authorRepository.getOne(createBookVM.authorId) returns a proxy object, not an instance of Author, but I do not know how to cope with this situation.

mrts
  • 16,697
  • 8
  • 89
  • 72
Eerik Sven Puudist
  • 2,098
  • 2
  • 23
  • 42

1 Answers1

3

Instead of using authorRepository.getOne(createBookVM.binId) use authorRepository.findById(createBookVM.binId).

T getOne(ID id) returns a reference, not an entity.

/**
 * Returns a reference to the entity with the given identifier.
 *
 * @param id must not be {@literal null}.
 * @return a reference to the entity with the given identifier.
 * @see EntityManager#getReference(Class, Object)
 * @throws javax.persistence.EntityNotFoundException if no entity exists for given {@code id}.
 */
T getOne(ID id);

Optional<T> findById(ID id) returns an entity.

/**
 * Retrieves an entity by its id.
 *
 * @param id must not be {@literal null}.
 * @return the entity with the given id or {@literal Optional#empty()} if none found
 * @throws IllegalArgumentException if {@code id} is {@literal null}.
 */
Optional<T> findById(ID id);

Also you can use authorRepository.findOne(createBookVM.binId) for older versions than jpa 2.x.x :

/**
 * Retrieves an entity by its id.
 * 
 * @param id must not be {@literal null}.
 * @return the entity with the given id or {@literal null} if none found
 * @throws IllegalArgumentException if {@code id} is {@literal null}
 */
T findOne(ID id);
mrts
  • 16,697
  • 8
  • 89
  • 72
Francesc Recio
  • 2,187
  • 2
  • 13
  • 26
  • Given the OP wants to reference an existing `Author` in a `Book`, `getOne` is in fact *the right tool* for the job – crizzis May 19 '19 at 10:31
  • He wants the same behavior that `user` has, and in `user` returns an entity, not a reference, and it's correctly assigned to `book`. – Francesc Recio May 19 '19 at 10:42
  • The problem is that `getOne` should work in this case. The fact that it does not means there is another issue with the code. What you're suggesting is merely a workaround *and* a bad practice – crizzis May 19 '19 at 11:40
  • Can you justify me because it's bad practice? – Francesc Recio May 19 '19 at 12:10
  • It's bad practice to load the entire state of the entity (`findById`) from the db when all you need to link it with another entity is its `id` (`getOne`) – crizzis May 19 '19 at 12:16