Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I would like to know if there is a way —maybe with AOP— to extend table/entity definitions so that I can add functionality across the board that requires persistence.

Let me explain what I want to do with a concrete example. Let's suppose we have a simple ecommerce system:

  • User
    • id
    • name
    • password
  • Item
    • id
    • name
    • price
    • stock
  • ShoppingCart
    • id
    • user_id
  • ShoppingCartItems
    • id
    • shopping_cart_id
    • item_id
  • Order
    • id
    • shopping_cart_id
  • Purchase
    • id
    • order_id
    • invoice_number

Now, let's suppose that we think:

hey, wouldn't it be great if we could add a field to timestamp all entities?

You would now know things like:

  • When a User registered
  • When an item was created
  • When a shopping cart was created
  • When an item was added to a shopping cart
  • When an order was placed
  • When was the order was processed and paid

Now you have another great idea:

What if there was a status field for all entities so I could soft-delete or archive items, etc.

And yet another idea:

What if there was a text field called meta to serialize unimportant data, but that could help adding functionality without painful database modifications.

There are solutions I can think of (meeting relational integrity requirement):

  1. Of course, you would need to go back, change your tables, modify your implementations so that when creating/updated you save the timestamp of then operation, same for status, same for meta.

  2. And a somewhat convoluted but very modular way. Create some sort of plugin, that creates a table that handles the field, and 1 pivot for each entity. And through events, associate the extended data to the existing entities accordingly.

But what if... you could just tell Hibernate to extend the table definitions programmatically at run time, and add the persistence behaviors through something like AOP to inject functionality.

I actually did the first thing (programmatically extending table definitions outside existing implementation) in Doctrine successfully once, but I'm just starting to learn Hibernate. OTOH, I'm just starting to learn Spring and know the basics on AOP, so at least in my mind it is feasible to intercept Hibernate's configuration process where it understands table definitions.

So, is this possible with Spring and Hibernate?, how?, can you provide an example?

Addendum: The problem is that I need to do this more than once, and it could come from anywhere. AOP was my answer to the multiple inheritance problem since extending classes would be too constrained, however, in the past I did it with Events and worked just as fine... IIRC the problem is that I had to hack Doctrine in order to do this to fire an event at the time between when the model description was being converted from configuration files into actual models.

AOP is not a must, just an idea for an approach if such an event or dependency injection mechanism is not already in place. Another approach could be mixins, but I come back to AOP as probably the most elegant solution.

The main requirement here is to not modify the original model's code.

Disclaimer: I'm not an expert on AOP but I'm fairly familiar to the concepts.

share|improve this question
2  
Not an answer to the specific question, but... I would take a different approach: have all your entity implementations extend a base class that has all the nifty functionality you want everywhere. For example, I manage create-date and modified-date in the base class (using JPA's PrePersist and PreUpdate annotations). AOP might be workable, but it will certainly be more complex and perplexing for anyone that needs to work with your code. Do you think you have requirements that cannot be satisfied via a common base class? – Rob Jan 4 '15 at 19:50
    
I agree with @Rob, I would say don't fall into a complexity trap when learning AOP. It looks cool, you can imagine it doing all these cool things, but the level of runtime complexity it adds, in addition to the new programming paradigm it introduces needs to be fully understood by anyone who ever looks at the code, and unfortunately... not everyone (or even most) of the people you'll work with will ever bother to learn such things – Alex Jan 4 '15 at 20:15
    
@Rob Please see my latest edit at the bottom. – dukeofgaming Jan 4 '15 at 23:57

As far as I can tell, what you are describing can be trivially implemented with an Embeddable class and not need of AOP.

@Embeddable
class Audit {
  Timestamp created;
  String createdBy;
  String updatedBy;
}

Then you can simply add your embeddable object within your entities.

@Entity
class Order {
   @Embedded
   Audit audit;
}

Using inheritance, you might just as well make this available for a set of entities:

@MappedSuperClass
class MotherOfAllEntities {
   @Embedded
   Audit audit;
}

@Entity
class ChildClass extends MotherOfAllEntities {
}

If the information being added is just audit information, as you seem to suggest in your post you may consider using something like Hibernate Envers which seems to be an implementation of what you're apparently suggesting with your question

@Entity
@Audited
class Order {
}

And Envers will make sure to store audit information about the entity in some other data structure.

Since Envers seem to be an implementation of something like what you want to do from scratch, you might just as well give it a look to their code and see how they did it, but yet again, if it is to implement what you described, to me it sounds like killing a fly with a bazooka.

share|improve this answer
    
Well, the main requirement is really to not modify the original implementation, any ideas on how to not need to do that? – dukeofgaming Jan 10 '15 at 19:46

Hibernate has events to which you can react using interceptors. Here's an incomplete list of events:

  • onDelete
  • onSave
  • instantiate
  • afterTransactionCompletion

Take a look at org.hibernate.Interceptor to see complete list of events to which you can react using Interceptor.

Simplified example of classical usage is auditting interceptor which sets "lastmodified":

public class AuditInterceptor extends EmptyInterceptor {
    @Override public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) throws CallbackException {
        if (entity instanceof AuditedEntity) {
            int index = findElementIndex(propertyNames, "dateModified");

            if (index >= 0) {
                state[index] = new Date();

                return true; // entity has been modified
            }
        }

        return false; // entity was not modified
    }

    private int findElementIndex(String[] propertyNames, String element) {
        for (int i = 0; i < propertyNames.length; i++) {
            if (element.equals(propertyNames[i])) {
                return i;
            }
        }

        return -1;
    }
}

Interceptors might not be enough for your needs. Luckily Hibernate's architecture is quite pluggable - most of the functionality consists of "Services", resp. service implementations which implement service roles (interfaces). You can override default implementations with your custom ones, or even add totally new services. But this might be more involved and might break in future versions of Hibernate. I'd recommend to stick with interceptors as much as possible.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.