forked from TimefoldAI/timefold-solver
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: Add internal interface for planning cloning atypical types (Ti…
…mefoldAI#727) Sometimes, the domain model has atypical types for fields (for instance, UserList instead of List or ArrayList). The default planning cloner originally failed fast when the field cannot be assigned a typical value. Now, it checks if the collection implements the internal interface. If it does, it uses it to create an empty collection/map. This allows the default planning cloner to be used when the user has control over UserList.
- Loading branch information
1 parent
2773757
commit 019a13e
Showing
9 changed files
with
288 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
22 changes: 22 additions & 0 deletions
22
.../src/main/java/ai/timefold/solver/core/impl/domain/solution/cloner/PlanningCloneable.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package ai.timefold.solver.core.impl.domain.solution.cloner; | ||
|
||
/** | ||
* An internal interface used to construct new instances of an object | ||
* when there is no suitable constructor. | ||
* Used during planning cloning to create an "empty"/"blank" instance | ||
* whose fields/items will be set to the planning clone of the original's | ||
* fields/items. | ||
* | ||
* @param <T> The type of object being cloned. | ||
*/ | ||
public interface PlanningCloneable<T> { | ||
/** | ||
* Creates a new "empty"/"blank" instance. | ||
* If the {@link PlanningCloneable} is a {@link java.util.Collection} | ||
* or {@link java.util.Map}, the returned instance should be | ||
* empty and modifiable. | ||
* | ||
* @return never null, a new instance with the same type as the object being cloned. | ||
*/ | ||
T createNewInstance(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
26 changes: 26 additions & 0 deletions
26
...ld/solver/core/impl/testdata/domain/clone/planning_cloneable/PlanningCloneableEntity.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package ai.timefold.solver.core.impl.testdata.domain.clone.planning_cloneable; | ||
|
||
import ai.timefold.solver.core.api.domain.entity.PlanningEntity; | ||
import ai.timefold.solver.core.api.domain.variable.PlanningVariable; | ||
import ai.timefold.solver.core.impl.domain.solution.cloner.PlanningCloneable; | ||
import ai.timefold.solver.core.impl.testdata.domain.TestdataValue; | ||
|
||
@PlanningEntity | ||
public class PlanningCloneableEntity implements PlanningCloneable<PlanningCloneableEntity> { | ||
public String code; | ||
@PlanningVariable | ||
public TestdataValue value; | ||
|
||
public PlanningCloneableEntity(String code) { | ||
this.code = code; | ||
} | ||
|
||
public String getCode() { | ||
return code; | ||
} | ||
|
||
@Override | ||
public PlanningCloneableEntity createNewInstance() { | ||
return new PlanningCloneableEntity(code); | ||
} | ||
} |
45 changes: 45 additions & 0 deletions
45
...fold/solver/core/impl/testdata/domain/clone/planning_cloneable/PlanningCloneableList.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package ai.timefold.solver.core.impl.testdata.domain.clone.planning_cloneable; | ||
|
||
import java.util.AbstractList; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
import ai.timefold.solver.core.impl.domain.solution.cloner.PlanningCloneable; | ||
|
||
public class PlanningCloneableList<T> extends AbstractList<T> implements PlanningCloneable<PlanningCloneableList<T>> { | ||
private final List<T> backingList; | ||
|
||
public PlanningCloneableList() { | ||
this.backingList = new ArrayList<>(); | ||
} | ||
|
||
@Override | ||
public PlanningCloneableList<T> createNewInstance() { | ||
return new PlanningCloneableList<>(); | ||
} | ||
|
||
@Override | ||
public T get(int i) { | ||
return backingList.get(i); | ||
} | ||
|
||
@Override | ||
public T set(int i, T item) { | ||
return backingList.set(i, item); | ||
} | ||
|
||
@Override | ||
public void add(int i, T item) { | ||
backingList.add(i, item); | ||
} | ||
|
||
@Override | ||
public T remove(int i) { | ||
return backingList.remove(i); | ||
} | ||
|
||
@Override | ||
public int size() { | ||
return backingList.size(); | ||
} | ||
} |
31 changes: 31 additions & 0 deletions
31
...efold/solver/core/impl/testdata/domain/clone/planning_cloneable/PlanningCloneableMap.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package ai.timefold.solver.core.impl.testdata.domain.clone.planning_cloneable; | ||
|
||
import java.util.AbstractMap; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
import java.util.Set; | ||
|
||
import ai.timefold.solver.core.impl.domain.solution.cloner.PlanningCloneable; | ||
|
||
public class PlanningCloneableMap<K, V> extends AbstractMap<K, V> implements PlanningCloneable<PlanningCloneableMap<K, V>> { | ||
private final Map<K, V> backingMap; | ||
|
||
public PlanningCloneableMap() { | ||
this.backingMap = new HashMap<>(); | ||
} | ||
|
||
@Override | ||
public PlanningCloneableMap<K, V> createNewInstance() { | ||
return new PlanningCloneableMap<>(); | ||
} | ||
|
||
@Override | ||
public Set<Entry<K, V>> entrySet() { | ||
return backingMap.entrySet(); | ||
} | ||
|
||
@Override | ||
public V put(K key, V value) { | ||
return backingMap.put(key, value); | ||
} | ||
} |
Oops, something went wrong.