diff --git a/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/matcher/DefaultTreeMatcherMetadata.java b/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/matcher/DefaultTreeMatcherMetadata.java new file mode 100644 index 000000000..c95718195 --- /dev/null +++ b/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/matcher/DefaultTreeMatcherMetadata.java @@ -0,0 +1,39 @@ +/* + * 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.matcher; + +import java.lang.annotation.Annotation; +import java.util.Set; + +import org.apiguardian.api.API; +import org.apiguardian.api.API.Status; + +@API(since = "1.0.4", status = Status.EXPERIMENTAL) +public final class DefaultTreeMatcherMetadata implements TreeMatcherMetadata { + private final Set annotations; + + public DefaultTreeMatcherMetadata(Set annotations) { + this.annotations = annotations; + } + + @Override + public Set getAnnotations() { + return annotations; + } +} diff --git a/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/matcher/TreeMatcher.java b/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/matcher/TreeMatcher.java new file mode 100644 index 000000000..419d44585 --- /dev/null +++ b/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/matcher/TreeMatcher.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.matcher; + +import org.apiguardian.api.API; +import org.apiguardian.api.API.Status; + +/** + * It is mainly used to customize the ObjectTree that meets the specific condition with {@link TreeMatcherOperator}. + *

+ * The main difference to the {@link Matcher} is the scope. + * {@link Matcher} is intended to reference the nodes of the ObjectTree, + * but {@link TreeMatcher} is intended to reference the ObjectTree itself. + * + * @see Matcher + */ +@API(since = "1.0.4", status = Status.EXPERIMENTAL) +@FunctionalInterface +public interface TreeMatcher { + /** + * Determines if the ObjectTree meets the condition. + * + * @param metadata the metadata of the ObjectTree + * @return {@code true} if the condition matches, {@code false} if not matches + */ + boolean match(TreeMatcherMetadata metadata); +} diff --git a/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/matcher/TreeMatcherMetadata.java b/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/matcher/TreeMatcherMetadata.java new file mode 100644 index 000000000..1c534e0f9 --- /dev/null +++ b/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/matcher/TreeMatcherMetadata.java @@ -0,0 +1,38 @@ +/* + * 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.matcher; + +import java.lang.annotation.Annotation; +import java.util.Set; + +import org.apiguardian.api.API; +import org.apiguardian.api.API.Status; + +/** + * It contains the metadata of the ObjectTree. + */ +@API(since = "1.0.4", status = Status.EXPERIMENTAL) +public interface TreeMatcherMetadata { + /** + * Retrieves the annotations of all nodes in the ObjectTree. + * + * @return the annotations of all nodes + */ + Set getAnnotations(); +} diff --git a/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/matcher/TreeMatcherOperator.java b/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/matcher/TreeMatcherOperator.java new file mode 100644 index 000000000..d64cac70d --- /dev/null +++ b/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/matcher/TreeMatcherOperator.java @@ -0,0 +1,42 @@ +/* + * 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.matcher; + +import org.apiguardian.api.API; +import org.apiguardian.api.API.Status; + +@API(since = "1.0.4", status = Status.EXPERIMENTAL) +public final class TreeMatcherOperator implements TreeMatcher { + private final TreeMatcher matcher; + private final T operator; + + public TreeMatcherOperator(TreeMatcher matcher, T operator) { + this.matcher = matcher; + this.operator = operator; + } + + @Override + public boolean match(TreeMatcherMetadata metadata) { + return this.matcher.match(metadata); + } + + public T getOperator() { + return operator; + } +} diff --git a/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/option/BuilderContextInitializer.java b/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/option/BuilderContextInitializer.java new file mode 100644 index 000000000..f854094ed --- /dev/null +++ b/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/option/BuilderContextInitializer.java @@ -0,0 +1,44 @@ +/* + * 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.option; + +import org.apiguardian.api.API; +import org.apiguardian.api.API.Status; + +/** + * It is a public API to customize the ObjectTree. + *

+ * It should contain the customizing options for the ObjectTree, not for the node. + */ +@API(since = "1.1.4", status = Status.EXPERIMENTAL) +public final class BuilderContextInitializer { + private final boolean validOnly; + + private BuilderContextInitializer(boolean validOnly) { + this.validOnly = validOnly; + } + + public static BuilderContextInitializer validOnly(boolean validOnly) { + return new BuilderContextInitializer(validOnly); + } + + public boolean isValidOnly() { + return validOnly; + } +} diff --git a/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/option/FixtureMonkeyOptions.java b/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/option/FixtureMonkeyOptions.java index bccbdf50c..2528912c5 100644 --- a/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/option/FixtureMonkeyOptions.java +++ b/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/option/FixtureMonkeyOptions.java @@ -78,6 +78,7 @@ import com.navercorp.fixturemonkey.api.matcher.MatcherOperator; import com.navercorp.fixturemonkey.api.matcher.Matchers; import com.navercorp.fixturemonkey.api.matcher.SingleGenericTypeMatcher; +import com.navercorp.fixturemonkey.api.matcher.TreeMatcherOperator; import com.navercorp.fixturemonkey.api.property.CandidateConcretePropertyResolver; import com.navercorp.fixturemonkey.api.property.CompositeCandidateConcretePropertyResolver; import com.navercorp.fixturemonkey.api.property.ConcreteTypeCandidateConcretePropertyResolver; @@ -167,6 +168,7 @@ public final class FixtureMonkeyOptions { private final InstantiatorProcessor instantiatorProcessor; private final List> candidateConcretePropertyResolvers; private final boolean enableLoggingFail; + private final List> builderContextInitializers; public FixtureMonkeyOptions( List> propertyGenerators, @@ -188,7 +190,8 @@ public FixtureMonkeyOptions( JavaConstraintGenerator javaConstraintGenerator, InstantiatorProcessor instantiatorProcessor, List> candidateConcretePropertyResolvers, - boolean enableLoggingFail + boolean enableLoggingFail, + List> builderContextCustomizer ) { this.propertyGenerators = propertyGenerators; this.defaultPropertyGenerator = defaultPropertyGenerator; @@ -210,6 +213,7 @@ public FixtureMonkeyOptions( this.instantiatorProcessor = instantiatorProcessor; this.candidateConcretePropertyResolvers = candidateConcretePropertyResolvers; this.enableLoggingFail = enableLoggingFail; + this.builderContextInitializers = builderContextCustomizer; } public static FixtureMonkeyOptionsBuilder builder() { @@ -342,6 +346,10 @@ public boolean isEnableLoggingFail() { return enableLoggingFail; } + public List> getBuilderContextInitializers() { + return builderContextInitializers; + } + @Nullable public CandidateConcretePropertyResolver getCandidateConcretePropertyResolver(Property property) { List candidateConcretePropertyResolverList = @@ -373,7 +381,8 @@ public FixtureMonkeyOptionsBuilder toBuilder() { .decomposedContainerValueFactory(decomposedContainerValueFactory) .javaConstraintGenerator(javaConstraintGenerator) .instantiatorProcessor(instantiatorProcessor) - .candidateConcretePropertyResolvers(candidateConcretePropertyResolvers); + .candidateConcretePropertyResolvers(candidateConcretePropertyResolvers) + .builderContextInitializers(builderContextInitializers); } private static List> getDefaultContainerPropertyGenerators() { diff --git a/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/option/FixtureMonkeyOptionsBuilder.java b/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/option/FixtureMonkeyOptionsBuilder.java index ff6c3399c..bca7d533f 100644 --- a/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/option/FixtureMonkeyOptionsBuilder.java +++ b/fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/option/FixtureMonkeyOptionsBuilder.java @@ -73,6 +73,7 @@ import com.navercorp.fixturemonkey.api.jqwik.JqwikJavaTypeArbitraryGeneratorSet; import com.navercorp.fixturemonkey.api.matcher.Matcher; import com.navercorp.fixturemonkey.api.matcher.MatcherOperator; +import com.navercorp.fixturemonkey.api.matcher.TreeMatcherOperator; import com.navercorp.fixturemonkey.api.plugin.Plugin; import com.navercorp.fixturemonkey.api.property.CandidateConcretePropertyResolver; import com.navercorp.fixturemonkey.api.property.DefaultPropertyGenerator; @@ -139,6 +140,7 @@ public final class FixtureMonkeyOptionsBuilder { private InstantiatorProcessor instantiatorProcessor = new JavaInstantiatorProcessor(); private List> candidateConcretePropertyResolvers = new ArrayList<>(FixtureMonkeyOptions.DEFAULT_CANDIDATE_CONCRETE_PROPERTY_RESOLVERS); + private List> builderContextInitializers = new ArrayList<>(); FixtureMonkeyOptionsBuilder() { new JdkVariantOptions().apply(this); @@ -539,6 +541,23 @@ public FixtureMonkeyOptionsBuilder insertFirstCandidateConcretePropertyResolvers return this; } + public FixtureMonkeyOptionsBuilder builderContextInitializers( + List> builderContextInitializers + ) { + this.builderContextInitializers = builderContextInitializers; + return this; + } + + public FixtureMonkeyOptionsBuilder insertFirstBuilderContextInitializer( + TreeMatcherOperator builderContextInitializer + ) { + this.builderContextInitializers = insertFirst( + this.builderContextInitializers, + builderContextInitializer + ); + return this; + } + public FixtureMonkeyOptions build() { ObjectPropertyGenerator defaultObjectPropertyGenerator = defaultIfNull( this.defaultObjectPropertyGenerator, @@ -671,7 +690,8 @@ public FixtureMonkeyOptions build() { resolvedJavaConstraintGenerator, this.instantiatorProcessor, this.candidateConcretePropertyResolvers, - this.enableLoggingFail + this.enableLoggingFail, + this.builderContextInitializers ); } diff --git a/fixture-monkey-tests/kotlin-tests/src/test/kotlin/com/navercorp/fixturemonkey/tests/kotlin/KotlinTest.kt b/fixture-monkey-tests/kotlin-tests/src/test/kotlin/com/navercorp/fixturemonkey/tests/kotlin/KotlinTest.kt index 6c8a53c8f..98e9c8421 100644 --- a/fixture-monkey-tests/kotlin-tests/src/test/kotlin/com/navercorp/fixturemonkey/tests/kotlin/KotlinTest.kt +++ b/fixture-monkey-tests/kotlin-tests/src/test/kotlin/com/navercorp/fixturemonkey/tests/kotlin/KotlinTest.kt @@ -23,6 +23,7 @@ import com.navercorp.fixturemonkey.api.arbitrary.CombinableArbitrary import com.navercorp.fixturemonkey.api.experimental.JavaGetterMethodPropertySelector.javaGetter import com.navercorp.fixturemonkey.api.experimental.TypedExpressionGenerator.typedRoot import com.navercorp.fixturemonkey.api.experimental.TypedExpressionGenerator.typedString +import com.navercorp.fixturemonkey.api.expression.TypedExpressionGenerator import com.navercorp.fixturemonkey.api.introspector.AnonymousArbitraryIntrospector import com.navercorp.fixturemonkey.api.introspector.ArbitraryIntrospectorResult import com.navercorp.fixturemonkey.api.introspector.BeanArbitraryIntrospector @@ -39,6 +40,7 @@ import com.navercorp.fixturemonkey.api.property.PropertyUtils import com.navercorp.fixturemonkey.api.type.Types.GeneratingWildcardType import com.navercorp.fixturemonkey.customizer.Values import com.navercorp.fixturemonkey.javax.validation.plugin.JavaxValidationPlugin +import com.navercorp.fixturemonkey.javax.validation.validator.JavaxArbitraryValidator import com.navercorp.fixturemonkey.kotlin.KotlinPlugin import com.navercorp.fixturemonkey.kotlin.expression.root import com.navercorp.fixturemonkey.kotlin.get @@ -79,6 +81,7 @@ import java.time.temporal.ChronoUnit import java.util.LinkedList import java.util.TreeSet import java.util.UUID +import javax.validation.Valid import javax.validation.constraints.Size import kotlin.reflect.jvm.javaMethod @@ -1097,6 +1100,63 @@ class KotlinTest { then(actual).isEqualTo(expected) } + @Test + fun customizerValidOnly() { + // given + class StringWithSizeZero( + @field:Size(min = 0, max = 0) + val value: String, + ) + + class Wrapper(@field:Valid val value: StringWithSizeZero) + + val sut = FixtureMonkey.builder() + .plugin(KotlinPlugin()) + .plugin { it.defaultArbitraryValidator(JavaxArbitraryValidator()) } + .pushCustomizeValidOnly( + { it.annotations.any { annotation -> annotation.annotationClass == Size::class } }, + false + ) + .build() + + // when + val actual = sut.giveMeBuilder() + .customizeProperty(TypedExpressionGenerator.typedString("value.value")) { it.filter { str -> str.length > 1 } } + .sample() + + // then + then(actual).isNotNull + } + + @Test + fun customizerValidOnlyBuilderValidOnlyFirst() { + // given + class StringWithSizeZero( + @field:Size(min = 0, max = 0) + val value: String, + ) + + class Wrapper(@field:Valid val value: StringWithSizeZero) + + val sut = FixtureMonkey.builder() + .plugin(KotlinPlugin()) + .plugin { it.defaultArbitraryValidator(JavaxArbitraryValidator()) } + .pushCustomizeValidOnly( + { it.annotations.any { annotation -> annotation.annotationClass == Size::class } }, + true + ) + .build() + + // when + val actual = sut.giveMeBuilder() + .customizeProperty(TypedExpressionGenerator.typedString("value.value")) { it.filter { str -> str.length > 1 } } + .validOnly(false) + .sample() + + // then + then(actual).isNotNull + } + companion object { private val SUT: FixtureMonkey = FixtureMonkey.builder() .plugin(KotlinPlugin()) diff --git a/fixture-monkey/src/main/java/com/navercorp/fixturemonkey/FixtureMonkeyBuilder.java b/fixture-monkey/src/main/java/com/navercorp/fixturemonkey/FixtureMonkeyBuilder.java index 5d55af804..d3fa6b80a 100644 --- a/fixture-monkey/src/main/java/com/navercorp/fixturemonkey/FixtureMonkeyBuilder.java +++ b/fixture-monkey/src/main/java/com/navercorp/fixturemonkey/FixtureMonkeyBuilder.java @@ -43,6 +43,9 @@ import com.navercorp.fixturemonkey.api.matcher.AssignableTypeMatcher; import com.navercorp.fixturemonkey.api.matcher.Matcher; import com.navercorp.fixturemonkey.api.matcher.MatcherOperator; +import com.navercorp.fixturemonkey.api.matcher.TreeMatcher; +import com.navercorp.fixturemonkey.api.matcher.TreeMatcherOperator; +import com.navercorp.fixturemonkey.api.option.BuilderContextInitializer; import com.navercorp.fixturemonkey.api.option.FixtureMonkeyOptions; import com.navercorp.fixturemonkey.api.option.FixtureMonkeyOptionsBuilder; import com.navercorp.fixturemonkey.api.plugin.Plugin; @@ -474,6 +477,16 @@ public FixtureMonkeyBuilder pushJavaConstraintGeneratorCustomizer( return this; } + public FixtureMonkeyBuilder pushCustomizeValidOnly(TreeMatcher matcher, boolean validOnly) { + fixtureMonkeyOptionsBuilder.insertFirstBuilderContextInitializer( + new TreeMatcherOperator<>( + matcher, + BuilderContextInitializer.validOnly(validOnly) + ) + ); + return this; + } + /** * It is deprecated. Please use {@code @Seed} in fixture-monkey-junit-jupiter module. */ diff --git a/fixture-monkey/src/main/java/com/navercorp/fixturemonkey/builder/ArbitraryBuilderContext.java b/fixture-monkey/src/main/java/com/navercorp/fixturemonkey/builder/ArbitraryBuilderContext.java index 27ffcf8fe..bd9cc3f52 100644 --- a/fixture-monkey/src/main/java/com/navercorp/fixturemonkey/builder/ArbitraryBuilderContext.java +++ b/fixture-monkey/src/main/java/com/navercorp/fixturemonkey/builder/ArbitraryBuilderContext.java @@ -61,7 +61,11 @@ public final class ArbitraryBuilderContext { private final Map, ArbitraryIntrospector> arbitraryIntrospectorsByType; private final MonkeyContext monkeyContext; - private boolean validOnly; + @Nullable + private Boolean optionValidOnly; + + @Nullable + private Boolean customizedValidOnly; @Nullable private FixedState fixedState = null; @@ -73,7 +77,6 @@ private ArbitraryBuilderContext( List containerInfoManipulators, Map, List> propertyConfigurers, Map, ArbitraryIntrospector> arbitraryIntrospectorsByType, - boolean validOnly, @Nullable FixedState fixedState, @Nullable CombinableArbitrary fixedCombinableArbitrary, MonkeyContext monkeyContext @@ -82,7 +85,6 @@ private ArbitraryBuilderContext( this.containerInfoManipulators = containerInfoManipulators; this.propertyConfigurers = propertyConfigurers; this.arbitraryIntrospectorsByType = arbitraryIntrospectorsByType; - this.validOnly = validOnly; this.fixedState = fixedState; this.fixedCombinableArbitrary = fixedCombinableArbitrary; this.monkeyContext = monkeyContext; @@ -99,8 +101,8 @@ public static ArbitraryBuilderContext newBuilderContext(MonkeyContext monkeyCont new ArrayList<>(), new HashMap<>(), new HashMap<>(), - true, - null, null, + null, + null, monkeyContext ); } @@ -115,7 +117,6 @@ public ArbitraryBuilderContext copy() { copiedContainerInfoManipulators, new HashMap<>(propertyConfigurers), new HashMap<>(arbitraryIntrospectorsByType), - this.validOnly, fixedState, fixedCombinableArbitrary, monkeyContext @@ -162,12 +163,23 @@ public Map, List> getPropertyConfigurers() { return propertyConfigurers; } - public void setValidOnly(boolean validOnly) { - this.validOnly = validOnly; + public void setOptionValidOnly(@Nullable Boolean optionValidOnly) { + this.optionValidOnly = optionValidOnly; + } + + public void setCustomizedValidOnly(@Nullable Boolean customizedValidOnly) { + this.customizedValidOnly = customizedValidOnly; } public boolean isValidOnly() { - return validOnly; + if (this.customizedValidOnly != null) { + return this.customizedValidOnly; + } + + if (this.optionValidOnly != null) { + return this.optionValidOnly; + } + return true; } public void markFixed() { @@ -216,7 +228,7 @@ public TraverseContext newTraverseContext() { registeredContainerInfoManipulators, this.getPropertyConfigurers(), this.getArbitraryIntrospectorsByType(), - this.isValidOnly(), + this::isValidOnly, this.monkeyContext ); } diff --git a/fixture-monkey/src/main/java/com/navercorp/fixturemonkey/builder/DefaultArbitraryBuilder.java b/fixture-monkey/src/main/java/com/navercorp/fixturemonkey/builder/DefaultArbitraryBuilder.java index 6e34023e8..0abb289b6 100644 --- a/fixture-monkey/src/main/java/com/navercorp/fixturemonkey/builder/DefaultArbitraryBuilder.java +++ b/fixture-monkey/src/main/java/com/navercorp/fixturemonkey/builder/DefaultArbitraryBuilder.java @@ -101,7 +101,7 @@ public DefaultArbitraryBuilder( @Override public ArbitraryBuilder validOnly(boolean validOnly) { - this.context.setValidOnly(validOnly); + this.context.setCustomizedValidOnly(validOnly); return this; } diff --git a/fixture-monkey/src/main/java/com/navercorp/fixturemonkey/resolver/ArbitraryResolver.java b/fixture-monkey/src/main/java/com/navercorp/fixturemonkey/resolver/ArbitraryResolver.java index 7d80d58fc..f89840502 100644 --- a/fixture-monkey/src/main/java/com/navercorp/fixturemonkey/resolver/ArbitraryResolver.java +++ b/fixture-monkey/src/main/java/com/navercorp/fixturemonkey/resolver/ArbitraryResolver.java @@ -27,6 +27,8 @@ import com.navercorp.fixturemonkey.api.arbitrary.CombinableArbitrary; import com.navercorp.fixturemonkey.api.context.MonkeyContext; +import com.navercorp.fixturemonkey.api.matcher.DefaultTreeMatcherMetadata; +import com.navercorp.fixturemonkey.api.matcher.TreeMatcherOperator; import com.navercorp.fixturemonkey.api.option.FixtureMonkeyOptions; import com.navercorp.fixturemonkey.api.property.RootProperty; import com.navercorp.fixturemonkey.builder.ArbitraryBuilderContext; @@ -60,10 +62,20 @@ public CombinableArbitrary resolve( return new ResolvedCombinableArbitrary<>( rootProperty, - () -> new ObjectTree( - rootProperty, - builderContext.newTraverseContext() - ), + () -> { + ObjectTree objectTree = new ObjectTree( + rootProperty, + builderContext.newTraverseContext() + ); + + fixtureMonkeyOptions.getBuilderContextInitializers().stream() + .filter(it -> it.match(new DefaultTreeMatcherMetadata(objectTree.getMetadata().getAnnotations()))) + .findFirst() + .map(TreeMatcherOperator::getOperator) + .ifPresent(it -> builderContext.setOptionValidOnly(it.isValidOnly())); + + return objectTree; + }, objectTree -> { List registeredManipulators = monkeyManipulatorFactory.newRegisteredArbitraryManipulators( @@ -86,7 +98,7 @@ public CombinableArbitrary resolve( }, fixtureMonkeyOptions.getGenerateMaxTries(), fixtureMonkeyOptions.getDefaultArbitraryValidator(), - builderContext.isValidOnly() + builderContext::isValidOnly ); } } diff --git a/fixture-monkey/src/main/java/com/navercorp/fixturemonkey/resolver/ResolvedCombinableArbitrary.java b/fixture-monkey/src/main/java/com/navercorp/fixturemonkey/resolver/ResolvedCombinableArbitrary.java index 1d9a0c50a..85d08d940 100644 --- a/fixture-monkey/src/main/java/com/navercorp/fixturemonkey/resolver/ResolvedCombinableArbitrary.java +++ b/fixture-monkey/src/main/java/com/navercorp/fixturemonkey/resolver/ResolvedCombinableArbitrary.java @@ -43,7 +43,7 @@ final class ResolvedCombinableArbitrary implements CombinableArbitrary { private final int generateMaxTries; private final LazyArbitrary> arbitrary; private final ArbitraryValidator validator; - private final boolean validOnly; + private final Supplier validOnly; private Exception lastException = null; @@ -53,7 +53,7 @@ public ResolvedCombinableArbitrary( Function> generateArbitrary, int generateMaxTries, ArbitraryValidator validator, - boolean validOnly + Supplier validOnly ) { this.rootProperty = rootProperty; this.objectTree = LazyArbitrary.lazy(regenerateTree); @@ -73,7 +73,7 @@ public T combined() { for (int i = 0; i < generateMaxTries; i++) { try { return arbitrary.getValue() - .filter(VALIDATION_ANNOTATION_FILTERING_COUNT, this.validateFilter(validOnly)) + .filter(VALIDATION_ANNOTATION_FILTERING_COUNT, this.validateFilter(validOnly.get())) .combined(); } catch (ContainerSizeFilterMissException | RetryableFilterMissException ex) { lastException = ex; @@ -100,7 +100,7 @@ public Object rawValue() { for (int i = 0; i < generateMaxTries; i++) { try { return arbitrary.getValue() - .filter(VALIDATION_ANNOTATION_FILTERING_COUNT, this.validateFilter(validOnly)) + .filter(VALIDATION_ANNOTATION_FILTERING_COUNT, this.validateFilter(validOnly.get())) .rawValue(); } catch (ContainerSizeFilterMissException | RetryableFilterMissException ex) { lastException = ex; diff --git a/fixture-monkey/src/main/java/com/navercorp/fixturemonkey/tree/MetadataCollector.java b/fixture-monkey/src/main/java/com/navercorp/fixturemonkey/tree/MetadataCollector.java index 003bf43b0..2d7904ee4 100644 --- a/fixture-monkey/src/main/java/com/navercorp/fixturemonkey/tree/MetadataCollector.java +++ b/fixture-monkey/src/main/java/com/navercorp/fixturemonkey/tree/MetadataCollector.java @@ -18,10 +18,13 @@ package com.navercorp.fixturemonkey.tree; +import java.lang.annotation.Annotation; import java.util.Collections; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -34,21 +37,27 @@ final class MetadataCollector { private final ObjectNode rootNode; private final Map> nodesByProperty; + private final Set annotations; public MetadataCollector(ObjectNode rootNode) { this.rootNode = rootNode; this.nodesByProperty = new LinkedHashMap<>(); + this.annotations = new HashSet<>(); } public ObjectTreeMetadata collect() { for (ObjectNode child : rootNode.resolveChildren()) { collect(child); } - return new ObjectTreeMetadata(Collections.unmodifiableMap(nodesByProperty)); + return new ObjectTreeMetadata( + Collections.unmodifiableMap(nodesByProperty), + Collections.unmodifiableSet(annotations) + ); } private void collect(ObjectNode node) { Property property = node.getTreeProperty().getObjectProperty().getProperty(); + annotations.addAll(property.getAnnotations()); List children = node.resolveChildren(); for (ObjectNode child : children) { diff --git a/fixture-monkey/src/main/java/com/navercorp/fixturemonkey/tree/ObjectTreeMetadata.java b/fixture-monkey/src/main/java/com/navercorp/fixturemonkey/tree/ObjectTreeMetadata.java index 4d04c5fa6..1d5cf56f3 100644 --- a/fixture-monkey/src/main/java/com/navercorp/fixturemonkey/tree/ObjectTreeMetadata.java +++ b/fixture-monkey/src/main/java/com/navercorp/fixturemonkey/tree/ObjectTreeMetadata.java @@ -18,23 +18,31 @@ package com.navercorp.fixturemonkey.tree; +import java.lang.annotation.Annotation; import java.util.List; import java.util.Map; +import java.util.Set; import org.apiguardian.api.API; import org.apiguardian.api.API.Status; import com.navercorp.fixturemonkey.api.property.Property; -@API(since = "0.4.0", status = Status.MAINTAINED) +@API(since = "0.4.0", status = Status.INTERNAL) public final class ObjectTreeMetadata { private final Map> nodesByProperty; // matchOperator + private final Set annotations; - public ObjectTreeMetadata(Map> nodesByProperty) { + public ObjectTreeMetadata(Map> nodesByProperty, Set annotations) { this.nodesByProperty = nodesByProperty; + this.annotations = annotations; } public Map> getNodesByProperty() { return nodesByProperty; } + + public Set getAnnotations() { + return annotations; + } } diff --git a/fixture-monkey/src/main/java/com/navercorp/fixturemonkey/tree/TraverseContext.java b/fixture-monkey/src/main/java/com/navercorp/fixturemonkey/tree/TraverseContext.java index e1213e7a1..a8d20a354 100644 --- a/fixture-monkey/src/main/java/com/navercorp/fixturemonkey/tree/TraverseContext.java +++ b/fixture-monkey/src/main/java/com/navercorp/fixturemonkey/tree/TraverseContext.java @@ -22,6 +22,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.function.Supplier; import java.util.stream.Collectors; import javax.annotation.Nullable; @@ -56,7 +57,7 @@ public final class TraverseContext { private final List>> registeredContainerInfoManipulators; private final Map, List> propertyConfigurers; private final Map, ArbitraryIntrospector> arbitraryIntrospectorConfigurer; - private final boolean validOnly; + private final Supplier validOnly; private final MonkeyContext monkeyContext; public TraverseContext( @@ -65,7 +66,7 @@ public TraverseContext( List>> registeredContainerInfoManipulators, Map, List> propertyConfigurers, Map, ArbitraryIntrospector> arbitraryIntrospectorConfigurer, - boolean validOnly, + Supplier validOnly, MonkeyContext monkeyContext ) { this.treeProperties = treeProperties; @@ -99,7 +100,7 @@ public Map, ArbitraryIntrospector> getArbitraryIntrospectorConfigurer() } public boolean isValidOnly() { - return validOnly; + return validOnly.get(); } public MonkeyContext getMonkeyContext() {