2012-08-14 1 views
5

devo classe di dati/tabella "Utente" che ha colonna "preferenze"Come serializzare e deserializzare automaticamente la stringa JSON utilizzando JPA e Hibernate?

CREATE table "user"; 
ALTER TABLE "user" ADD COLUMN preferences TEXT; 

preferenze è un'immagine e sto memorizzando JSON lì.

public class User extends AbstractEntity{ 
public String preferences; 
} 

così user.preferences valore è "{notifyByEmail:1, favouriteColor:"blue" }"

Come posso avvolgere con qualche annotazione in modo da poter accedere come

user.preferences.notifyByEmail 

o senza necessità di avvolgere in dati oggetto

user.preferences.get("notifByEmail"); 
user.preferences.set("notifByEmail",true); 

Immagino ci possa essere qualche annotazione di Jackson che io possa dd a campo come

@JsonGenerate 
public String preferences; 

Sono abbastanza nuovo per APP e la documentazione è ripida.

Credo che il mio caso sia abbastanza comune. Qualcuno può dare qualche esempio?

+0

Qual è il motivo per cui si desidera archiviare questi dati come stringhe JSON e non campi separati e distinti (qui, di tipi booleani ed enum)? – Samuel

+0

Essendo la logica, non voglio supportare ogni preferenza valore-chiave come campo separato. Tasto Preference: i valori crescono e si accumulano e ce ne sono molti. cambiare modello o aggiungere campi al database per ognuno di essi è eccessivo. – Roman

+0

Hai quindi considerato di utilizzare una tabella degli attributi per narrare i valori? Il caso d'uso è in effetti comune, ma la soluzione proposta non si adatta a un modello relazionale. – Samuel

risposta

6

Onestamente, penso che la soluzione migliore sia creare una tabella separata (preferenza) per le proprietà.

+------------+ 
| preference | 
+------------+---------+------+-----+ 
| Field  | Type | Null | Key | 
+------------+---------+------+-----+ 
| user_id | bigint | NO | PRI | 
| key  | varchar | NO | PRI | 
| value  | varchar | NO |  | 
+------------+---------+------+-----+ 

È possibile mappare questo nel vostro soggetto come questo:

@Entity 
public class User 
{ 
    @Id 
    private Long id; 

    @ElementCollection 
    @MapKeyColumn(name = "key") 
    @Column(name = "value") 
    @CollectionTable(name = "preference", 
     joinColumns = @JoinColumn(name = "user_id")) 
    private Map<String, String> preferences; 
} 

In questo modo il database è più normalizzata e non si deve scherzare con 'soluzioni creative' come memorizzando le preferenze come JSON .

+0

Grazie per aver fornito una descrizione completa. Lo proverò! – Roman

+7

Questo non lo fa nel modo in cui la domanda lo richiedeva. –

+2

@HiramChirino Non vedo nulla di sbagliato nel fornire un'alternativa all'interrogante. Soprattutto quando un'alternativa può fornire una soluzione migliore. L'intervistatore sembrava soddisfatto di questa soluzione (utile), la risposta non è né semplice né corretta, quindi non vedo alcun motivo per votare. Per favore [vedi le pagine di aiuto su quando votare giù] (http://stackoverflow.com/help/privileges/vote-down), per motivi di Stackoverflow. – siebz0r

2

Se davvero bisogno di una cosa del genere il più raccomandabile è quello di fare i prossimi:

public class User extends AbstractEntity{ 
    @JsonIgnore //This variable is going to be ignored whenever you send data to a client(ie. web browser) 
    private String preferences; 

    @Transient //This property is going to be ignored whenever you send data to the database 
    @JsonProperty("preferences") //Whenever this property is serialized to the client, it is going to be named "perferences" instead "preferencesObj" 
    private Preferences preferencesObj; 

    public String getPreferences() { 
    return new ObjectMapper().writeValueAsString(preferencesObj); 
    } 

    pbulic void setPreferneces(String preferences) { 
    this.preferences = preferences; 
    this.preferncesObj = new ObjectMapper().readValue(preferences, Preferences.class); 
    } 

    pubilc Preferences getPreferencesObj() { 
    return preferencesObj; 
    } 

    public void setPreferencesObj(Preferences preferencesObj) { 
    this.preferencesObj = preferencesObj; 
    } 
} 

Note aggiuntive:

  • Forse la proprietà privata "preferenze" potrebbe essere soppresso e utilizzare solo getter e setter.
  • Non ho provato quel codice.
  • Il codice sopra riportato è destinato all'utilizzo del modulo Jackson ObjectMapper e Hibernate.
+0

puoi anche fornire l'esempio di JSON Array. Sto lottando per deserializzare JSON Array con annotaion. – Azerue

+0

Questo non richiede una classe chiamata 'Preferenze' che richiede tutte le diverse preferenze che un utente può avere? – Christian

+0

si. Se preferisci qualcosa di dinamico, è meglio usare una mappa. –

6

È possibile ottenere questo utilizzando JPA Converter.

Entità;

@Id 
@GeneratedValue 
Long id; 

@Column(name = "mapvalue") 
@Convert(converter = MapToStringConverter.class) 
Map<String, String> mapValue; 

Converter:

@Converter 
public class MapToStringConverter implements AttributeConverter<Map<String, String>, String> { 

    ObjectMapper mapper = new ObjectMapper(); 

    @Override 
    public String convertToDatabaseColumn(Map<String, String> data) { 
     String value = ""; 
     try { 
      value = mapper.writeValueAsString(data); 
     } catch (JsonProcessingException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
     return value; 
    } 

    @Override 
    public Map<String, String> convertToEntityAttribute(String data) { 
     Map<String, String> mapValue = new HashMap<String, String>(); 
     TypeReference<HashMap<String, Object>> typeRef = new TypeReference<HashMap<String, Object>>() { 
     }; 
     try { 
      mapValue = mapper.readValue(data, typeRef); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
     return mapValue; 
    } 

} 

Salvataggio dei dati:

Map<String, String> mapValue = new HashMap<String, String>(); 
mapValue.put("1", "one"); 
mapValue.put("2", "two"); 
DataEntity entity = new DataEntity(); 
entity.setMapValue(mapValue); 
repo.save(entity); 

Il valore memorizza nel DB come

{"1":"three","2":"two"} 
0

Come ho spiegato in this article, è molto facile persistono l'oggetto JSON usando Hibe rnate.

Non è necessario creare tutti questi tipi manualmente, è possibile ottenere semplicemente loro via Maven centrale utilizzando la seguente dipendenza:

<dependency> 
    <groupId>com.vladmihalcea</groupId> 
    <artifactId>hibernate-types-52</artifactId> 
    <version>${hibernate-types.version}</version> 
</dependency> 

Per ulteriori informazioni, visitate il hibernate-types open-source project.

Ora, è necessario dichiarare il nuovo tipo su entrambi livello di classe o in un package-info.java pacchetto di livello descriptior:

@TypeDef(
    name = "jsonb-node", 
    typeClass = JsonNodeBinaryType.class 
) 

E la mappatura entità sarà simile a questa:

@Type(type = "json-node") 
@Column(columnDefinition = "json") 
private JsonNode preferences; 

Questo è tutto!