Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2022-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.instancio.internal;
import org.instancio.exception.InstancioException;
import org.instancio.generator.AfterGenerate;
import org.instancio.generator.Hints;
import org.instancio.generator.hints.ArrayHint;
import org.instancio.generator.hints.CollectionHint;
import org.instancio.generator.hints.MapHint;
import org.instancio.internal.assigners.Assigner;
import org.instancio.internal.assigners.AssignerImpl;
import org.instancio.internal.assignment.AssignmentErrorUtil;
import org.instancio.internal.context.ModelContext;
import org.instancio.internal.generator.ContainerAddFunction;
import org.instancio.internal.generator.GeneratorResult;
import org.instancio.internal.generator.InternalContainerHint;
import org.instancio.internal.nodes.InternalNode;
import org.instancio.internal.nodes.NodeKind;
import org.instancio.internal.util.ArrayUtils;
import org.instancio.internal.util.CollectionUtils;
import org.instancio.internal.util.Constants;
import org.instancio.internal.util.ErrorMessageUtils;
import org.instancio.internal.util.Fail;
import org.instancio.internal.util.ObjectUtils;
import org.instancio.internal.util.RecordUtils;
import org.instancio.internal.util.ReflectionUtils;
import org.instancio.settings.Keys;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Array;
import java.lang.reflect.Modifier;
import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Deque;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.instancio.internal.util.ObjectUtils.defaultIfNull;
/**
* Entry point for generating an object.
*
*
A new instance of this class should be created for each
* object generated via {@link #createRootObject()}.
*/
@SuppressWarnings({"PMD.GodClass", "PMD.CyclomaticComplexity", "PMD.ExcessiveImports"})
class InstancioEngine {
private static final Logger LOG = LoggerFactory.getLogger(InstancioEngine.class);
private final GeneratorFacade generatorFacade;
private final ModelContext> context;
private final InternalNode rootNode;
private final ErrorHandler errorHandler;
private final CallbackHandler callbackHandler;
private final ContainerFactoriesHandler containerFactoriesHandler;
private final GenerationListener[] listeners;
private final AfterGenerate defaultAfterGenerate;
private final NodeFilter nodeFilter;
private final Assigner assigner;
private final GeneratedObjectStore generatedObjectStore;
private final DelayedNodeQueue delayedNodeQueue = new DelayedNodeQueue();
InstancioEngine(InternalModel> model) {
context = model.getModelContext();
rootNode = model.getRootNode();
errorHandler = new ErrorHandler(context);
callbackHandler = new CallbackHandler(context);
containerFactoriesHandler = new ContainerFactoriesHandler(context.getInternalServiceProviders());
generatedObjectStore = new GeneratedObjectStore(context);
generatorFacade = new GeneratorFacade(context, generatedObjectStore);
defaultAfterGenerate = context.getSettings().get(Keys.AFTER_GENERATE_HINT);
nodeFilter = new NodeFilter(context);
assigner = new AssignerImpl(context);
listeners = new GenerationListener[]{
callbackHandler, generatedObjectStore, new GeneratedNullValueListener(context)};
}
@SuppressWarnings("unchecked")
T createRootObject() {
return (T) errorHandler
.conditionalFailOnError(this::createRootObjectInternal)
.orElse(null);
}
private Object createRootObjectInternal() {
final GeneratorResult generatorResult = createObject(rootNode); // NOPMD
callbackHandler.invokeCallbacks();
processDelayedNodes(true);
context.reportWarnings();
if (generatorResult.isEmpty()) {
final Class> rootClass = rootNode.getTargetClass();
if (Modifier.isAbstract(rootClass.getModifiers())
&& !context.getSubtypeSelectorMap().getSubtype(rootNode).isPresent()) {
throw Fail.withUsageError(ErrorMessageUtils.abstractRootWithoutSubtype(rootClass));
}
}
return generatorResult.getValue();
}
private void processDelayedNodes(final boolean failOnUnprocessed) {
int i = delayedNodeQueue.size();
while (i >= 0 && !delayedNodeQueue.isEmpty()) {
final DelayedNode entry = delayedNodeQueue.removeFirst();
final GeneratorResult result = createObject(entry.getNode());
if (result.isDelayed()) {
i--;
delayedNodeQueue.addLast(entry);
} else {
assignValue(entry.getParentResult().getValue(), entry.getNode(), result);
}
}
if (failOnUnprocessed && (delayedNodeQueue.hasRecordNodes() || !delayedNodeQueue.isEmpty())) {
final String msg = AssignmentErrorUtil.getUnresolvedAssignmentErrorMessage(
generatorFacade.getUnresolvedAssignments(), delayedNodeQueue);
throw Fail.withUnresolvedAssignment(msg);
}
}
@NotNull
private GeneratorResult createObject(final InternalNode node, final boolean isNullable) {
LOG.trace(" >> {}", node);
final GeneratorResult generatorResult;
if (context.getRandom().diceRoll(isNullable)) {
generatorResult = GeneratorResult.nullResult();
} else if (node.is(NodeKind.JDK) || node.getChildren().isEmpty()) { // leaf - generate a value
generatorResult = generateValue(node);
} else if (node.is(NodeKind.ARRAY)) {
generatorResult = generateArray(node);
} else if (node.is(NodeKind.COLLECTION)) {
generatorResult = generateCollection(node);
} else if (node.is(NodeKind.MAP)) {
generatorResult = generateMap(node);
} else if (node.is(NodeKind.RECORD)) {
generatorResult = generateRecord(node);
} else if (node.is(NodeKind.CONTAINER)) {
generatorResult = generateContainer(node);
} else if (node.is(NodeKind.POJO)) {
generatorResult = generatePojo(node);
} else { // unreachable
throw Fail.withFataInternalError("Unhandled node kind: '%s' for %s", node.getNodeKind(), node);
}
notifyListeners(node, generatorResult);
if (generatedObjectStore.hasNewValues()) {
processDelayedNodes(false);
}
LOG.trace("<< {} : {}", node, generatorResult);
return generatorResult;
}
@NotNull
private GeneratorResult createObject(final InternalNode node) {
return createObject(node, false);
}
private GeneratorResult generatePojo(final InternalNode node) {
final GeneratorResult nodeResult = generateValue(node);
if (!nodeResult.isDelayed()) {
populateChildren(node.getChildren(), nodeResult);
}
return nodeResult;
}
@SuppressWarnings({"PMD.CognitiveComplexity", "PMD.NPathComplexity"})
private GeneratorResult generateMap(final InternalNode node) {
final GeneratorResult generatorResult = generateValue(node);
if (generatorResult.containsNull() || node.getChildren().size() < 2) {
return generatorResult;
}
ApiValidator.validateValueIsAssignableToTargetClass(generatorResult.getValue(), Map.class, node);
//noinspection unchecked
final Map