Search code examples
kotlinneo4jneo4j-ogmneo4j-ogm-bolt-driver

Neo4j OGM - Deserializing enum lists in Kotlin


I'm trying to store and retrieve an object which has an enum list in a Neo4j database with Kotlin. Storing the entity with the enum works fine, but deserializing it back to the same enum doesn't work the way I'm trying to in Kotlin. I'm using the bolt driver.

enum class DayOfWeek { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY }

@NodeEntity
data class Weekend(
  @Id @GeneratedValue var id: Long? = null, 
  var days: List<DayOfWeek>? = null
)

fun main(args: Array<String>) {
  val config = Configuration.Builder()
    .uri("bolt://localhost:7687")
    .credentials("username", "password")
    .build()
  val sessionFactory = SessionFactory(config, "com.example.calendar")
  val session = sessionFactory.openSession()
  val weekend = session.load(Weekend::class.java, 10L)
  weekend.days?.forEach { print("The weekend consists of: $it") }
}

Doing this just throws an exception: Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to com.example.calendar.DayOfWeek. Doing the same in Java with this class works fine:

public class WeekendJ {
  @Id
  @GeneratedValue
  Long id;
  List<DayOfWeek> days;
  public WeekendJ() {
  }
  public WeekendJ(List<DayOfWeek> days) {
    this.days = days;
  }
}

My POM:

<dependency>
  <groupId>org.neo4j</groupId>
  <artifactId>neo4j-ogm-core</artifactId>
  <version>3.1.5</version>
  <scope>compile</scope>
</dependency>

<dependency>
  <groupId>org.neo4j</groupId>
  <artifactId>neo4j-ogm-bolt-driver</artifactId>
  <version>3.1.5</version>
  <scope>runtime</scope>
</dependency>

<dependency>
  <groupId>org.jetbrains.kotlin</groupId>
  <artifactId>kotlin-stdlib-jdk8</artifactId>
  <version>1.3.11</version>
</dependency>

Am I missing something obvious? How do you solve this is Kotlin?


Solution

  • I ran into this exact same problem. Not sure of the exact underlying cause, but it seems like a bug in the OGM+Kotlin. I fixed it with a converter that told OGM to convert it to a String array for storing in Neo4J. Like so:

    Tag your property to use the converter:

    public class WeekendJ {
      @Id
      @GeneratedValue
      Long id;
    
      @Convert(DayOfWeekConverter::class)
      List<DayOfWeek> days;
    
      public WeekendJ() {
      }
      public WeekendJ(List<DayOfWeek> days) {
        this.days = days;
      }
    }
    

    The converter:

    class DayOfWeek : AttributeConverter<Set<DayOfWeek>, Array<String>> {
        override fun toGraphProperty(days: Set<DayOfWeek>): Array<String> =
                days.map { it.name }.toTypedArray()
    
        override fun toEntityAttribute(dayNames: Array<String>): Set<DayOfWeek> =
                dayNames.map { DayOfWeek.valueOf(it) }.toSet()
    }