6

The question I'm asking is pretty simple but seemingly impossible to find an answer to. I'm using Spring Data JPA and I have a JDBC/JPA DataSource (which is PostgreSQL, but that shouldn't matter), which is preloaded with data and I simply am trying to read from it.

How do I construct my POJO so that I can have a List<String> field that doesn't require an extra join table? Here is an example entity class I have:

@Entity
@Table(name = "pojo", schema = "pojoschema")
public class POJO {
  @Id
  @Column(name = "id", columnDefinition = "uuid")
  private String id;

  @Column(name = "a_string", columnDefinition = "text")
  private String aString;

  @Column(name = "strings", columnDefinition = "text[]")
  @ElementCollection
  private List<String> strings;

  // getters/setters
}

Doing this I get a org.postgresql.util.PSQLException: ERROR: relation "pojo_strings" does not exist.

Why does hibernate think that the Strings I want are in another table? How do I fix this behavior? I'm simply trying to map a PostgreSQL text[] column back to a List<String> in a POJO via JPA.

K.Nicholas
  • 10,956
  • 4
  • 46
  • 66
heez
  • 2,029
  • 3
  • 27
  • 39

1 Answers1

6

The approach in these cases is to use jpa's AttributeConverter like this:

@Converter
public class StringToListConverter implements AttributeConverter<List<String>, String> {

  @Override
  public String convertToDatabaseColumn(List<String> list) {
    if(list == null) return "";
    return String.join(",", list); 
  }

  @Override
  public List<String> convertToEntityAttribute(String joined) {
    if(joined == null) return new ArrayList<>();
    return new ArrayList<>(Arrays.asList(joined.split(",")));
  }
}

And use the annotation Converter in your entity field:

@Entity
@Table(name = "pojo", schema = "pojoschema")
public class POJO {
  @Id
  @Column(name = "id", columnDefinition = "uuid")
  private String id;

  @Column(name = "a_string", columnDefinition = "text")
  private String aString;

  @Column(name = "strings")
  @Convert(converter = StringToListConverter.class)
  private List<String> strings;

  // getters/setters
}
NiVeR
  • 9,644
  • 4
  • 30
  • 35
  • My database column isn't a single `text` field. Would this work if the column in the database is `text[]`? – heez Nov 01 '18 at 20:59
  • Ofc, in this case you can/should use `text` datatype on db side. – NiVeR Nov 01 '18 at 21:00
  • Thanks, that did work. I saw your solution somewhere else, but assumed the mapping from `text[]` to `String` wouldn't work. Just seems like extra work I shouldn't have to do when using an ORM :/ – heez Nov 01 '18 at 21:07
  • ORMs do a tremendous job to facilitate the mapping of tables in objects but there are also some cases that need to be handled manually (at a point). – NiVeR Nov 01 '18 at 21:09
  • Definitely agree, this just seems like a trivial case though. – heez Nov 01 '18 at 21:18