-->
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.  [ 10 posts ] 
Author Message
 Post subject: Make a EnumSet persistent
PostPosted: Sat Sep 15, 2007 12:30 pm 
Newbie

Joined: Sat Sep 15, 2007 12:11 pm
Posts: 3
Hi,

Hibernate version: 3.2.5 with mapping documents, not Annotations.

I have a User-class that includes a property that is an EnumSet of
authorities (=roles) granted to the user. This is for a learn-as-I-go
sandbox-application. So I have modelled this in POJO-manner without
taking Hibernate into account:

Code:
  public enum Authority {
    ROLE_ANONYMOUS,
    ROLE_USER,
    ROLE_ADMIN
  }

  public class User implements Serializable {

    private Long id;
    private String userName;
    private String password;
    private Set<Authority> authorities = EnumSet.noneOf(Authority.class);
   
    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public void setAuthorities(Set<Authority> authorities) {
        this.authorities = authorities;
    }
   
    public Set<Authority> getAuthorities() {
        return this.authorities;
    }
  }


What options do I have to make the property authorities persistent?

I can only think of making Authority a standard class, mapping that (just
ID and Name, propably), and creating a many-to-many-mapping. I don't
like that because the possible selection of Authorities is really defined by
the code and not from the DB, so I don't need and want anybody adding
or removing authorities. I also like to refer to the Authorities in code,
using "ROLE_USER", and not having to load them in any way.

Could I make Hibernate persist the collection as string like
"ROLE_USER, ROLE_ADMIN" or just "ROLE_USER" for non-admin? It is
unlikely that there will ever be more than a handful of them.

Or as a bitmasked INTEGER? I'd put up with it not being very readable
in the DB if it feels good in the code that uses the class.

Or should I drop my Set altogether and make the roles separate boolean
properties, mapping them to separate columns in the USER-Table?

As I said: This is a learning project, so I welcome discussion of the topic
and am willing to do some work to arrive at an elegant solution.

Thank you all for reading this and

Bye, MM


Top
 Profile  
 
 Post subject:
PostPosted: Sat Sep 15, 2007 4:41 pm 
Expert
Expert

Joined: Tue Nov 23, 2004 7:00 pm
Posts: 570
Location: mostly Frankfurt Germany
You might consider to create a custom type, which converts your set into a flat value and back.
Have a look in the Hibernate downloads. You can find examples in the test directory.
Alternatively you might use CollectionOfElements but I don't know, if they work with this kind of object. Just try.

_________________
Best Regards
Sebastian
---
Training for Hibernate and Java Persistence
Tutorials for Hibernate, Spring, EJB, JSF...
eBook: Hibernate 3 - DeveloperGuide
Paper book: Hibernate 3 - Das Praxisbuch
http://www.laliluna.de


Top
 Profile  
 
 Post subject:
PostPosted: Sat Sep 15, 2007 6:16 pm 
Beginner
Beginner

Joined: Thu Jun 17, 2004 11:25 pm
Posts: 21
Location: Los Angeles
At the most basic level, Hibernate collections are mapped according to the principles of normalization in relational database theory. That is to say, a collection, being composed of a variable number of entities, is stored in a different table than the thing that "owns" the collection. This is because the basic premise of Hibernate is that one entity maps to one row in a database. So in theory, the many-to-many mapping is the "correct" approach.

That doesn't mean you should do it that way. However, none of your proposed approaches solves the problem you identified of having anyone add or remove Authorities (which I'll also call Roles). That's kind of a red herring. If someone can update the database, they can change the value of the Authorities column or relationship no matter what you do. They can add a new boolean columns, they can stuff new values into your bit mapped or string fields, etc. Besides which, the ability to easily add and remove Authorities or Roles is a desirable feature of an authorization system; it's a good thing, not a bad thing.

In situations like this in practice I've used a bit-mapped integer. This is a bad habit I got from learning to write hardware device drivers. I would discourage you from following this path as bit-mapped integers are hard to read, hard to maintain, and don't buy you very much. You need to have a good justification for using them.

The current philosophy of programming is that the critical resource is no longer CPU cycles or memory or disk storage but rather programmer time. The priority is in making things quick and easy for the programmer to write and maintain and for other programmers to quickly understand and modify if necessary. Your solution of persisting Authorities as concatenated string values is closer to the Java philosophy in that it keeps things human readable while conceptionallly being similar to a bitmap (and having another, more challenging IMHO, set of implementation problems).

You could map the roles as booleans, but this means a schema change and a lot of code changes whenever you add a role. Plus, it makes for an inelegant implementation of isUserInRole() aka doesUserHaveThisAuthority().

Which brings us back to the many-to-many mapping. It's really the best solution under this philosophy. It makes it easy to add Authorities to the system, which is a very likely change to be required of a real-world system. It leverages the existing Hibernate code without you having to invent something new, and it accurately reflects what you want to do. It is in many ways an elegant solution, just not necessarily the most CPU time and memory and disk space efficient.

If you're just playing around and learning, though, I suggest you go through and do it each of the 4 ways you considered and see what it's like to put them into practice. Write isUserInRole() for each one, and then after you've got the example finished, add a new role and see how long it takes you. (Here's a hint: with Roles as entities and many-to-many mappings, you can add a Role without touching the code. All you need to do is update the database. Which is really a good thing, not a bad thing as you initially thought.)

=Jeremy=

P.S. If you found this post helpful, please consider giving me a credit by clicking "Yes" on the line below.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Sep 15, 2007 9:33 pm 
Regular
Regular

Joined: Fri Jan 20, 2006 7:45 pm
Posts: 97
Location: San Antonio, TX
Quote:
In situations like this in practice I've used a bit-mapped integer. This is a bad habit I got from learning to write hardware device drivers. I would discourage you from following this path as bit-mapped integers are hard to read, hard to maintain, and don't buy you very much. You need to have a good justification for using them.


Well...I wouldn't call it a BAD habit, just a different one. I mean, why store a 100+ bytes in the database when one would do?
:)
An alternate approach to this would be using the [flag] attribute on your enum and then storing the numeric value in the DB. It's a little more readable in your code, but developers who weren't birthed out of the C community sometimes get confused by the bit-wise arithmetic used to check flags.

Of course for something like a user role...from an OO standpoint I would have the role as an object/entity (agree completely with jgro). This way I associate permission sets with roles, etc. I could then extend the roles set at will, share permissions with different roles, etc.

_________________
Dum spiro, spero
-------------------------------
Rate my post if it helps...


Top
 Profile  
 
 Post subject:
PostPosted: Sat Sep 15, 2007 9:40 pm 
Newbie

Joined: Wed Jun 21, 2006 2:25 pm
Posts: 15
You may find your answer here
http://www.hibernate.org/272.html
This page talks about how to deal with enums.

Thanks
anand raman


Top
 Profile  
 
 Post subject:
PostPosted: Sat Sep 15, 2007 11:57 pm 
Beginner
Beginner

Joined: Thu Jun 17, 2004 11:25 pm
Posts: 21
Location: Los Angeles
jlockwood wrote:
jgro wrote:
In situations like this in practice I've used a bit-mapped integer. This is a bad habit I got from learning to write hardware device drivers. I would discourage you from following this path as bit-mapped integers are hard to read, hard to maintain, and don't buy you very much. You need to have a good justification for using them.

Well...I wouldn't call it a BAD habit, just a different one. I mean, why store a 100+ bytes in the database when one would do?


It's a bad habit not always a bad practice. As a habit, I think you should start off with something easy to write and easy to understand and then later worry about optimizing it if it turns out to be too inefficient. If I save 100 bytes on 10,000,000 records, I've saved a GB of disk space. Last time I checked, a GB of disk space cost $0.25. Certainly not worth a minute of my time. My bit mapping got started back when you couldn't buy a disk drive that held 1 GB.

=Jeremy=


Top
 Profile  
 
 Post subject:
PostPosted: Sun Sep 16, 2007 6:15 am 
Regular
Regular

Joined: Fri Jan 20, 2006 7:45 pm
Posts: 97
Location: San Antonio, TX
Yeah, you're right, I came off more serious than I meant to be (was more tounge in cheek). My peers broke me of the habit a while back, along with returning int return codes from functions.

Maintainability is most important and simplicity is one of the agile core values.


BTW, I still have a working IMB PC (but my 20MB MFM drive for that died).

_________________
Dum spiro, spero
-------------------------------
Rate my post if it helps...


Top
 Profile  
 
 Post subject:
PostPosted: Tue Sep 18, 2007 5:15 am 
Newbie

Joined: Sat Sep 15, 2007 12:11 pm
Posts: 3
diduknow wrote:
http://www.hibernate.org/272.html
This page talks about how to deal with enums.


Yes, but Enums only, not Collections of Enums.

Ciao, MM


Top
 Profile  
 
 Post subject:
PostPosted: Tue Sep 18, 2007 5:30 am 
Newbie

Joined: Sat Sep 15, 2007 12:11 pm
Posts: 3
Quote:
That doesn't mean you should do it that way. However, none of
your proposed approaches solves the problem you identified of having
anyone add or remove Authorities (which I'll also call Roles).


The EnumSet does solve that problem (I think).

Anyone with access to the database can of course grant or revoke
authorities from users, but not add or remove the Authority itself.

Quote:
They can add a new boolean columns, they can stuff new values
into your bit mapped or string fields, etc.


Yes, they could. But that would not change the Enum, there would be
additional data, or possibly broken data (in case of
stuff-it-all-into-one-field approaches).

But I think I get your point.

What bothers me the most with making Authorities full-fledged
hibernate-mapped objects is that I can now refer to the (well-known)
Authorities by identifiers like ROLE_USER in my code without having
to first load anything from the DB.

I haven't actually spelled it out in code yet and may be totally off-track.
Now with my Enum I can write:

if User.getAuthorities.contains(Authority.ROLE_USER) {
.. // grant access;
}

(I don't because in my toy-project I have also resorted to have the
security managed by Acegi Security, but that is a different matter).

If I did the same with a non-Enum Authority-class I would first have to
load the Authorities I know by name and store them somewhere. Possibly
in static fields of Authority. The syntax would then be the same.

I would have to make these static fields in Authority publicly writeable
because the class itself is Hibernate-agnostic of course and so
the instances loaded from the DB would have to be stuffed in from the
outside. Then I would need a check whether all that are needed are
still there.

Doable, of course. But not as elegant as the EnumSet. Or so I feel now.

Quote:
P.S. If you found this post helpful, please consider giving me a
credit by clicking "Yes" on the line below.


Yes, absolutly. Have done so.

Ciao, MM


Top
 Profile  
 
 Post subject: Re: Make a EnumSet persistent
PostPosted: Wed Sep 19, 2007 3:05 am 
Beginner
Beginner

Joined: Mon Aug 27, 2007 8:10 am
Posts: 37
MarianAldenhoevel wrote:
Hi,

Hibernate version: 3.2.5 with mapping documents, not Annotations.

I have a User-class that includes a property that is an EnumSet of
authorities (=roles) granted to the user. This is for a learn-as-I-go
sandbox-application. So I have modelled this in POJO-manner without
taking Hibernate into account:

Code:
  public enum Authority {
    ROLE_ANONYMOUS,
    ROLE_USER,
    ROLE_ADMIN
  }





I would go with this solution:
1. persist Authorities as integer, where each bit correspond to an enum value
2. implement conversion from Set<Authority> to integer and vice versa.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 10 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.