J'ai une colonne MySQL déclarée comme type JSON et j'ai des problèmes pour la mapper avec Jpa/Hibernate. J'utilise Spring Boot sur le back-end.
Voici une petite partie de mon code:
@Entity
@Table(name = "some_table_name")
public class MyCustomEntity implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(name = "json_value")
private JSONArray jsonValue;
Le programme me renvoie une erreur et me dit que je ne peux pas mapper la colonne.
Dans la table mysql, la colonne est définie comme:
json_value JSON NOT NULL;
Je préfère faire de cette façon:
Le code est ci-dessous.
JsonToMapConverted.Java
@Converter
public class JsonToMapConverter
implements AttributeConverter<String, Map<String, Object>>
{
private static final Logger LOGGER = LoggerFactory.getLogger(JsonToMapConverter.class);
@Override
@SuppressWarnings("unchecked")
public Map<String, Object> convertToDatabaseColumn(String attribute)
{
if (attribute == null) {
return new HashMap<>();
}
try
{
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(attribute, HashMap.class);
}
catch (IOException e) {
LOGGER.error("Convert error while trying to convert string(JSON) to map data structure.");
}
return new HashMap<>();
}
@Override
public String convertToEntityAttribute(Map<String, Object> dbData)
{
try
{
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString(dbData);
}
catch (JsonProcessingException e)
{
LOGGER.error("Could not convert map to json string.");
return null;
}
}
}
Partie de la classe de domaine (mappage d'entité)
...
@Column(name = "meta_data", columnDefinition = "json")
@Convert(attributeName = "data", converter = JsonToMapConverter.class)
private Map<String, Object> metaData = new HashMap<>();
...
Cette solution fonctionne parfaitement pour moi.
Si les valeurs à l'intérieur de votre tableau json sont de simples chaînes, vous pouvez le faire:
@Type( type = "json" )
@Column( columnDefinition = "json" )
private String[] jsonValue;
Comme je l'ai expliqué dans cet article , il est très facile de conserver des objets JSON en utilisant Hibernate.
Vous n'avez pas besoin de créer tous ces types manuellement, vous pouvez simplement les obtenir via Maven Central en utilisant la dépendance suivante:
<dependency> <groupId>com.vladmihalcea</groupId> <artifactId>hibernate-types-52</artifactId> <version>${hibernate-types.version}</version> </dependency>
Pour plus d'informations, consultez le projet open-source hibernate-types .
Maintenant, pour expliquer comment tout cela fonctionne.
En supposant que vous ayez l'entité suivante:
@Entity(name = "Book")
@Table(name = "book")
@TypeDef(
name = "json",
typeClass = JsonStringType.class
)
public class Book {
@Id
@GeneratedValue
private Long id;
@NaturalId
private String isbn;
@Type(type = "json")
@Column(columnDefinition = "json")
private String properties;
//Getters and setters omitted for brevity
}
Remarquez deux choses dans l'extrait de code ci-dessus:
@TypeDef
est utilisé pour définir un nouveau type d'hibernation personnalisé, json
qui est géré par le JsonStringType
properties
a un type de colonne json
et il est mappé en tant que String
C'est tout!
Maintenant, si vous enregistrez une entité:
Book book = new Book();
book.setIsbn("978-9730228236");
book.setProperties(
"{" +
" \"title\": \"High-Performance Java Persistence\"," +
" \"author\": \"Vlad Mihalcea\"," +
" \"publisher\": \"Amazon\"," +
" \"price\": 44.99" +
"}"
);
entityManager.persist(book);
Hibernate va générer l'instruction SQL suivante:
INSERT INTO
book
(
isbn,
properties,
id
)
VALUES
(
'978-9730228236',
'{"title":"High-Performance Java Persistence","author":"Vlad Mihalcea","publisher":"Amazon","price":44.99}',
1
)
Et vous pouvez également le recharger et le modifier:
Book book = entityManager
.unwrap(Session.class)
.bySimpleNaturalId(Book.class)
.load("978-9730228236");
book.setProperties(
"{" +
" \"title\": \"High-Performance Java Persistence\"," +
" \"author\": \"Vlad Mihalcea\"," +
" \"publisher\": \"Amazon\"," +
" \"price\": 44.99," +
" \"url\": \"https://www.Amazon.com/High-Performance-Java-Persistence-Vlad-Mihalcea/dp/973022823X/\"" +
"}"
);
Hibernate prenant caare de l'instruction UPDATE
pour vous:
SELECT b.id AS id1_0_
FROM book b
WHERE b.isbn = '978-9730228236'
SELECT b.id AS id1_0_0_ ,
b.isbn AS isbn2_0_0_ ,
b.properties AS properti3_0_0_
FROM book b
WHERE b.id = 1
UPDATE
book
SET
properties = '{"title":"High-Performance Java Persistence","author":"Vlad Mihalcea","publisher":"Amazon","price":44.99,"url":"https://www.Amazon.com/High-Performance-Java-Persistence-Vlad-Mihalcea/dp/973022823X/"}'
WHERE
id = 1
Tous les codes disponibles sur GitHub .
Car personne ne peut faire @J. Wang répond au travail:
Essayez d'ajouter cette dépendance (c'est pour la mise en veille prolongée 5.1 et 5.0, vérification d'autres versions ici )
<dependency>
<groupId>com.vladmihalcea</groupId>
<artifactId>hibernate-types-5</artifactId>
<version>1.2.0</version>
</dependency>
Et ajoutez cette ligne à l'entité
@TypeDef(name = "json", typeClass = JsonStringType.class)
Version complète de la classe d'entité:
@Entity
@Table(name = "some_table_name")
@TypeDef(name = "json", typeClass = JsonStringType.class)
public class MyCustomEntity implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Type( type = "json" )
@Column( columnDefinition = "json" )
private List<String> jsonValue;
}
Je teste le code avec Spring Boot 1.5.9 et Hibernate-Types-5 1.2.0.
réponse de Heril Muratovic est bon, mais je pense que le JsonToMapConverter
devrait implémenter AttributeConverter<Map<String, Object>, String>
, ne pas AttributeConverter<String, Map<String, Object>>
. Voici le code qui fonctionne pour moi
@Slf4j
@Converter
public class JsonToMapConverter implements AttributeConverter<Map<String, Object>, String> {
@Override
@SuppressWarnings("unchecked")
public Map<String, Object> convertToEntityAttribute(String attribute) {
if (attribute == null) {
return new HashMap<>();
}
try {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(attribute, HashMap.class);
} catch (IOException e) {
log.error("Convert error while trying to convert string(JSON) to map data structure.", e);
}
return new HashMap<>();
}
@Override
public String convertToDatabaseColumn(Map<String, Object> dbData) {
try {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString(dbData);
} catch (JsonProcessingException e) {
log.error("Could not convert map to json string.", e);
return null;
}
}
}