2015-09-24 4 views
5

के साथ एक पाठ क्षेत्र में JSON के रूप में एक सूची भंडारण मैं हाइबरनेट में निम्नलिखित मॉडल की तरह कुछ है: हाइबरनेट

class Person { 
    String name; 
    List<Address> addresses; 
} 

class Address { 
    String street; 
    String city; 
} 

अब मैं एक मेज, जहां सभी व्यक्ति के पते एक को क्रमांकित हैं करने के लिए व्यक्ति बनाए रखना चाहते JSON स्ट्रिंग और व्यक्ति तालिका में एक कॉलम में संग्रहीत। डेटाबेस में एक व्यक्ति रिकॉर्ड इस तरह दिखेगा:

name: 'Benjamin Franklin', addresses: '[{"street"="...","city"="..."}, {...}]' 

क्या हाइबरनेट का उपयोग करके इसे प्राप्त करने का कोई तरीका है?

यदि पते एक सूची नहीं थे, तो मैं क्रमबद्ध करने के लिए उपयोगकर्ता टाइप पंजीकृत कर सकता था।

मैं जेपीए के @ कनवर्टर का भी उपयोग नहीं कर सकता, क्योंकि हाइबरनेट कार्यान्वयन में परिवर्तनों का पता नहीं लगाया जाएगा, HHH-10111 देखें।

+0

आप किस डीबी का उपयोग करते हैं? उदाहरण के लिए पोस्टग्रेस में एक जेसन कॉलम प्रकार है। हालांकि मैंने कभी कोशिश नहीं की, इसे हाइबनेट के साथ उपयोग करना संभव होना चाहिए ... http: //www.vivekpatidar.com/? P = 13 –

+1

मैं एक विशिष्ट डीबी पर निर्भर नहीं होना चाहता, इसलिए मैं एक वचरर का उपयोग करना चाहता हूं या सीएलओबी/टेक्स्ट कॉलम – Jochen

+0

आप वास्तव में उपयोगकर्ता टाइप का उपयोग कर सकते हैं। एक उत्तर जोड़ा गया। – NikolaB

उत्तर

3

आप कस्टम प्रकार बना सकते हैं:

import com.fasterxml.jackson.core.type.TypeReference; 
import com.fasterxml.jackson.databind.JavaType; 
import com.fasterxml.jackson.databind.ObjectMapper; 
import org.hibernate.usertype.ParameterizedType; 
import org.hibernate.usertype.UserType; 

public class JsonListType implements UserType, ParameterizedType { 

    public static final String LIST_TYPE = "LIST"; 
    private static final int[] SQL_TYPES = new int[]{Types.LONGVARCHAR}; 
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); 
    private static final TypeReference LIST_TYPE_REF = new TypeReference<List<?>>() {}; 

    private JavaType valueType = null; 
    private Class<?> classType = null; 

    @Override 
    public int[] sqlTypes() { 
     return SQL_TYPES; 
    } 

    @Override 
    public Class<?> returnedClass() { 
     return classType; 
    } 

    @Override 
    public boolean equals(Object x, Object y) throws HibernateException { 
     return Objects.equals(x, y); 
    } 

    @Override 
    public int hashCode(Object x) throws HibernateException { 
     return Objects.hashCode(x); 
    } 

    @Override 
    public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws HibernateException,  SQLException { 
     return nullSafeGet(rs, names, owner); 
    } 

    @Override 
    public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws HibernateException, SQLException { 
     nullSafeSet(st, value, index); 
    } 

    public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException { 
     String value = rs.getString(names[0]); 
     Object result = null; 
     if (valueType == null) { 
      throw new HibernateException("Value type not set."); 
     } 
     if (value != null && !value.equals("")) { 
      try { 
       result = OBJECT_MAPPER.readValue(value, valueType); 
      } catch (IOException e) { 
       throw new HibernateException("Exception deserializing value " + value, e); 
      } 
     } 
     return result; 
    } 

    public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException { 
     StringWriter sw = new StringWriter(); 
     if (value == null) { 
      st.setNull(index, Types.VARCHAR); 
     } else { 
      try { 
       OBJECT_MAPPER.writeValue(sw, value); 
       st.setString(index, sw.toString()); 
      } catch (IOException e) { 
       throw new HibernateException("Exception serializing value " + value, e); 
      } 
     } 
    } 

    @Override 
    public Object deepCopy(Object value) throws HibernateException { 
     if (value == null) { 
      return null; 
     } else if (valueType.isCollectionLikeType()) { 
      try { 
       Object newValue = value.getClass().newInstance(); 
       Collection newValueCollection = (Collection) newValue; 
       newValueCollection.addAll((Collection) value); 
       return newValueCollection; 
      } catch (InstantiationException e) { 
       throw new HibernateException("Failed to deep copy the collection-like value object.", e); 
      } catch (IllegalAccessException e) { 
       throw new HibernateException("Failed to deep copy the collection-like value object.", e); 
      } 
     } 
    } 

    @Override 
    public boolean isMutable() { 
     return true; 
    } 

    @Override 
    public Serializable disassemble(Object value) throws HibernateException { 
     return (Serializable) deepCopy(value); 
    } 

    @Override 
    public Object assemble(Serializable cached, Object owner) throws HibernateException { 
     return deepCopy(cached); 
    } 

    @Override 
    public Object replace(Object original, Object target, Object owner) throws HibernateException { 
     return deepCopy(original); 
    } 

    @Override 
    public void setParameterValues(Properties parameters) { 
     String type = parameters.getProperty("type"); 
     if (type.equals(LIST_TYPE)) { 
      if (parameters.getProperty("element") != null) { 
       try { 
        valueType = OBJECT_MAPPER.getTypeFactory().constructCollectionType(ArrayList.class, Class.forName(parameters.getProperty("element"))); 
       } catch (ClassNotFoundException e) { 
        throw new IllegalArgumentException("Type " + type + " is not a valid type."); 
       } 
      } else { 
       valueType = OBJECT_MAPPER.getTypeFactory().constructType(LIST_TYPE_REF); 
      } 
      classType = List.class; 
     } 
    } 

और यह पसंद का उपयोग करें:

@Type(type = "com.company.util.JsonListType", parameters = {@org.hibernate.annotations.Parameter(name = "type", value = "LIST"), @org.hibernate.annotations.Parameter(name = "element", value = "com.company.model.MyCustomClass")}) 
private List<MyCustomClass> myCustomClasses; 

यह समाधान डीबी विशिष्ट नहीं है और आप इसे आसानी से मानचित्र और कस्टम क्लोनेबल इकाइयों का समर्थन करने के लिए बढ़ा सकते हैं।

+0

कृपया हमेशा आयात जोड़ें। मैं यहां बैठा हूं कि ऑब्जेक्टमैपर और टाइप रेफरेंस के किस संस्करण का उपयोग करने की आवश्यकता है। – Sonny

+1

@ सोनी क्षमा करें, आयात जोड़ा, उम्मीद है कि यह मदद करता है। – NikolaB

+0

@NikolaB उपरोक्त एनोटेशन उसी तालिका में एक नया कॉलम बनाता है। क्या कोई नई तालिका बनाने के लिए एक एनोटेशन है और वास्तविक तालिका का विदेशी कुंजी संदर्भ है? – Aditya

0

मैं अपने आप को प्रयास नहीं किया है, लेकिन यहाँ एक ब्लॉग जो की चर्चा करते हुए लायक है ... https://dzone.com/articles/annotating-custom-types

कौन सा मूल रूप से एक कस्टम टिप्पणी जोड़ने के लिए आप का सुझाव है। उदाहरण के लिए एनोटेटेड क्लास इसे "एड्रेसजेसन पार्सर" कहते हैं, अपनी पता ऑब्जेक्ट को JSON (पार्सर का उपयोग करके) में परिवर्तित करना चाहिए और स्ट्रिंग के रूप में लौटा देना चाहिए। तुम भी एक एक पार्सर जो JSON स्ट्रिंग वापस पता वस्तु से रिवर्स करता है, होने के बारे में सोचना चाहिए ...