-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 12 posts ] 
Author Message
 Post subject: How to persist java.util.Locale?
PostPosted: Thu Nov 04, 2004 11:08 am 
Newbie

Joined: Thu Nov 04, 2004 10:38 am
Posts: 6
Is it possible to persist a 'java.util.Locale' object in a table?

For example LOCALE table:

Code:
CREATE TABLE `LOCALE` (
  `LOCALE` CHAR(2) NOT NULL PRIMARY KEY
);

I need this table, because I reference to it from locale-sensitive tables. And this table represent supported locales in my application.

My usage scenario is:
Code:
Locale someLocale = new Locale("ru");
List list = session.createCriteria(java.util.Locale.class).list();
if (list.contains(someLocale)) {
    // Locale is supported
} else {
    // Locale is not supported
}


Any ideas to implement <hibernate-mapping>?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 04, 2004 12:08 pm 
Hibernate Team
Hibernate Team

Joined: Tue Sep 09, 2003 2:10 pm
Posts: 3246
Location: Passau, Germany
Just use a custom UserType


Top
 Profile  
 
 Post subject:
PostPosted: Fri Nov 05, 2004 1:43 am 
Newbie

Joined: Thu Nov 04, 2004 10:38 am
Posts: 6
michael wrote:
Just use a custom UserType

If I use a custom UserType for the class java.util.Locale I can't persist it as an entity, for example:
Code:
Locale newSupportedLocale = new Locale("en");
session.save(newSupportedLocale);

So far I understood the hibernate-mapping UserType can only mapped as a property of an entity or in a collection, but what I want is to store java.util.Locale object in a table as an entity.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Nov 05, 2004 2:55 am 
Hibernate Team
Hibernate Team

Joined: Tue Sep 09, 2003 2:10 pm
Posts: 3246
Location: Passau, Germany
Why would you want to do that? IMHO thats not possible, at least not easily.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Nov 05, 2004 4:02 am 
Newbie

Joined: Thu Nov 04, 2004 10:38 am
Posts: 6
michael wrote:
Why would you want to do that? IMHO thats not possible, at least not easily.

My intention is to implement an object, that I only extend if I want to implement a multilingual entity. For example:
Code:
public class Multilingual extends Polyglot {
}

And here is the implementation:

DB SCHEMA:
Code:
-- My application support only language sensitive locales.
-- Otherwise use VARCHAR(255) instead of CHAR(2)
CREATE TABLE `LOCALE` (
  `LOCALE` CHAR(2) NOT NULL PRIMARY KEY
);

CREATE TABLE `POLYGLOT` (
  `POLYGLOT_ID` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY
);

CREATE TABLE `POLYGLOT_CONTENT` (
  `LOCALE` CHAR(2) NOT NULL,
  `POLYGLOT_ID` INTEGER UNSIGNED NOT NULL,
  `CONTENT_KEY` VARCHAR(255) NOT NULL,
  `CONTENT_VALUE` TEXT NOT NULL,
  PRIMARY KEY (`LOCALE`, `POLYGLOT_ID`, `CONTENT_KEY`),
  FOREIGN KEY `FK_POLYGLOT_CONTENT_LOCALE` (`LOCALE`)
    REFERENCES `LOCALE` (`LOCALE`)
    ON DELETE CASCADE
    ON UPDATE CASCADE,
  FOREIGN KEY `FK_POLYGLOT_CONTENT_POLYGLOT` (`POLYGLOT_ID`)
    REFERENCES `POLYGLOT` (`POLYGLOT_ID`)
    ON DELETE CASCADE
    ON UPDATE CASCADE
);

CREATE TABLE `MULTILINGUAL` (
  `MULTILINGUAL_ID` INTEGER UNSIGNED NOT NULL PRIMARY KEY,
  FOREIGN KEY `FK_MULTILINGUAL_POLYGLOT` (`MULTILINGUAL_ID`)
    REFERENCES `POLYGLOT` (`MULTILINGUAL_ID`)
    ON DELETE CASCADE
    ON UPDATE CASCADE
);

MAPPING:
Code:
<hibernate-mapping>
    <class name="Polyglot" table="POLYGLOT">
        <cache usage="transactional"/>
        <id access="field" name="polyglotID" type="integer" unsaved-value="null">
            <column name="POLYGLOT_ID" not-null="true"/>
            <generator class="native"/>
        </id>
        <map access="field" name="contents" table="POLYGLOT_CONTENT">
            <cache usage="transactional"/>
            <key column="POLYGLOT_ID"/>
            <composite-index class="PolyglotIndex">
                <key-property access="field" column="LOCALE" name="locale" type="locale"/>
                <key-property access="field" column="CONTENT_KEY" name="key" type="string"/>
            </composite-index>
            <element column="CONTENT_VALUE" type="string"/>
        </map>
        <!-- So I implement, for example, a multilingual object 'Multilingual' -->
        <joined-subclass name="Multilingual" table="MULTILINGUAL">
            <key column="MULTILINGUAL_ID"/>
        </joined-subclass>
    </class>
</hibernate-mapping>

JAVA:
Code:
import java.io.Serializable;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

public abstract class Polyglot implements Serializable {
   
    private int polyglotID;
    public Map contents = new HashMap();

    public boolean equals(Object object) {
        if (object == this) {
            return true;
        } else if (object instanceof Polyglot && object.hashCode() == hashCode()) {
            return true;
        } else {
            return false;
        }
    }
   
    public int hashCode() {
        return polyglotID;
    }
   
   
    public String getString(Locale locale, String key) {
        PolyglotIndex index = new PolyglotIndex(locale, key);
        String value = (String)contents.get(index);
        if (value == null) {
            return "";
        }
        return value;
    }
   
    public void setString(Locale locale, String key, String value) {
        PolyglotIndex index = new PolyglotIndex(locale, key);
        if (!value.equals(contents.get(index))) {
            contents.put(index, value);
        }
    }
   
    public void removeString(Locale locale, String key) {
        PolyglotIndex index = new PolyglotIndex(locale, key);
        contents.remove(index);
    }
}

class PolyglotIndex implements Serializable {
   
    private Locale locale;
    private String key;

    protected PolyglotIndex() {
    }
   
    protected PolyglotIndex(Locale locale, String key) {
        this.locale = locale;
        this.key = key;
    }
   
    public final boolean equals(Object object) {
        if (object == this) {
            return true;
        } else if (object instanceof PolyglotIndex && object.hashCode() == hashCode()) {
            return true;
        } else {
            return false;
        }
    }
   
    public final int hashCode() {
        int hash = locale == null ? 0 : locale.hashCode();
        hash = 31 * hash + (key == null ? 0 : key.hashCode());
        return hash;
    }
}


So I can now use my Multilingual object:
Code:
Multilingual someProduct = new Multilingual();
someProduct.setString(Locale.GERMAN, "NAME", "Buch");
someProduct.setString(Locale.ENGLISH, "NAME", "Book");
someProduct.setString(Locale.GERMAN, "TITLE", "Hibernate in Action");
someProduct.setString(Locale.ENGLISH, "TITLE", "Hibernate in Action");
someProduct.setString(Locale.GERMAN, "DESCRIPTION", "Sehr interessantes Buch!");
mayBeAProduct.setString(Locale.ENGLISH, "DESCRIPTION", "Very interesting book!");
session.save(someProduct);


CONCLUSION:
So long as the given Locale exists in the 'LOCALE' table it works fine. My intention is if a locale does not exists in the 'LOCALE' table to throw an exception by setting a string or if a superuser decide to add or remove a locale to make possible without implement an entity that holds the collection of supported locales to manage locales. Therefore I need a solution that persists 'java.util.Locale' object in the plain table 'LOCALE'.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Nov 05, 2004 4:08 am 
Senior
Senior

Joined: Sun Jan 04, 2004 2:46 pm
Posts: 147
Locale, I believe, can be described by the language and country codes use to instantiate it. You could therefore map the Locale to a string ( varchar in the db ).

UserType:

Code:
public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException
{
    String localeString = (String)Hibernate.STRING.nullSafeGet( rs, names[ 0 ] );

    String[] localeInfo = localeString.split( "," );

    return new Locale( localeInfo[ 0 ], localeInfo[ 1 ] );
}
   
public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException
{
    Locale locale = (Locale)value;

    String localeString = locale.getLanguage() + "," + locale.getCountry();

    Hibernate.STRING.nullSafeSet( st, localeString, index );
}


Not sure if , is allowed in language or country codes so this might need changing. Alternatively you could use a CompositeUserType and just have two columns.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Nov 05, 2004 4:24 am 
Newbie

Joined: Thu Nov 04, 2004 10:38 am
Posts: 6
Myk wrote:
Locale, I believe, can be described by the language and country codes use to instantiate it. You could therefore map the Locale to a string ( varchar in the db )...


ANNOTATION:
For that reason I have to refence the splitted 'java.util.Locale' attributes as a foreign key in other tables. The problem is that the reference key length in some databases is limited. Therefore the limitation to only language sensitive locales.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Nov 05, 2004 5:31 am 
Expert
Expert

Joined: Tue Oct 05, 2004 9:45 am
Posts: 263
well, using the locale (or part from it) as db-keys sounds for me a little bit as 'business-key' ... i think (as some others in this forum, too) that this is not the best way ...
why not use a generated id? then you haven't got any problems with that?

gtx
curio


Top
 Profile  
 
 Post subject:
PostPosted: Fri Nov 05, 2004 6:48 am 
Newbie

Joined: Thu Nov 04, 2004 10:38 am
Posts: 6
curio wrote:
well, using the locale (or part from it) as db-keys sounds for me a little bit as 'business-key' ... i think (as some others in this forum, too) that this is not the best way ...
why not use a generated id? then you haven't got any problems with that?

gtx
curio

I mean is it possible to map 'java.util.Locale' as an entity like this:
Code:
<hibernate-mapping>
    <class name="java.util.Locale" table="LOCALE">
        <id column="LOCALE" type="locale" unsaved-value="null">
            <generator class="assigned"/>
        </id>
    </class>
</hibernate-mapping>


Top
 Profile  
 
 Post subject:
PostPosted: Fri Nov 05, 2004 7:00 am 
Hibernate Team
Hibernate Team

Joined: Tue Sep 09, 2003 2:10 pm
Posts: 3246
Location: Passau, Germany
oktanix wrote:
[
I mean is it possible to map 'java.util.Locale' as an entity like this:


No.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Nov 05, 2004 8:13 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
hmm...you could probably do it with something like:

Code:
   <class name="java.util.Locale">
      <id type="long">
         <generator class="native"/>
      </id>
      <property name="language" access="field"/>
      <property name="country" access="field"/>
      <property name="variant" access="field"/>
   </class>


and let hibernate manage all the id stuff for ya.

But the main problem is acutally that java.util.Locale does not have a default constructor so hibernate cannot instantiate a new Locale for you.

For this we can use Interceptor.instantiate(), which allow you to control how objects get instantiated....BUT for some reason the basicpersister will not allow you to map this as it requires a default constructor....this is probably a bug....

So, at the moment it does not seem like we can persist java.util.Locale - but as other people has suggested, it is very easy to do as a custom usertype (but then you will be missing your "java.util.Locale"-list)

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Fri Nov 05, 2004 8:45 am 
Newbie

Joined: Thu Nov 04, 2004 10:38 am
Posts: 6
Thanks all very much, I appreciate all your ideas!


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 12 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.