Skip to content

Commit

Permalink
Add ConcreteTypeDefinition to store the definition that resolves the …
Browse files Browse the repository at this point in the history
…concrete class (#944)
  • Loading branch information
seongahjo authored Mar 15, 2024
1 parent 57f75fe commit b8c1cfb
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 78 deletions.
7 changes: 7 additions & 0 deletions docs/content/v1.0.x/release-notes/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,30 +18,35 @@

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)
public final class ArbitraryProperty {
private final ObjectProperty objectProperty;
private final boolean container;
private final double nullInject;
private final Map<Property, List<Property>> childPropertyListsByCandidateProperty;
private final List<ConcreteTypeDefinition> 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(
Expand All @@ -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() {
Expand All @@ -72,21 +77,29 @@ public double getNullInject() {
return nullInject;
}

public List<ConcreteTypeDefinition> getConcreteTypeDefinitions() {
return concreteTypeDefinitions;
}

/**
* It is deprecated. Use {@link #getConcreteTypeDefinitions()} instead.
*/
@Deprecated
public Map<Property, List<Property>> getChildPropertyListsByCandidateProperty() {
return childPropertyListsByCandidateProperty;
return concreteTypeDefinitions.stream()
.collect(toMap(ConcreteTypeDefinition::getConcreteProperty, ConcreteTypeDefinition::getChildPropertyLists));
}

/**
* It is deprecated. Use {@link #getConcreteTypeDefinitions()} instead.
*/
@Deprecated
public Map.Entry<Property, List<Property>> getChildPropertiesByResolvedProperty(Matcher matcher) {
for (
Entry<Property, List<Property>> 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
Expand All @@ -105,4 +118,12 @@ public boolean equals(Object obj) {
public int hashCode() {
return Objects.hash(objectProperty, container);
}

private static List<ConcreteTypeDefinition> toConcreteTypeDefinition(
Map<Property, List<Property>> childPropertyListsByCandidateProperty
) {
return childPropertyListsByCandidateProperty.entrySet().stream()
.map(entry -> new ConcreteTypeDefinition(entry.getKey(), entry.getValue()))
.collect(Collectors.toList());
}
}
Original file line number Diff line number Diff line change
@@ -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<Property> childPropertyLists;

public ConcreteTypeDefinition(Property concreteProperty, List<Property> childPropertyLists) {
this.concreteProperty = concreteProperty;
this.childPropertyLists = childPropertyLists;
}

public Property getConcreteProperty() {
return concreteProperty;
}

public List<Property> getChildPropertyLists() {
return childPropertyLists;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@

import java.util.Collections;
import java.util.List;
import java.util.Map.Entry;

import javax.annotation.Nullable;

Expand All @@ -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;
Expand Down Expand Up @@ -148,14 +148,16 @@ private void setValue(ObjectNode objectNode, @Nullable Object value) {
return;
}

Entry<Property, List<Property>> 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<Property> childProperties = childPropertiesByResolvedProperty.getValue();
List<Property> childProperties = concreteTypeDefinition.getChildPropertyLists();
for (ObjectNode child : children) {
if (childProperties.contains(child.getProperty())
&& resolvedParentProperty.equals(child.getResolvedParentProperty())) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,20 +107,30 @@ public ObjectNode traverse(
);
}

Map<Property, List<Property>> 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<ArbitraryProperty> parentArbitraryProperties = new ArrayList<>();
parentArbitraryProperties.add(arbitraryProperty);

ObjectNode rootNode = this.traverse(
ObjectNode rootNode = generateObjectNode(
arbitraryProperty,
containerProperty,
null,
container,
new TraverseContext(
arbitraryProperty,
parentArbitraryProperties,
Expand Down Expand Up @@ -162,29 +172,10 @@ private PropertyGenerator getPropertyGenerator(Map<Class<?>, List<Property>> 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<ObjectNode> children = new ArrayList<>();
Expand All @@ -203,7 +194,7 @@ private ObjectNode generateObjectNode(
generateChildrenNodes(
childProperties,
arbitraryProperty,
null,
container,
candidateProperty,
context
)
Expand All @@ -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<Property> elementProperties = containerProperty.getElementProperties();

return new ObjectNode(
resolvedParentProperty,
resolvedProperty,
arbitraryProperty,
generateChildrenNodes(
elementProperties,
arbitraryProperty,
containerProperty,
objectProperty.getProperty(),
context
)
);
}

private List<ObjectNode> generateChildrenNodes(
List<Property> childProperties,
ArbitraryProperty parentArbitraryProperty,
@Nullable ContainerProperty parentContainerProperty,
boolean parentContainer,
Property resolvedParentProperty,
TraverseContext context
) {
List<ObjectNode> children = new ArrayList<>();
List<ContainerInfoManipulator> containerInfoManipulators = context.getContainerInfoManipulators();
boolean container = parentContainerProperty != null;

for (int sequence = 0; sequence < childProperties.size(); sequence++) {
Property childProperty = childProperties.get(sequence);
Expand Down Expand Up @@ -283,7 +248,7 @@ private List<ObjectNode> generateChildrenNodes(
ObjectProperty childObjectProperty = objectPropertyGenerator.generate(
new ObjectPropertyGeneratorContext(
childProperty,
container ? index : null,
parentContainer ? index : null,
parentArbitraryProperty,
childContainer,
getPropertyGenerator(context.getPropertyConfigurers()),
Expand All @@ -292,6 +257,8 @@ private List<ObjectNode> generateChildrenNodes(
)
);

Map<Property, List<Property>> childPropertyListsByCandidateProperty;

ContainerProperty childContainerProperty = null;
ContainerInfoManipulator appliedContainerInfoManipulator = null;
if (childContainer) {
Expand All @@ -310,24 +277,30 @@ private List<ObjectNode> 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)
);

Expand Down

0 comments on commit b8c1cfb

Please sign in to comment.