private static void createCloneSolutionRun()

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);
    }