Cloning PlanningSolution in OptaPlanner - 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.

Related

DDD reusable functionality in an Entity/Aggregate

I have the following desing in DDD
Post Aggregate with
Body: HTML of the post
Banner entity with
Html: HTML of the banner
The Banner entity belongs to Post aggregate, so I want to create a method BodyWithBanners in the Post aggregate.
The point of this method will be to search into the HTML of the Post.Body and insert the HTML of the Banner.
So far, so good.
However I have intention of reuse this functionallity in abstract: "Insert some HTML inside another HTML". So I'm creating a diffent class for doing that: BannerReplacer
Here comes the problem, how should I invoke this new class?
Just create an instance inside the Post.BodyWithBanners method (breaking Dependency Injection)
Passing the BannerReplacer in the constructor of the Post aggregate (This can be a nightmare for creating Post instances)
Passing the BannerReplacer to the BodyWithBanners method (which implies the client using Post must handle the BannerReplacer)
I have chosen for now the first option, but I don't feel really confortable with it, I believe there must be a better way of doing this.
I have chosen for now the first option, but I don't feel really comfortable with it, I believe there must be a better way of doing this.
Much of the time, the first option is fine -- so you should practice being comfortable with it. That mostly means thinking more about what dependency injection is for, and having a clear picture in your mind for whether or not those forces are at play here.
If Banner is an entity, in the domain-driven-design sense, then it is probably something analogous to an in memory state machine. It's got a data structure that it manages, and some functions for changing that data structure, or answering interesting questions about that data structure, but it doesn't have I/O, database, network etc concerns.
That in turn suggests that you can run it the same way in all contexts - you don't need a bunch of substitute implementations to make it testable. You just instantiate one and call its methods.
If it runs the same way in all contexts, then it doesn't need configurable behavior. If you don't need to be able to configure the behavior, then you don't need dependency injection (because all copies of this entity will use (copies of) the same dependencies.
When you do have a configurable behavior, then the analysis is going to need to look at scope. If you need to be able to change that behavior from one invocation to the next, then the caller is going to need to know about it. If the behavior changes less frequently than that, then you can start looking into whether "constructor injection" makes sense.
You know that you intend to use a single BannerReplacer for a given method invocation, so you can immediately start with a method that looks like:
class Banner {
void doTheThing(arg, bannerReplacer) {
/* do the bannerReplacer thing */
}
}
Note that this signature has no dependency at all on the lifetime of the bannerReplacer. More particularly, the BannerReplacer might have a longer lifetime than Banner, or a shorter one. We only care that the lifetime is longer than the doTheThing method.
class Banner {
void doTheThing(arg) {
this.doTheThing(arg, new BannerReplacer())
}
// ...
}
Here, the caller doesn't need to know about BannerReplacer at all; we'll use a new copy of the default implementation every time. Caller's that care which implementation is used can pass in their own.
class Banner {
bannerReplacer = new BannerReplacer()
void doTheThing(arg) {
this.doTheThing(arg, this.bannerReplacer)
}
// ...
}
Same idea as before; we're just using an instance of the BannerReplacer with a longer lifetime.
class Banner {
Banner() {
this(new BannerReplacer())
}
Banner(bannerReplacer) {
this.bannerReplacer = bannerReplacer;
}
void doTheThing(arg) {
this.doTheThing(arg, this.bannerReplacer)
}
// ...
}
Same idea as before, but now we are allowing the "injection" of a default implementation that can outlive the given instance of Banner.
In the long term, the comfort comes from doing the analysis to understand the requirements of the current problem, so that you can choose the appropriate tool.

How to make the IDEA to recognize Spock's with() method?

I write on Groovy and use Spock framework for testing.
Some time ago, IDEA completely supports Spock.
When I've writing the code inside feature (test method) in where-block something like this:
with(someObject) {
intField == 1
...
}
IDEA correctly recognize the someObject and understand that intField is field of the object, also, it was offering me other fields of the object. So, inside Spock's with() block I've felt like inside any closure from DefaultGroovyMethods (with{}, each{}, find{}, etc.), but haven't need to use explicit it param.
(So, I's writing with(someObject) { intField == 1 } what is the same is someObject.with { assert it.intField == 1 }.
After a moment IDEA missed Spock's with() method support.
Now, it don't recognize the class of the parameter (ex. someObject) in think that it's object of Object class. Any fields inside closure don't be recognized. Explicit it usage didn't help.
After some IDEA update everything have repaired, but after reboot the problem has come back.
Does anybody know how to fix it??
I'm using the last version of the IDE - 2018.2
I just tested this out with 2018.1 and have the same issue as you. I didn't run the code but I am fairly certain that the code would be recognized and executed. This to me looks like a bug with Intellij, and it might be worth it to submit a bug report in their ticket tracking system.

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.

How to test a grails Criteria query?

first post here and hopefully relevant to many people.
I'm working on writing integration tests for a domain and on that domain I have a query using the withCriteria() method. I've searched all over the net and found many that give you detailed instructions on how to go about mocking a criteria query, but none on how to exactly test it.
I've tried mocking the domain using the mockDomain(domain,list) function, and setting up a domain for the test to use in the setUp() then calling the criteria and I get nothing.
I did a similar findBy here and got the results, but not exactly the ones I was looking for. I'm pretty sure it's not just my query, but the criteria, I've read in a few places criteria does not work in service testing. The query thus far has worked for me in the app, but I want to have some tests that I can refer to later in case my code base changes.
I've actually done as many have suggested and pulled out the code for the query and made it a static method in my domain so that I can mock it for the tests that use it, but now I'm stuck with how to actually test this part. Do I need to run the app and just do functional testing from that standpoint, or is there some way I could do this in the grails unit/integration testing. I'll post my query below.
static Attribute getDefinitionsUsingCriteria(List categoryNames, List types){
def definitions = Definition.withCriteria() {
and {
'in'('type', types)
if (categoryNames) {
categories {
'in'('name', categoryNames)
}
}
}
}
return definitions
}
Definitions has a string property type, and has a property categories of type Set that each element in this set has a String name property.
I'm still pretty new to grails and have been reading many reference books, and I'm surprised this is missing in all of the books I've read thus far. I hope this is something that is just a mistake on my part, and easily testable. I appreciate any help, and thanks for reading this long post.
JR.
One way: move the test from test/unit to test/integration folder. Criteria won't work in unit test (there's no Hibernate there), but will in integration. Never use mockDomain() in integration tests.
Note: don't make the method static - it only complicates testing.
Second way: In unit tests - use mockDomain(). Just rely on the fact that the logic is pretty straightforward, and unit-test everything except the method. Override it in setUp() like:
Definition.metaClass.getDefinitionsUsingCriteria = { List categoryNames, List types ->
delegate.findAll{ (it.type in types) &&
(it.categories.find { c -> c in categoryNames })
}
}
Grails 2.0.1 now has native #Mock for test criteria, but groupProperty is not implemented yet.
I wrote mock criteria plugin (with groupProperty)
https://github.com/fabiooshiro/plastic-criteria
it works in 1.3.7
Criteria are supported since grails 2.2. See "Unit Testing GORM" at What's new in Grails 2.2

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

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.