-->
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.  [ 9 posts ] 
Author Message
 Post subject: UserType with non-public constructor?
PostPosted: Mon Nov 29, 2004 2:58 pm 
Beginner
Beginner

Joined: Mon Nov 29, 2004 2:26 pm
Posts: 28
Hi,

I would like to persist a typesafe enumeration in Hibernate without breaking the pattern, so I'd like to keep my constructors private if possible.

I was under the belief that Hibernate would support constructing objects with private and protected constructors via the Reflection API (when given sufficient security permissions of course) as it does for properties.

However, the constructor for CustomType uses Class.newInstance() to instantiate my persistent enum, which yields an IllegalAccessException (context shown in code snippet below).

Is there a reason why CustomType does not use ReflectHelper.getDefaultConstructor(Class clazz) to "safely" get a reference to the class's default constructor and then instantiate it? Doing this would cause AccessibleObject.setAccessible(true) to be called on my enumeration's private default constructor, which is exactly what I would like to happen

Code:
public class CustomType extends AbstractType {
   
   // ...
   
   public CustomType(Class userTypeClass) throws MappingException {
      
      name = userTypeClass.getName();

      try {
         userType = (UserType) userTypeClass.newInstance();
      }
      catch (InstantiationException ie) {
         throw new MappingException( "Cannot instantiate custom type: " + userTypeClass.getName() );
      }
      catch (IllegalAccessException iae) {

         // ******************
         // I get this error:
         // ******************
         throw new MappingException( "IllegalAccessException trying to instantiate custom type: " + userTypeClass.getName() );

      }
      catch (ClassCastException cce) {
         throw new MappingException( userTypeClass.getName() + " must implement net.sf.hibernate.UserType" );
      }
      types = userType.sqlTypes();

      if ( !Serializable.class.isAssignableFrom( userType.returnedClass() ) ) {
         LogFactory.getLog(CustomType.class).warn("custom type does not implement Serializable: " + userTypeClass);
      }
   }

   /...
}


Many thanks,
Luís

PS I'm referring to Hibernate 2.1.6


Top
 Profile  
 
 Post subject:
PostPosted: Mon Nov 29, 2004 3:16 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
what custom type do you have that need to not have a public constructor ?

custom types normally doesn't contain a single line of businesscode - only some glue code between your domain to hibernate.....so hard to find a usecase for it - please show me ?

and besides if you think you have a fix then please provide a patch instead of some halfbaked code ;)

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Tue Nov 30, 2004 6:49 am 
Beginner
Beginner

Joined: Mon Nov 29, 2004 2:26 pm
Posts: 28
I'd be happy to provide a fix, I'm just not sure if it's something that needs to be fixed or if it should behave this way by design.

I'm not using CustomType directly but this is where the exception crops up. I'm implementing UserType so I can persist a typesafe enumeration, as described in this link: UserType for persisting a Typesafe Enumeration with a VARCHAR column.

So I have a persistent Enum base class:

Code:
public abstract class Enum implements Serializable, Comparable, UserType {
    // default constructor for hibernate
    protected Enum() {
        super();
    }

    // implement the interfaces...
}


And a concrete typesafe enumeration:

Code:
public final class ProvisioningState extends Enum {
    // default constructor for hibernate
    private ProvisioningState() {
        super();
    }

    private ProvisioningState(int ordinal, String name) {
        super(ordinal, name);
    }

    public static final ProvisioningState FOO = new ProvisioningState(0, "Foo");
    public static final ProvisioningState BAR = new ProvisioningState(1, "Bar");
}


I would like the constructors to remain non-public to prevent a user of this class from instantiating it.

The (interesting part of the) stack trace I get:
    [java] 2004-11-30 10:29:15,495 ERROR (Configuration.java:255) - Could not compile the mapping documentnet.sf.hibernate.MappingException: IllegalAccessException trying to instantiate custom type: com.mycompany.ProvisioningState
    [java] at net.sf.hibernate.type.CustomType.<init>(CustomType.java:41)
    [java] at net.sf.hibernate.type.TypeFactory.heuristicType(TypeFactory.java:163)
    [java] at net.sf.hibernate.cfg.Binder.getTypeFromXML(Binder.java:933)
    [java] at net.sf.hibernate.cfg.Binder.bindSimpleValue(Binder.java:435)
    [java] at net.sf.hibernate.cfg.Binder.propertiesFromXML(Binder.java:1047)
    [java] at net.sf.hibernate.cfg.Binder.bindRootClass(Binder.java:362)
    [java] at net.sf.hibernate.cfg.Binder.bindRoot(Binder.java:1256)
    [java] at net.sf.hibernate.cfg.Configuration.add(Configuration.java:252)
    [java] at net.sf.hibernate.cfg.Configuration.addInputStream(Configuration.java:288)
    [java] at net.sf.hibernate.cfg.Configuration.addResource(Configuration.java:336)
    [java] at net.sf.hibernate.cfg.Configuration.doConfigure(Configuration.java:1013)
    [java] at net.sf.hibernate.cfg.Configuration.doConfigure(Configuration.java:969)
    [java] at net.sf.hibernate.cfg.Configuration.configure(Configuration.java:931)


Top
 Profile  
 
 Post subject:
PostPosted: Tue Nov 30, 2004 6:57 am 
Expert
Expert

Joined: Tue Oct 05, 2004 9:45 am
Posts: 263
hi,

just a remark (perhaps i'm mixing something) ...

The UserType should not be your "Enum" or "ProvisioningState" ..
the UserType can 'only' handle it ...!

gtx
curio


Top
 Profile  
 
 Post subject:
PostPosted: Tue Nov 30, 2004 6:59 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
you are not following the example ;)

The business type (in your case Enum and Rating - btw. Enum is a reaally bad name to use as enum is a keyword in 1.5) should not implement/extends UserType.

You should have an additional EnumUserType class, so you remove the hibernate dependency from your code - and thus also don't have much need to not having a default constructor on the UserType.

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Tue Nov 30, 2004 7:22 am 
Beginner
Beginner

Joined: Mon Nov 29, 2004 2:26 pm
Posts: 28
max wrote:
btw. Enum is a reaally bad name to use as enum is a keyword in 1.5

Oops. Duly noted, thanks. :)


max wrote:
You should have an additional EnumUserType class, so you remove the hibernate dependency from your code - and thus also don't have much need to not having a default constructor on the UserType.


Sorry, the example that was followed was actually UserType for persisting Typesafe Enumerations with a single class. Even with the first example, however, I would argue that the constructor should be private in order to prevent instantiation of this class by a user.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Nov 30, 2004 7:27 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
well - it cannot come out of sync nor be used to much ;)

...but again, you are welcoem to provide a patch if you would like to have the opportunity to have it use the reflection trick.

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Tue Nov 30, 2004 7:29 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
and regarding that page - it is a bad example ;(

i'll make a comment on that page about it.

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Tue Nov 30, 2004 8:13 am 
Beginner
Beginner

Joined: Mon Nov 29, 2004 2:26 pm
Posts: 28
You're right, this solution creates an unwanted dependency on Hibernate instead of the "transparent persistency" that we would like. I will probably end up using the 2-class solution as it is conceptually nicer (although more work). ;)

For those who don't care about this dependency, however, I think ability to keep the constructor private would be useful, so I'll be submitting a patch.

Thanks again,
Luís


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