Let\'s say I have the following situation:
Object Car has an ArrayList of prices, which are all numbers. Is it possible in Hibernate to save all the prices in a sin
AFAIR, Hibernate will use native serialization and store the resulting bytes in your column. I wouldn't do that though, and use a dedicated transformation that would make the prices readable in the database, and at least be able to use the data without needing Java native serialization:
@Basic
private String prices;
public void setPrices(List<Integer> prices) {
this.prices = Joiner.on(',').join(prices);
}
public List<Integer> getPrices() {
List<Integer> result = new ArrayList<Integer>();
for (String s : Splitter.on(',').split(this.prices)) {
result.add(Integer.valueOf(s));
}
return result;
}
I updated Chris's code to utilize the Jackson JSON library for lists and maps:
import java.util.List;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
@Converter
public class ListToJsonConverter<T> implements AttributeConverter<List<T>, String> {
private static ObjectMapper mapper = new ObjectMapper();
@Override
public String convertToDatabaseColumn(List<T> attribute) {
if (attribute == null) {
return null;
}
try {
return mapper.writeValueAsString(attribute);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
@SuppressWarnings("unchecked")
@Override
public List<T> convertToEntityAttribute(String dbData) {
if (dbData == null || dbData.isEmpty()) {
return null;
}
try {
return mapper.readValue(dbData, List.class);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
import java.util.Map;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
@Converter
public class MapToJsonConverter<T, K> implements AttributeConverter<Map<T, K>, String> {
private static ObjectMapper mapper = new ObjectMapper();
@Override
public String convertToDatabaseColumn(Map<T, K> attribute) {
if (attribute == null) {
return null;
}
try {
return mapper.writeValueAsString(attribute);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
@SuppressWarnings("unchecked")
@Override
public Map<T, K> convertToEntityAttribute(String dbData) {
if (dbData == null || dbData.isEmpty()) {
return null;
}
try {
return mapper.readValue(dbData, Map.class);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@Column(name = "example_list")
@Convert(converter = ListToJsonConverter.class)
public List<String> getExampleList() {
return exampleList;
}
@Column(name = "example_map")
@Convert(converter = MapToJsonConverter.class)
public Map<String, String> getExampleMap() {
return exampleMap;
}
This allows storing just about any types in a human-readable way in a string column, and makes it so you don't need a separate class for every type of list or hashmap. It also automatically escapes the strings.
You can implement your own custom type as an array:
http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/types.html#types-custom
Also, it is not that hard to find some implementations, some of them going as far to let you compare those arrays in a HQL where clause.
https://forum.hibernate.org/viewtopic.php?t=946973
I personally never thought i would try something like this. But now I am very curious.
I know this is an old question but for anyone trying to do this in a JPA context you can do this
import org.apache.commons.lang3.StringUtils;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.Collections;
@Converter
public class IntArrayToStringConverter implements AttributeConverter<List<Integer>,String>{
@Override
public String convertToDatabaseColumn(List<Integer> attribute) {
return attribute == null ? null : StringUtils.join(attribute,",");
}
@Override
public List<Integer> convertToEntityAttribute(String dbData) {
if (StringUtils.isBlank(dbData))
return Collections.emptyList();
try (Stream<String> stream = Arrays.stream(dbData.split(","))) {
return stream.map(Integer::parseInt).collect(Collectors.toList());
}
}
}
Then to use it something like this in your entity
@Entity
public class SomeEntity
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column
@Convert(converter = IntArrayToStringConverter.class)
private List<Integer> integers;
...
}