• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

ModelDriven/Hibernate validation issue

 
Greenhorn
Posts: 13
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi all,

I want to use annotation validations and ModelDriven for an action working with a Hibernate entity for the model. But I'd prefer not to put Struts 2 annotations in the entity class, but in the action instead and keep them in the web tier. Does this mean I just add the appropriate setters in the action (which update the model), then annotate these setters? Anybody got an example of this?

I know adding extra setters in the action goes against the DRY principle, since these setters already exist in the Hibernante entity, but there seems to be well known problems with ModelDriven where, when validation fails for a setter, previous setters may have passed and update the Hibernate entity, thus causing it to be persisted when the session is flushed. Also the fact that adding Struts 2 annotations (web tier) to Hibernate entities (business tier) just sounds nasty.

Any advice would be much appreciated.

Cheers
 
Ranch Hand
Posts: 194
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Sounds like you found my old thread...

Yeah, I've decided that Model Driven just doesn't work if you're using OpenEntityManagerInView or OpenSessionInView.

For now I've given up on ModelDriven. Though I might look into writing a custom OEMIV, since one of the proponents claims that if you don't start a transaction nothing bad can happen. I looked and didn't find the OEMIV opening a transaction, but perhaps I didn't look closely enough.

I terms of, if I could use Model Driven.... I would actually be more willing to use the Struts 2 annotations in my Model Classes than the Hibernate/JPA annotations, long term. During early development I'll use the JPA annotations, but I feel that having persistence concerns clutter up the domain model is wrong (TM). And so after the early stages I plan to move to XML mapping.... Especially when the mapping gets more complicated than a single annotation with one or two arguments (ie the stacks of like 5 annotations, some JPA some hibernate overrides, is just plain gross)

Validation on the other hand, to me is a domain issue, and is close to the notions of the Representation Invariant. Now yes, I'd prefer that it used a different package, etc to avoid looking like a dependency on the controller/view tier, but to me that is a lesser code smell than the extra setters on the view.

Though, if I could make the choice.... I think I would still choose to avoid Model Driven and prefer action-based validation, so the issue is moot to me.
 
Hugh O'Donnell
Greenhorn
Posts: 13
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Eric,

Thanks for the reply, much appreciated. Yes, I'm sure it must have been your thread I came across :-) I do agree about the domain validation and the package naming. I was aiming to use the extra setters on the action as a kind of firewall between the form data and the hibernate object. Am I right in thinking that when using ModelDriven, the model is updated with every successful field validation? This seems wrong, as if the first field passes, the Hibernate entity is updated (marked as dirty), then the rest of the fields fail, but leaving you with an altered Hibernate entity which may cause database activity. I'd rather make sure all validation passes, before the Hibernate entity is even touched.

Regards,

Hugh
 
Eric Nielsen
Ranch Hand
Posts: 194
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Yes, in ModelDriven, any incoming parameter that is "settable" on the model will be set, regardless of whether its valid or not, which can easily leave an object in a dirty and invalid state. (By settable I mean -- is type compatible after any type conversion that is invoked).

There are two constraining requirements:
a) validation should be atomic, domain objects should not be left in an invalid state
b) user interface guidelines tend to require re-presenting the invalid data for correction rather than throwing it away.

Creating a validation system, that can work with an unmodified model object backing the form, is going to be extremely hard.

In my opinion a solution would start to look like
a) Something like the current struts 2 validations/model driven
b) a set of two reflection generated hash maps
--1) <String,String> (fieldName -> rawValue)
--2) <String,Object> (fieldName -> typeConverted value using the model object to determine field type)
c) some proxy-type object that wraps all of these together and is exposed to the Action and View

Now you can potentially create a system where you can run the validation against the b.2. values and on success push them atomicly into a.

If it fails, a. isn't updated, but you still have access to either the raw or type-converted inputs to redisplay. Of course some XSS protection might be needed to protect against the redisplay of b.1/b.2 values in certain cases.
 
Hugh O'Donnell
Greenhorn
Posts: 13
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Eric,

I dont' see why they couldn't have done it in two passes, one to validate the fields, and another pass when all validation passes to apply the updated values. Hopefully they can sort it in the near future. As for me, I think I'll abandon ModelDriven for now, add the extra setters in the Action, and when validation passes, I'll update the Hibernate entity manually in the execute() method. I'm going to have to do this anyway to resolve dependencies from form dropdowns with other Hibernate tables.

E.g. updating an Account model object but the AccountType is determined by a dropdown.

public String execute() {
// Resolve AccounType from the selected dropdown
AccountType accountType = accountService.findAccountTypeById(accountTypeId);
account.setAccountType(accountType);

// set account fields from form..
account.setName(name);
account.setSurname(surname);
accountService.saveOrUpdate(account);
}

Thanks again,

Hugh
 
Eric Nielsen
Ranch Hand
Posts: 194
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Not really related, but one trick that I've been using and liking so far (but I'm not sure I won't run into problems later...) is using a custom type converter to do those lookups. Ie my code would look more like


The custom type converter handles the "rehydration" of the primary key to a full AccountType.
 
Hugh O'Donnell
Greenhorn
Posts: 13
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Man, that's pretty sweet. I wouldn't have thought of that. But it's no biggie for me to do it that way I am. Can I ask how does your converter class access the AccountService? The converter class is mentioned in the @TypeConversion annotation, but I thought a new converter would be instantiated every time? How does it handle the injection of beans from the Spring application context?

Regards,
Hugh
 
Eric Nielsen
Ranch Hand
Posts: 194
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Here's a sample converter class for my app:


I haven't found a good way to make it general, but they only differ in the class,service name.

The services are all declared in the struts-beans.xml file. The converters are not. It appears that the default autowiring rules take care of the rest.

I'm still surprised that its worked for me. I knew that the incoming direction would work, but i had some concern that the outgoing direction wouldn't behave right.

In many ways this is like the "Stripernate" extension to Stripes for rehydrating objects on id....

One of my goals was to get rid of all the "extraneous" services/daos/repositories in the actions, ie only need the ones that the actual operation of the action requires, not the myriad ones needed to rebuild the object graph. so far its been good... I'm also trying to migrate from the DAO approach to a repository approach... as this happens most of the current "services" will get replaced with the bare EntityManager -- I'm considering that the rehydration of the objects takes place outside of the application or domain tiers and therefore doesn't, by itself, justify stand-alone services that aren't used elsewhere.
 
With a little knowledge, a cast iron skillet is non-stick and lasts a lifetime.
reply
    Bookmark Topic Watch Topic
  • New Topic