Hibernate Books

All times are UTC - 5 hours [ DST ]



Post new topic Reply to topic  [ 4 posts ] 
Author Message
 Post subject: Per-Class Property Resolver?
PostPosted: Sat Aug 29, 2009 12:44 pm 
Newbie

Joined: Sat Aug 29, 2009 11:56 am
Posts: 3
Hi,

I feel like some one must have mentioned this (or I need to just look at the spec more) - but I do not see a straight forward way to easily constrain beans which have dynamic properties (like a bag of attributes) and provide overrides via a configuration file. In my use case I have a profile object with a set of base attributes and a set of extension attributes that the customer defines.

An extremely simple extension to the specification that would solve this problem would be to have a property binding SPI:

Code:
interface PropertyBinderFactory {
  PropertyBinding getBinding(Class beanCls, String propertyName);
}

interface PropertyBinding {
  Object getValue(Object instance);
}


You could then refine it further to allow programmatic adding of custom property resolvers by globally or by class:

Code:
ValidatorFactory factory = ...;
factory.setDefaultPropertyBinder(..);
factory.addPropertyBinder(new MyPropertyBinderFactory(), Mybean.class, MyOtherBean.class, ....);


Finally you could drive this down to the annotation on the specific class:

Code:
@PropertyBinder(MyPropertyBinderFactory.class)
public class MyBean {
...
}


I hope there is some other way to accomplish this, but given the above I could define constraints for the class in a configuration file and easily bind them to my Bag objects properties.


Top
 Profile  
 
 Post subject: Re: Per-Class Property Resolver?
PostPosted: Sat Aug 29, 2009 7:10 pm 
Newbie

Joined: Sat Aug 29, 2009 11:56 am
Posts: 3
Ok - so I tried to actually implement a JSR303 solution using the current API's and it while it is possible it has various limitations and is extremely ugly. If someone wants to post a better solution I would like to hear it. Since this must be a relatively common problem I want to share my solution for posterity.

Looking back at my original post, while something could be worked out annotation wise, the lack of a programatic API means for defining constraints (other than through XML) is a big hindrance to the 'bag-o-attributes' validation problem. In addition my post did not define a way to bind the constraint types to any sort of built-in attributes; so this whole idea would need a bit of work to flesh out properly.

Solution:

Looking at what is going on under the hood ; it is also clear that the Hibernate implementation is deeply bound to the idea of a concrete java bean so I quickly dismissed the idea of breaking the code from its binding to concrete classes (give my desire to solve this in one day :).

Instead, I looked into by breaking my dynamic bag-of-attributes class into two parts:
(1) Predefined attributes
(2) Dynamic (user-defined) attributes

Code:
public final class Attribute {
...
}


Predefined Attribute Bag Problem
Solving the first problem was fairly straight forward so long as you do not mind programatically validating each field yourself.

First off, you can define a 'Base' definitions class that contains the base attributes you wish to have along with their corresponding constraints:

Code:
   public static final class Base {
      
      private Base() {}
      
      @NotNull
      @Pattern(flags=Flag.CASE_INSENSITIVE,regexp="\\w{6,6}")
      @SuppressWarnings("unused")  private String key;   
      
      @NotNull
      @Pattern(flags=Flag.CASE_INSENSITIVE,regexp="\\w+ \\w+")
      @SuppressWarnings("unused")  private String displayName;
   
   }


Given the above you can then programatically validate your attributes doing something like this:

Code:
if (attribute.isBaseAttr())
   Set<ConstraintViolation<Base>> violations = validator.validateValue(Base.class, Names.DISPLAY_NAME, value);



Dynamic (user-defined) attributes problem

The second half of this, dynamic attributes are a bit more cumbersome, but work in the same way as the base attributes with the one caveat that you can only have a finite number of them.

First create an extensions class attribute holder given some large number of numbered fields:

Code:
public static class Ext {

                private static final int maxIndex = n;
      private int cindex = 0;   
      private Map<String,Integer> indexMap = ..;
      
                public String getExtAttrInternalId(Attribute extAttr) {      
                    Integer i = indexMap.get(extAttr.getName());
                    return "attribute" + i;
      }

      // attributes to bind values too
      @SuppressWarnings("unused") private Object attribute0;
      @SuppressWarnings("unused") private Object attribute1;
                ...
      @SuppressWarnings("unused") private Object attributeN;
      
}


Then to configure the above you would use the standard JSR303 file with a definition for your 'Ext' attributes <bean class="Attribute$Ext">..</bean>. However before passing this XML file to the configuration mapping, need to run through the configuration file:

Code:
<bean class="Attribute$Ext">
    <field name="foo"> ... </field>
    <field name="bar"> ... </field>
</bean>


And convert your extension attribute names into their corresponding 'indexed' attribute names:

Code:
<bean class="Attribute$Ext">
    <field name="attribute1"> ... </field>
    <field name="attribute2"> ... </field>
</bean>


Finally the extension attributes can be programatically validate similar to the base attributes above:

Code:
else if (attribute.isExtAttr())
   Set<ConstraintViolation<Base>> violations = validator.validateValue(Ext.class, Ext.instance().getExtAttrInternalId(attribute), value);


Minor code cleanliness improvements (as well as any further enhancements possibly needed for typing) can then be made by embedding the attribute holder class into the Attribute definition class, resulting in something like this:

Code:
Set<ConstraintViolation<Base>> violations = validator.validateValue(
        attribute.getValidationCls(), attribute.getValidationId(), value);


Top
 Profile  
 
 Post subject: Re: Per-Class Property Resolver?
PostPosted: Thu Sep 03, 2009 1:26 pm 
Newbie

Joined: Tue Jul 21, 2009 2:57 pm
Posts: 8
this might be trivializing what you're trying to accomplish, but couldn't you define object types that the user can add as independent objects.

address
email address
phone number

use @Valid on the collection of user-defined attributes and have the added property bag validate in that manner


Top
 Profile  
 
 Post subject: Re: Per-Class Property Resolver?
PostPosted: Thu Sep 03, 2009 1:54 pm 
Newbie

Joined: Sat Aug 29, 2009 11:56 am
Posts: 3
It does not quite work.

Here is my problem:
(1) My data structure is a glorified hash map
(2) Customers can have any combination of attributes in this hash map
(3) Many attributes will be of the same type, but they may have refinements off the base type
- For example a customer may want to have two types of phone numbers:
a. An external phone number (which could be represented by a phone number class)
b. An internal tie-line number (which is a refinement of the class)

Using your approach I could solve (1) by creating having an array method that got all of my attributes stuffed into type specific classes (address, phone number, etc) and then letting the validator using the type based validator for each. However this solution breaks down on (2) & (3) because I have to no ahead of time which types the customer wants to define refinements on and build a holder class that they can then override the validation rules on.

It seems like a simple use case, basically I am looking for a good way of validating a HashMap model bean. Thinks struts 1/validator DynaBean.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 4 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.