I guess
Code:
Invention extends Necessity
or something like that.
Hearing no response to my question, and reading in the specs that what I wanted to do seemingly isn't possible, I was left with either updating the whole system to match my component's method-based annotation or, if possible, making my component use field-based annotations.
I eventually did the latter, with a pattern that might help others stuck like I was.
So if you're interested in a means of simulating method-based JPA annotations with actual field-based ones, read on. Otherwise, scram!
I had already made my JPA-enabled POJO a wrapper around the intrinsic business object POJO, so that not all clients of the business library needed to include the Hibernate libraries in order to compile. There was in my case a single business method,
Code:
public void setSomething(int newVal) {}
which performed significantly more logic than simply setting a single int field. This was one of the fields that needed to be persisted on save. I added a
Code:
@Column(...) private int something;
field. I set this field appropriately in each constructor from my delegated business POJO, and I set it whenever the corresponding field in the delegate is set.
Then, and here is the strange thing, in the beginning of every method that accesses the object's state, including all getXxx() methods, toString(), and others, I call the method
Code:
private void initValues() {
if (something != delegate.getSomething()) {
setSomething(something);
}
// ...
}
In this way I ensure that the mutation of a private field properly updates the true model.
Of course this is simplified. There is more than one such property, and there are additional complexities in some of my delegation. But this is the gist.
Note that this technique leads to the possibility that introspection (say in a debugger) could show this object in a state that violates a class invariant. This should not cause any problems, but the user is cautioned about believing what the debugger says about the state of this object. Running programs, unless they are using reflection to access this, will never notice.
Although I've managed to get this working, I would love to hear of any better techniques.
-- Scott