0

i have two different small projects in kotlin, one where mapping works (i dont use data class) and the other one where mapping does not work.

The working example Book

@Entity
class Book()  {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    var id: Int? = null
    var name: String? = null

    @ManyToMany(cascade = [CascadeType.PERSIST, CascadeType.MERGE])
    @JoinTable(name = "BOOK_AUTHOR", joinColumns = [JoinColumn(name = "BOOK_ID", referencedColumnName = "ID")], inverseJoinColumns = [JoinColumn(name = "AUTHOR_ID", referencedColumnName = "ID")])
    private var authors: MutableSet<Author> = HashSet()

//    constructor(name: String?, authors: Set<Author>) : this() {
//        this.name = name
//
//        setAuthors(authors)
//    }

    fun getAuthors(): Set<Author> {
        return authors
    }

    fun setAuthors(authors: Set<Author>) {

        for (author in authors) {
            author.books.add(this)
            this.authors.add(author)
        }
    }
    }

Author

   @Entity
class Author()  {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    var id: Int? = null
    var name: String? = null

    @ManyToMany(mappedBy = "authors")
    val books: MutableSet<Book> = HashSet<Book>()


//    constructor(name: String?) : this() {
//        this.name = name
//    }



}

now the one that does not work, with data classes

Book

@Entity
data class Book  (
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        val id:Int,
        var name:String,
        @ManyToMany(cascade = [CascadeType.PERSIST, CascadeType.MERGE])
        @JoinTable(name = "BOOK_AUTHOR", joinColumns = [JoinColumn(name = "BOOK_ID", referencedColumnName = "ID")], inverseJoinColumns = [JoinColumn(name = "AUTHOR_ID", referencedColumnName = "ID")])
        private var authors: MutableSet<Author> = HashSet()


){
    constructor() : this(-1,"", mutableSetOf()) {}
//    constructor(name: String) : this() {
//        this.name = name
//        authors = HashSet()
//    }

    constructor(name: String, authors: Set<Author>) : this() {
        this.name = name
        //this.authors = authors;
        setAuthors(authors)
    }

    fun getAuthors(): Set<Author> {
        return authors
    }

    fun setAuthors(authors: Set<Author>) { //this.authors = authors;
//add relations manually
        for (author in authors) {
            author.books.add(this)
            this.authors.add(author)
        }
    }
    override fun toString(): String {
        return "heya"
    }
}

author

@Entity
    data class Author(
            @Id
            @GeneratedValue(strategy = GenerationType.IDENTITY)
            val id:Int,
            var name:String,
            @ManyToMany(mappedBy = "authors")
            val books: MutableSet<Book> = HashSet<Book>()

    ){
        constructor() : this(-1,"", mutableSetOf()) {}
        constructor(name: String) : this() {
            this.name = name
        }

        override fun toString(): String {
            return "heya"
        }
    }

Now i got this to work in first example, but i do not use data class provided by kotlin, i am not sure if that is big deal or not, here is mentioned that some of the functionallity will not be available.

Second just for the sake of it i would like to understand what is needed for the data class mapping to work, since now it always just throws a stack overflow error,

ImRaphael
  • 204
  • 2
  • 20

1 Answers1

0

As per JPS spec, the entity class should be non-final and should have at least one no-args constructor and all the fields to persist should be non-final too.

So kotlin data class might not work (but it depends on which JPA implementation you use). I would recommended to use open class for entity classes.