JPA <pre-persist> <pre-update> are being ignored but the #PrePersist and #PreUpdate work fine - orm

I ran into strange problem. I have the whole domain model defined in the orm.xml file. All my entities in my project are just simple POJOs (no jpa annotations at all). I want to save the last update and the insert timestamps of my entities and I've decided to use the "pre persist" and "pre update" like most of us. So I've defined a base entity class and let all my entities to extend it.
Strange is that the "pre persist" (and all others events) are being called only when I define them using annotations. When I define them in the orm.xml file instead - nothing happens, they are just ignored.
This works for me:
public abstract class BaseEntity {
private Timestamp insertTimestamp;
private Timestamp lastUpdateTimestamp;
#PrePersist
public void onPersist() {
...
}
#PreUpdate
public void onUpdate() {
...
}
}
But after removing annotations and switching to the xml nothing works anymore:
<mapped-superclass class="com.my.model.BaseEntity">
<pre-persist method-name="onPersist"/>
<pre-update method-name="onUpdate"/>
<post-load method-name="postLoad"/>
</mapped-superclass>
According to the JPA specification the above declarations in xml seem to be correct.
I have no idea where to dig for the problem.
I'm using EclipseLink 2.2.0 with H2 in the SE environment.
UPDATE:
Thanks for your answer. There are no errors in log/console to see. Events just seem being ignored.
As you thought is might be a bug because moving the methods and XML declarations from the superclass to the subclass solves the problem. It is not a desired solution for me as I want to have a global solution for all entities but moved me a bit forward.
I've sent the bug report to the EclipseLink guys :)
As you suggested I've tried with entity listener and it works for me. so I will stick to this solution. It even looks better then the solution with base entity class ;)
Thanks !

Your XML looks correct. Do any errors occur in the logs?
It could be a bug with MappedSuperClass and entity events.
Can you try setting the event on a subclass and see if it works?
If it does, then it is probably a bug, please log the bug in Eclipse Bugzilla.
Another workaround would be to use an entity listener.

Related

Serialize & Deserialize Unity3D MonoBehaviour script

Background: Classes that inherit from Monobehaviour can't be serialized.
Premise: A way to save the data (variables/fields and their values) of a MonoBehaviour script so it can be serialized, and deserialize it again and use this data to "fill in" a corresponding MonoBehaviour script's variable/field values.
Tried so far:
Having a serializable "wrapper/container" class that has the same fields as the MB script, but does not inherit from MB. Works nicely but every MV script needs it's own wrapper class and it's own wrapping function.
Serializing a List<FieldInfo> and fill it with the MB's fields... Works 30%;
The FieldInfos get added but are of the wrong Type, and
When deserialzing their values can't be accessed because an instance of a class is needed, but only a list is available
I feel like it can't be that hard but my Reflection skills and related are limited but seeing as saving/loading is a rather common feature I hope there is either someone who did it or someone who can point me in the right direction.
There is no easy way to serialize a MonoBehaviour using a BinaryFormatter built in .NET. There are a few options you can consider:
Using a Memento Patter. That is (more or less) what you have tried to achieve using a wrapper. Momento assumes a saving and restoring internal state of objects, so serialization is one of techniques.
Using Unity Serialization, by declaring the methods:
void Serialize(){}
void Deserialize(){}
In your MonoBehaviour script, so within the methods you will choose the properties/fields you want to serialize/deserialize.
There is an interesting framework, source code is on GitHub. It has a custom serialization framework that lets you serialize almost anything (not only monobehaviors). I have never used it, here is the forum page on Unity3d forum, I believe it's worth a look.
The answer to the question is: ScriptableObject. That's what they're for.
Put your variables in a ScriptableObject and Unity will handle the serialisation and give you a custom editor and other nice features. Recommended.

Cloning PlanningSolution in OptaPlanner

I am trying to solve timetabling problem with OptaPlanner but I am facing with problem which may be connected to cloning issue. Why when my planning entity collection method looks like that
#PlanningEntityCollectionProperty
public List<Lesson> getLessons() {
return getProject().getLessons();
}
I am getting error
java.lang.IllegalStateException: The solutionProperty (lessons) was not cloned as expected. The FieldAccessingSolutionCloner failed to recognize that property's field, probably because its field name is different.
but, when the method looks like
#PlanningEntityCollectionProperty
public List<Lesson> getLessons() {
if (lessons == null) {
lessons = getProject().getLessons();
}
return lessons;
}
everything is ok. What could be a reason? Why I am getting this error? Thanks for any help.
The generic cloner (to planning clone the best solution so the working solution can degrade) can't currently handle that first piece of code unfortunately.
There are 2 workarounds:
Implement a custom planning cloner (this is not simple, but it's explained in the docs section "4.3.7.6. Cloning a Solution".
Make the canonical field for lessons on that planning solution instead of Project (or refactor Project to implement Solution).
I wouldn't do it with that lazy initialization trick, as you might not always be able to guarantee that the getter has been called at least once before a planning clone happened.

NHibernate ISessionFactory that enables filters on OpenSession

I have been trying to create an ISessionFactory that has a list of filters as a property (so it can be specified in the XML configuration) and enables each of the filters whenever OpenSession() is called.
Unfortunately, I have been stymied at every turn. I've subclassed LocalSessionFactoryObject and SimpleDelegatingSessionFactory, mixed-and-matched every way I can think of, but there's always some syntax or run-time error that keeps it from working.
Can anyone give me an example of how to do this?
Thanks in advance.
[Update]
I've been asked to provide some code to illustrate my issue. I don't think that's really relevant to the question I'm asking, but I can elaborate:
I figured that to make sure the filters are enables whenever a new session is opened I'd have to have my own OpenSession method. It seemed the best way to do this was to subclass DelegatingSessionFactory, add the filter-list property and a method like this
public new ISession OpenSession()
{
var rtn = base.OpenSession();
foreach (var filter in filters)
rtn.EnableFilter(filter);
return rtn;
}
When I had Spring construct this as my ISessionFactory object, though, I got runtime errors about not having an exception translator. So, I figured I'm better off also subclassing LocalSessionFactoryObject and having it create an ISessionFactory of my new type with the filter list, rather than the default type. To do this I tried to override NewSessionFactory, but then I got a runtime error about not having a DbProvider defined, and when I tried to copy the code that handles this from LocalSessionFactoryObject I got a bunch of syntax errors because of the scope of some members...
In short, something that seemed like it should be simple -- and that in fact I rather expected many to have done before me -- turned in a coding safari. That's why I'm looking for someone who's already done it, or who at least understands the framework better than I do.
But do the filters need to be active always? If that is the case, then you should instead be using Where restrictions on the entity and/or collections.

"Abstract" methods in Yii Behaviors

I've been developing Yii application. And I'm wondering if it's possible to declare in model behavior some kind of "abstract" method. I know that it impossible to use directly following declaration:
abstract class FantasticBehavior extends CActiveRecordBehavior
{
public abstract function doSomethingFantastic();
}
because we need an instanse of this class. But also I know that Yii is full magic:)
I just want to make owner class to redeclare method from the behavior in obligatory order. Sure, I can use interface in addition to behavior but ...
Sorry if I've missed something to tell or something is not clear. Just ask and I'll try to explain what I mean.
Does anybody know something about this?
Thanks in advance.
UPD
I do understand that Yii is just PHP. It doesn't extend PHP. It is superstructure over it. And it doesn't have multiple inheritance since PHP doesn't.
I do understand behavior method can't be declared using abstract keyword. That is why I have written word "abstract" in quotes. But whatever. I know how behaviors work.
My question was if I can somehow oblige model(e.g. child of CActiveRecord) to declare some method.
For example, for my purposes I can do something like this:
class FantasticBehavior extends CActiveRecordBehavior
{
public function doFantasticThings()
{
$this->owner->prepareForFantastic();
// some code
}
}
Therefore, if I attach this behavior to my model and call method doFantasticThings this method will try to call method prepareForFantastic from model(owner). And if model doesn't have method prepareForFantastic declared new exception will be thrown because non-declared method are called.
Looks like I've answered my question myself :) What do you think about this?
UPD2
Yes, I know that if we don't call "abstract" method we won't know that it is not declared. It is a "charm" of interpretable languages :) We don't know if there is any error untill the code is run. Although, it would awesome if we could know about this as earlier as possible. For example, once instance of FantasticBehavior-class is attached to the model we could throw some child of CException to show what required methods must be declared in model. To achive this we can use something like listed below:
class FantasticBehavior extends CActiveRecordBehavior
{
public function attach($owner)
{
if(!/*$owner has declared methods list this->abstractMethods*/)
{
throw new CAbstractMethodNotDecalared('....');
}
parent::attach($owner);
}
public function abstractMethods()
{
return array('prepareForFantastic');
}
}
We need to override method attach from class CBehavior and check if "abstract" methods declared. Method abstractMethods is used to get list "abstract" method.
I don't know if there is attachBehavior event exists. If so, we can use it instead of overriding attach method.
Using this idea Base class for behaviors with "abstract" methods.
What do you think about this?
Maybe in future I'll make extention for Yii and become famous and rich? :))
This might be a little confusing to explain...
No, you cannot "attach" abstract methods to your CActiveRecord model using Yii's Behaviors. All Behavior's do is some clever overrides of __call(), __get() and __set() that give the illusion of multiple inheritance. (This is a good article about it). Behaviors do not provide true "multiple inheritance" support for core language features like abstract classes and interfaces. So if you attach that Behavior and add doSomethingFantastic() to your CActiveRecord class, you will still get an error.
You can, of course, declare abstract Behaviors that other Behaviors extend. So if you created another SuperFantasticBehavior Behavior that extended FantasticBehavior and implemented doSomethingFantastic() in it, you'll be fine. But it won't force you to declare the doSomethingFantastic() method in the CActiveRecord itself.
For a little deeper understanding: The way Yii's CComponent::_call() override is structured, when you call a method it will first see if any of the behaviors have that method, and call the method on the class itself.
Behavior's seem cool at first (mixins!), but sometimes it's just better to remember that PHP is a single class inheritance language and keep is simple. ;)
UPDATE:
The difference is that if you could use abstract methods in this case you'd see a "Class must implement method" error when you try to run your code (any code), and your IDE would highlight the error. This is more of a "compile" time error (not that it really exists in an interpreted lang like PHP).
Instead you'll see a "non-declared method" error (as you mention) at runtime. But you won't see it until that method is actually called, meaning you don't get that nice early warning like an abstract definition would give you. And if that method is never called, you won't get the error, which to means it's not really "obliging" the declaration in the same way an abstract def would.
Sorry if my initial answer was starting out at too basic of a level, I just wanted to be sure there was no misunderstanding. It's an interesting discussion, and made me think more about what an abstract declaration really does. Thanks, and happy coding! :)
Cheers

nhibernate virtual methods & resharper

I am curious how other Resharper users deal wih R#'s complaint about virtual methods it thinks are unused because it can't tell that NHIb will use them at runtime. I currently leave it as a hint, reluctantly, although am tempted to shut it off completely.
Cheers,
Berryl
example property or method where R# sees that a virtual member is never overriden
public virtual string Hello{ get { return "Hello"; } }
Have you tried adding the UsedImplicitlyAttribute?
EDIT: This works for me at the method level to suppress "Method 'Fink' is never used":
[UsedImplicitly]
private void Fink()
{
Console.WriteLine("Fink!");
}
Note that you can also go to ReSharper/Options/Code Inspection/Settings and add to the Generated code regions. We do that for our CodeSmith templates.
You can safely keep them as hints.
It would be nice if R# allowed different settings per project, so you could disable it for your Domain classes only.
It's important to remember R# is just a tool; don't let it do the thinking for you. If an inspection is unhelpful most of the time, just disable it (or leave it as a hint, like you did)