From b8c1cfbd73b58497189ea57a30199874c4ae0708 Mon Sep 17 00:00:00 2001 From: "ah.jo" Date: Sat, 16 Mar 2024 00:16:36 +0900 Subject: [PATCH] Add ConcreteTypeDefinition to store the definition that resolves the concrete class (#944) --- docs/content/v1.0.x/release-notes/_index.md | 7 ++ .../api/generator/ArbitraryProperty.java | 51 +++++++---- .../api/property/ConcreteTypeDefinition.java | 43 ++++++++++ .../NodeSetDecomposedValueManipulator.java | 16 ++-- .../tree/ArbitraryTraverser.java | 85 +++++++------------ 5 files changed, 124 insertions(+), 78 deletions(-) create mode 100644 fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/property/ConcreteTypeDefinition.java diff --git a/docs/content/v1.0.x/release-notes/_index.md b/docs/content/v1.0.x/release-notes/_index.md index d0f322e59..a7a5cfafc 100644 --- a/docs/content/v1.0.x/release-notes/_index.md +++ b/docs/content/v1.0.x/release-notes/_index.md @@ -5,6 +5,13 @@ menu: docs: weight: 100 --- + +sectionStart +### v.1.0.15 +Add `ConcreteTypeDefinition` in `ArbitraryProperty`, deprecate `getChildPropertiesByResolvedProperty` and `getChildPropertyListsByCandidateProperty` which is added in 1.0.14. + +sectionEnd + sectionStart ### v.1.0.14 Add supporting value class with the private constructor. diff --git a/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/generator/ArbitraryProperty.java b/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/generator/ArbitraryProperty.java index 658c07500..b5cf67439 100644 --- a/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/generator/ArbitraryProperty.java +++ b/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/generator/ArbitraryProperty.java @@ -18,15 +18,19 @@ package com.navercorp.fixturemonkey.api.generator; +import static java.util.stream.Collectors.toMap; + +import java.util.AbstractMap.SimpleEntry; import java.util.List; import java.util.Map; -import java.util.Map.Entry; import java.util.Objects; +import java.util.stream.Collectors; import org.apiguardian.api.API; import org.apiguardian.api.API.Status; import com.navercorp.fixturemonkey.api.matcher.Matcher; +import com.navercorp.fixturemonkey.api.property.ConcreteTypeDefinition; import com.navercorp.fixturemonkey.api.property.Property; @API(since = "0.4.0", status = Status.MAINTAINED) @@ -34,14 +38,15 @@ public final class ArbitraryProperty { private final ObjectProperty objectProperty; private final boolean container; private final double nullInject; - private final Map> childPropertyListsByCandidateProperty; + private final List concreteTypeDefinitions; @Deprecated public ArbitraryProperty(ObjectProperty objectProperty, boolean container) { this.objectProperty = objectProperty; this.container = container; this.nullInject = objectProperty.getNullInject(); - this.childPropertyListsByCandidateProperty = objectProperty.getChildPropertyListsByCandidateProperty(); + this.concreteTypeDefinitions = + toConcreteTypeDefinition(objectProperty.getChildPropertyListsByCandidateProperty()); } public ArbitraryProperty( @@ -53,7 +58,7 @@ public ArbitraryProperty( this.objectProperty = objectProperty; this.container = container; this.nullInject = nullInject; - this.childPropertyListsByCandidateProperty = childPropertyListsByCandidateProperty; + this.concreteTypeDefinitions = toConcreteTypeDefinition(childPropertyListsByCandidateProperty); } public ObjectProperty getObjectProperty() { @@ -72,21 +77,29 @@ public double getNullInject() { return nullInject; } + public List getConcreteTypeDefinitions() { + return concreteTypeDefinitions; + } + + /** + * It is deprecated. Use {@link #getConcreteTypeDefinitions()} instead. + */ + @Deprecated public Map> getChildPropertyListsByCandidateProperty() { - return childPropertyListsByCandidateProperty; + return concreteTypeDefinitions.stream() + .collect(toMap(ConcreteTypeDefinition::getConcreteProperty, ConcreteTypeDefinition::getChildPropertyLists)); } + /** + * It is deprecated. Use {@link #getConcreteTypeDefinitions()} instead. + */ + @Deprecated public Map.Entry> getChildPropertiesByResolvedProperty(Matcher matcher) { - for ( - Entry> childPropertyListByPossibleProperty : - childPropertyListsByCandidateProperty.entrySet() - ) { - Property property = childPropertyListByPossibleProperty.getKey(); - if (matcher.match(property)) { - return childPropertyListByPossibleProperty; - } - } - throw new IllegalArgumentException("No resolved property is found."); + return concreteTypeDefinitions.stream() + .filter(it -> matcher.match(it.getConcreteProperty())) + .findFirst() + .map(it -> new SimpleEntry<>(it.getConcreteProperty(), it.getChildPropertyLists())) + .orElseThrow(() -> new IllegalArgumentException("No resolved property is found.")); } @Override @@ -105,4 +118,12 @@ public boolean equals(Object obj) { public int hashCode() { return Objects.hash(objectProperty, container); } + + private static List toConcreteTypeDefinition( + Map> childPropertyListsByCandidateProperty + ) { + return childPropertyListsByCandidateProperty.entrySet().stream() + .map(entry -> new ConcreteTypeDefinition(entry.getKey(), entry.getValue())) + .collect(Collectors.toList()); + } } diff --git a/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/property/ConcreteTypeDefinition.java b/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/property/ConcreteTypeDefinition.java new file mode 100644 index 000000000..2a332cb9d --- /dev/null +++ b/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/property/ConcreteTypeDefinition.java @@ -0,0 +1,43 @@ +/* + * Fixture Monkey + * + * Copyright (c) 2021-present NAVER Corp. + * + * 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 + * + * http://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 com.navercorp.fixturemonkey.api.property; + +import java.util.List; + +/** + * Represents a concrete type definition with a resolved concrete property and a list of child properties. + * Instances of this class are immutable once created. + */ +public final class ConcreteTypeDefinition { + private final Property concreteProperty; + private final List childPropertyLists; + + public ConcreteTypeDefinition(Property concreteProperty, List childPropertyLists) { + this.concreteProperty = concreteProperty; + this.childPropertyLists = childPropertyLists; + } + + public Property getConcreteProperty() { + return concreteProperty; + } + + public List getChildPropertyLists() { + return childPropertyLists; + } +} diff --git a/fixture-monkey/src/main/java/com/navercorp/fixturemonkey/customizer/NodeSetDecomposedValueManipulator.java b/fixture-monkey/src/main/java/com/navercorp/fixturemonkey/customizer/NodeSetDecomposedValueManipulator.java index 69a7c5bb1..77f7777d2 100644 --- a/fixture-monkey/src/main/java/com/navercorp/fixturemonkey/customizer/NodeSetDecomposedValueManipulator.java +++ b/fixture-monkey/src/main/java/com/navercorp/fixturemonkey/customizer/NodeSetDecomposedValueManipulator.java @@ -24,7 +24,6 @@ import java.util.Collections; import java.util.List; -import java.util.Map.Entry; import javax.annotation.Nullable; @@ -35,6 +34,7 @@ import com.navercorp.fixturemonkey.api.container.DecomposableJavaContainer; import com.navercorp.fixturemonkey.api.container.DecomposedContainerValueFactory; import com.navercorp.fixturemonkey.api.generator.ArbitraryContainerInfo; +import com.navercorp.fixturemonkey.api.property.ConcreteTypeDefinition; import com.navercorp.fixturemonkey.api.property.MapEntryElementProperty; import com.navercorp.fixturemonkey.api.property.Property; import com.navercorp.fixturemonkey.api.type.Types; @@ -148,14 +148,16 @@ private void setValue(ObjectNode objectNode, @Nullable Object value) { return; } - Entry> childPropertiesByResolvedProperty = objectNode.getArbitraryProperty() - .getChildPropertiesByResolvedProperty( - property -> isAssignable(value.getClass(), Types.getActualType(property.getType())) - ); + ConcreteTypeDefinition concreteTypeDefinition = objectNode.getArbitraryProperty() + .getConcreteTypeDefinitions() + .stream() + .filter(it -> isAssignable(value.getClass(), Types.getActualType(it.getConcreteProperty().getType()))) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("No resolved property is found.")); - Property resolvedParentProperty = childPropertiesByResolvedProperty.getKey(); + Property resolvedParentProperty = concreteTypeDefinition.getConcreteProperty(); objectNode.setResolvedProperty(resolvedParentProperty); - List childProperties = childPropertiesByResolvedProperty.getValue(); + List childProperties = concreteTypeDefinition.getChildPropertyLists(); for (ObjectNode child : children) { if (childProperties.contains(child.getProperty()) && resolvedParentProperty.equals(child.getResolvedParentProperty())) { diff --git a/fixture-monkey/src/main/java/com/navercorp/fixturemonkey/tree/ArbitraryTraverser.java b/fixture-monkey/src/main/java/com/navercorp/fixturemonkey/tree/ArbitraryTraverser.java index 3e31e1fea..4c8f593e7 100644 --- a/fixture-monkey/src/main/java/com/navercorp/fixturemonkey/tree/ArbitraryTraverser.java +++ b/fixture-monkey/src/main/java/com/navercorp/fixturemonkey/tree/ArbitraryTraverser.java @@ -107,20 +107,30 @@ public ObjectNode traverse( ); } + Map> childPropertyListsByCandidateProperty; + if (container) { + childPropertyListsByCandidateProperty = Collections.singletonMap( + property, + containerProperty.getElementProperties() + ); + } else { + childPropertyListsByCandidateProperty = objectProperty.getChildPropertyListsByCandidateProperty(); + } + ArbitraryProperty arbitraryProperty = new ArbitraryProperty( objectProperty, container, objectProperty.getNullInject(), - objectProperty.getChildPropertyListsByCandidateProperty() + childPropertyListsByCandidateProperty ); List parentArbitraryProperties = new ArrayList<>(); parentArbitraryProperties.add(arbitraryProperty); - ObjectNode rootNode = this.traverse( + ObjectNode rootNode = generateObjectNode( arbitraryProperty, - containerProperty, null, + container, new TraverseContext( arbitraryProperty, parentArbitraryProperties, @@ -162,29 +172,10 @@ private PropertyGenerator getPropertyGenerator(Map, List> pro }; } - private ObjectNode traverse( - ArbitraryProperty arbitraryProperty, - @Nullable ContainerProperty containerProperty, - @Nullable Property resolvedParentProperty, - TraverseContext context - ) { - boolean container = containerProperty != null; - - if (container) { - return generateContainerNode( - arbitraryProperty, - containerProperty, - resolvedParentProperty, - context - ); - } - - return generateObjectNode(arbitraryProperty, resolvedParentProperty, context); - } - private ObjectNode generateObjectNode( ArbitraryProperty arbitraryProperty, @Nullable Property resolvedParentProperty, + boolean container, TraverseContext context ) { List children = new ArrayList<>(); @@ -203,7 +194,7 @@ private ObjectNode generateObjectNode( generateChildrenNodes( childProperties, arbitraryProperty, - null, + container, candidateProperty, context ) @@ -221,41 +212,15 @@ private ObjectNode generateObjectNode( ); } - private ObjectNode generateContainerNode( - ArbitraryProperty arbitraryProperty, - ContainerProperty containerProperty, - @Nullable Property resolvedParentProperty, - TraverseContext context - ) { - ObjectProperty objectProperty = arbitraryProperty.getObjectProperty(); - - Property resolvedProperty = objectProperty.getProperty(); - List elementProperties = containerProperty.getElementProperties(); - - return new ObjectNode( - resolvedParentProperty, - resolvedProperty, - arbitraryProperty, - generateChildrenNodes( - elementProperties, - arbitraryProperty, - containerProperty, - objectProperty.getProperty(), - context - ) - ); - } - private List generateChildrenNodes( List childProperties, ArbitraryProperty parentArbitraryProperty, - @Nullable ContainerProperty parentContainerProperty, + boolean parentContainer, Property resolvedParentProperty, TraverseContext context ) { List children = new ArrayList<>(); List containerInfoManipulators = context.getContainerInfoManipulators(); - boolean container = parentContainerProperty != null; for (int sequence = 0; sequence < childProperties.size(); sequence++) { Property childProperty = childProperties.get(sequence); @@ -283,7 +248,7 @@ private List generateChildrenNodes( ObjectProperty childObjectProperty = objectPropertyGenerator.generate( new ObjectPropertyGeneratorContext( childProperty, - container ? index : null, + parentContainer ? index : null, parentArbitraryProperty, childContainer, getPropertyGenerator(context.getPropertyConfigurers()), @@ -292,6 +257,8 @@ private List generateChildrenNodes( ) ); + Map> childPropertyListsByCandidateProperty; + ContainerProperty childContainerProperty = null; ContainerInfoManipulator appliedContainerInfoManipulator = null; if (childContainer) { @@ -310,24 +277,30 @@ private List generateChildrenNodes( childContainerProperty = containerPropertyGenerator.generate( new ContainerPropertyGeneratorContext( childProperty, - container ? index : null, + parentContainer ? index : null, containerInfo, fixtureMonkeyOptions.getArbitraryContainerInfoGenerator(childProperty) ) ); + childPropertyListsByCandidateProperty = Collections.singletonMap( + childProperty, + childContainerProperty.getElementProperties() + ); + } else { + childPropertyListsByCandidateProperty = childObjectProperty.getChildPropertyListsByCandidateProperty(); } ArbitraryProperty childArbitraryProperty = new ArbitraryProperty( childObjectProperty, childContainer, childObjectProperty.getNullInject(), - childObjectProperty.getChildPropertyListsByCandidateProperty() + childPropertyListsByCandidateProperty ); - ObjectNode childNode = this.traverse( + ObjectNode childNode = generateObjectNode( childArbitraryProperty, - childContainerProperty, resolvedParentProperty, + childContainer, context.appendArbitraryProperty(childArbitraryProperty) );