in core/optaplanner-core-impl/src/main/java/org/optaplanner/core/impl/domain/solution/cloner/gizmo/GizmoSolutionClonerImplementor.java [258:345]
private static void createCloneSolutionRun(ClassCreator classCreator, SolutionDescriptor solutionDescriptor,
Set<Class<?>> solutionClassSet,
Map<Class<?>, GizmoSolutionOrEntityDescriptor> memoizedSolutionOrEntityDescriptorMap,
SortedSet<Class<?>> deepClonedClassesSortedSet, Comparator<Class<?>> instanceOfComparator) {
Class<?> solutionClass = solutionDescriptor.getSolutionClass();
MethodCreator methodCreator =
classCreator.getMethodCreator("cloneSolutionRun", solutionClass, solutionClass, Map.class);
methodCreator.setModifiers(Modifier.STATIC | Modifier.PRIVATE);
ResultHandle thisObj = methodCreator.getMethodParam(0);
BranchResult solutionNullBranchResult = methodCreator.ifNull(thisObj);
BytecodeCreator solutionIsNullBranch = solutionNullBranchResult.trueBranch();
solutionIsNullBranch.returnValue(thisObj); // thisObj is null
BytecodeCreator solutionIsNotNullBranch = solutionNullBranchResult.falseBranch();
ResultHandle createdCloneMap = methodCreator.getMethodParam(1);
ResultHandle maybeClone = solutionIsNotNullBranch.invokeInterfaceMethod(
GET_METHOD, createdCloneMap, thisObj);
BranchResult hasCloneBranchResult = solutionIsNotNullBranch.ifNotNull(maybeClone);
BytecodeCreator hasCloneBranch = hasCloneBranchResult.trueBranch();
hasCloneBranch.returnValue(maybeClone);
BytecodeCreator noCloneBranch = hasCloneBranchResult.falseBranch();
List<Class<?>> sortedSolutionClassList = new ArrayList<>(solutionClassSet);
sortedSolutionClassList.sort(instanceOfComparator);
BytecodeCreator currentBranch = noCloneBranch;
ResultHandle thisObjClass =
currentBranch.invokeVirtualMethod(MethodDescriptor.ofMethod(Object.class, "getClass", Class.class), thisObj);
for (Class<?> solutionSubclass : sortedSolutionClassList) {
ResultHandle solutionSubclassResultHandle = currentBranch.loadClass(solutionSubclass);
ResultHandle isSubclass =
currentBranch.invokeVirtualMethod(EQUALS_METHOD, solutionSubclassResultHandle, thisObjClass);
BranchResult isSubclassBranchResult = currentBranch.ifTrue(isSubclass);
BytecodeCreator isSubclassBranch = isSubclassBranchResult.trueBranch();
GizmoSolutionOrEntityDescriptor solutionSubclassDescriptor =
memoizedSolutionOrEntityDescriptorMap.computeIfAbsent(solutionSubclass,
(key) -> new GizmoSolutionOrEntityDescriptor(solutionDescriptor, solutionSubclass));
ResultHandle clone = isSubclassBranch.newInstance(MethodDescriptor.ofConstructor(solutionSubclass));
isSubclassBranch.invokeInterfaceMethod(
MethodDescriptor.ofMethod(Map.class, "put", Object.class, Object.class, Object.class),
createdCloneMap, thisObj, clone);
for (GizmoMemberDescriptor shallowlyClonedField : solutionSubclassDescriptor.getShallowClonedMemberDescriptors()) {
writeShallowCloneInstructions(solutionSubclassDescriptor, isSubclassBranch, shallowlyClonedField, thisObj,
clone, createdCloneMap, deepClonedClassesSortedSet);
}
for (Field deeplyClonedField : solutionSubclassDescriptor.getDeepClonedFields()) {
GizmoMemberDescriptor gizmoMemberDescriptor =
solutionSubclassDescriptor.getMemberDescriptorForField(deeplyClonedField);
ResultHandle fieldValue = gizmoMemberDescriptor.readMemberValue(isSubclassBranch, thisObj);
AssignableResultHandle cloneValue = isSubclassBranch.createVariable(deeplyClonedField.getType());
writeDeepCloneInstructions(isSubclassBranch, solutionSubclassDescriptor, deeplyClonedField,
gizmoMemberDescriptor, fieldValue, cloneValue, createdCloneMap, deepClonedClassesSortedSet);
if (!gizmoMemberDescriptor.writeMemberValue(isSubclassBranch, clone, cloneValue)) {
throw new IllegalStateException("The member (" + gizmoMemberDescriptor.getName() + ") of class (" +
gizmoMemberDescriptor.getDeclaringClassName() +
") does not have a setter.");
}
}
isSubclassBranch.returnValue(clone);
currentBranch = isSubclassBranchResult.falseBranch();
}
ResultHandle errorBuilder = currentBranch.newInstance(MethodDescriptor.ofConstructor(StringBuilder.class, String.class),
currentBranch.load("Failed to create clone: encountered ("));
final MethodDescriptor APPEND =
MethodDescriptor.ofMethod(StringBuilder.class, "append", StringBuilder.class, Object.class);
currentBranch.invokeVirtualMethod(APPEND, errorBuilder, thisObjClass);
currentBranch.invokeVirtualMethod(APPEND, errorBuilder, currentBranch.load(") which is not a known subclass of " +
"the solution class (" + solutionDescriptor.getSolutionClass() + "). The known subclasses are " +
solutionClassSet.stream().map(Class::getName).collect(Collectors.joining(", ", "[", "]")) + "." +
"\nMaybe use DomainAccessType.REFLECTION?"));
ResultHandle errorMsg = currentBranch
.invokeVirtualMethod(MethodDescriptor.ofMethod(Object.class, "toString", String.class), errorBuilder);
ResultHandle error = currentBranch
.newInstance(MethodDescriptor.ofConstructor(IllegalArgumentException.class, String.class), errorMsg);
currentBranch.throwException(error);
}