Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement a Matcher interface to manage ArbitraryBuilders with a single variable #1062

Merged
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@
public interface Matcher {
boolean match(Property property);

default boolean match(Property property, MatcherMetadata<?> matcherMetadata) {
return match(property);
}

/**
* Creates and returns a new {@code Matcher} that represents the intersection
* of this matcher with another specified matcher. The resulting matcher will
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* 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;

public interface MatcherMetadata<T> {
T getMetadataInfo();
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

제네릭을 사용하는 것보다 스프링에 있는 AnnotatedTypeMetadata처럼 구현하는 방향이 어떨까 싶습니다.
당장 필요한 정보는 name이므로 String getName() 메서드를 추가하는 건 어떨까요?

https://github.com/spring-projects/spring-framework/blob/a3b979c5ecb7eda96ebf264672ce522177c6fc77/spring-core/src/main/java/org/springframework/core/type/AnnotatedTypeMetadata.java#L54

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵!
추후에 필요한 정보가 더 생기면 확장성을 고려해서 리팩토링 하겠습니다 :)

Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ public static <T, C> MatcherOperator<T> assignableTypeMatchOperator(Class<C> typ
return new MatcherOperator<>(new AssignableTypeMatcher(type), operator);
}

@Override
public boolean match(Property property, MatcherMetadata<?> matcherMetadata) {
return this.matcher.match(property, matcherMetadata);
}

@Override
public boolean match(Property property) {
return this.matcher.match(property);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.navercorp.fixturemonkey.api.matcher;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

라이센스를 추가하면 좋을 것 같습니다.

/*
 * 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.
 */

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵! 수정하겠습니다.


import com.navercorp.fixturemonkey.api.property.Property;

public final class NamedMatcher implements Matcher {
private final Matcher matcher;
private final String registeredName;

public NamedMatcher(Matcher matcher, String registeredName) {
this.matcher = matcher;
this.registeredName = registeredName;
}

public boolean matchRegisteredName(String registeredName) {
return this.registeredName.equals(registeredName);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이건 없어져도 될 것 같습니다.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵! 삭제하도록 하겠습니다.


@Override
public boolean match(Property property) {
return this.matcher.match(property);
}

@Override
public boolean match(Property property, MatcherMetadata<?> matcherMetadata) {
return this.matcher.match(property) && registeredName.equals(matcherMetadata.getMetadataInfo());
}
}
Original file line number Diff line number Diff line change
@@ -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 javax.annotation.Nullable;

public class NamedMatcherMetadata<T> implements MatcherMetadata<T> {
private final T medataInfo;

public NamedMatcherMetadata(@Nullable T medataInfo) {
this.medataInfo = medataInfo;
}

public static <T> NamedMatcherMetadata<T> empty() {
return new NamedMatcherMetadata<>(null);
}

@Override
public T getMetadataInfo() {
return medataInfo;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import static java.util.stream.Collectors.toList;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
Expand All @@ -34,6 +33,7 @@

import com.navercorp.fixturemonkey.api.context.MonkeyContext;
import com.navercorp.fixturemonkey.api.matcher.MatcherOperator;
import com.navercorp.fixturemonkey.api.matcher.NamedMatcher;
import com.navercorp.fixturemonkey.api.option.FixtureMonkeyOptions;
import com.navercorp.fixturemonkey.api.property.RootProperty;
import com.navercorp.fixturemonkey.api.type.LazyAnnotatedType;
Expand All @@ -55,8 +55,6 @@ public final class FixtureMonkey {
private final MonkeyContext monkeyContext;
private final List<MatcherOperator<? extends ArbitraryBuilder<?>>> registeredArbitraryBuilders = new ArrayList<>();
private final MonkeyManipulatorFactory monkeyManipulatorFactory;
private final Map<String, MatcherOperator<? extends ArbitraryBuilder<?>>>
namedArbitraryBuilderMap = new HashMap<>();

public FixtureMonkey(
FixtureMonkeyOptions fixtureMonkeyOptions,
Expand Down Expand Up @@ -116,7 +114,6 @@ public <T> ArbitraryBuilder<T> giveMeBuilder(TypeReference<T> type) {
monkeyManipulatorFactory,
builderContext.copy(),
registeredArbitraryBuilders,
namedArbitraryBuilderMap,
monkeyContext,
manipulatorOptimizer,
fixtureMonkeyOptions.getInstantiatorProcessor()
Expand Down Expand Up @@ -145,7 +142,6 @@ public <T> ArbitraryBuilder<T> giveMeBuilder(T value) {
monkeyManipulatorFactory,
context,
registeredArbitraryBuilders,
namedArbitraryBuilderMap,
monkeyContext,
manipulatorOptimizer,
fixtureMonkeyOptions.getInstantiatorProcessor()
Expand Down Expand Up @@ -208,9 +204,12 @@ private void initializeRegisteredArbitraryBuilders(
private void initializeNamedArbitraryBuilderMap(
Map<String, MatcherOperator<Function<FixtureMonkey, ? extends ArbitraryBuilder<?>>>> mapsByRegisteredName
) {
mapsByRegisteredName.forEach((name, matcherOperator) -> {
namedArbitraryBuilderMap.put(
name, new MatcherOperator<>(matcherOperator.getMatcher(), matcherOperator.getOperator().apply(this))
mapsByRegisteredName.forEach((registeredName, matcherOperator) -> {
registeredArbitraryBuilders.add(
new MatcherOperator<>(
new NamedMatcher(matcherOperator.getMatcher(), registeredName),
matcherOperator.getOperator().apply(this)
)
);
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import com.navercorp.fixturemonkey.api.generator.ArbitraryContainerInfo;
import com.navercorp.fixturemonkey.api.lazy.LazyArbitrary;
import com.navercorp.fixturemonkey.api.matcher.MatcherOperator;
import com.navercorp.fixturemonkey.api.matcher.NamedMatcherMetadata;
import com.navercorp.fixturemonkey.api.property.Property;
import com.navercorp.fixturemonkey.customizer.InnerSpecState.ManipulatorHolderSet;
import com.navercorp.fixturemonkey.customizer.Values.Just;
Expand Down Expand Up @@ -142,7 +143,8 @@ public ContainerInfoManipulator newContainerInfoManipulator(

public List<ArbitraryManipulator> newRegisteredArbitraryManipulators(
List<MatcherOperator<? extends ArbitraryBuilder<?>>> registeredArbitraryBuilders,
Map<Property, List<ObjectNode>> nodesByType
Map<Property, List<ObjectNode>> nodesByType,
ArbitraryBuilderContext builderContext
) {
List<ArbitraryManipulator> manipulators = new ArrayList<>();

Expand All @@ -152,7 +154,14 @@ public List<ArbitraryManipulator> newRegisteredArbitraryManipulators(

DefaultArbitraryBuilder<?> registeredArbitraryBuilder =
(DefaultArbitraryBuilder<?>)registeredArbitraryBuilders.stream()
.filter(it -> it.match(property))
.filter(it -> {
if (builderContext.getSelectedNames().isEmpty()) {
return it.match(property, NamedMatcherMetadata::empty);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it.match(property, NamedMatcherMetadata::empty대신 it.match(property)로 사용해도 되지 않나요??

Copy link
Author

@YongGoose YongGoose Nov 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it.match(property, NamedMatcherMetadata::empty대신 it.match(property)로 사용해도 되지 않나요??

이렇게 진행을 하면 registeredName API를 통해 register 연산을 등록한 후, selectName을 호출하지 않았는데도 적용이 되는 사이드 이펙트가 발생할 것 같습니다.

실제로 실행을 시켜본 결과 하기와 같은 테스트 코드가 성공함을 확인했습니다.

registeredName API를 초기 설계할 때 선택된 이름만 적용이 되도록 설계를 해서 위와 같은 경우는 적용이 되면 안 되는 경우라고 생각합니다.

@Property
void registeredNameWithNoSelectName() {
	FixtureMonkey sut = FixtureMonkey.builder()
		.registeredName(
			"test",
			String.class,
			monkey -> monkey.giveMeBuilder("test")
		)
		.build();

	SimpleObject actual = sut.giveMeBuilder(SimpleObject.class)
		// .selectName("test")
		.sample();

	then(actual.getStr()).isEqualTo("test");
}

Copy link
Contributor

@seongahjo seongahjo Nov 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

registeredName API를 초기 설계할 때 선택된 이름만 적용이 되도록 설계를 해서 위와 같은 경우는 적용이 되면 안 되는 경우라고 생각합니다.

registeredName도 register인 만큼 랜덤하게 선택된다고 생각했는데 아니었군요.
registeredName가 selectName으로만 동작한다면 너무 제한적이라고 생각하는데 어떻게 생각하시나요?? 어떤 시나리오에서 registeredName을 사용할지 아직은 잘 모르겠습니다. 말씀하신 초기 설계에서 registeredName와 InnerSpec이 어떤 게 다른지 잘 모르겠습니다.

이해하기 쉬운 주문 도메인을 구현한다고 가정했을 때, 제가 생각하는 시나리오는 아래와 같습니다.

옵션
registerdName("배송이 있는 주문", ...);
registerdName("배송이 없는 주문", ...);

주문을 생성할 때마다 위에 두 register로 등록한 연산 셋 중 하나를 선택해서 생성합니다.
테스트 케이스에서 배송이 있는 주문만 필요할 경우 selectName으로 선택합니다.

Copy link
Author

@YongGoose YongGoose Nov 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고민해보니, 성아님의 말씀대로 현재 설계가 InnerSpec과 크게 다르지 않은 것 같습니다.
초기에는 선택이라는 요소에 집중하여 설계를 진행하다 보니, 제한적인 구조가 된 것 같습니다.😅

성아님의 의견에 전적으로 동의를 하는데 한 가지 궁금한 점이 있습니다.

registeredName도 register인 만큼 랜덤하게 선택된다고 생각했는데 아니었군요.

현재 registeredName은 selectName이 없는 경우 가장 먼저 호출된 registeredName이 적용되는 구조입니다.
성아님께서 registeredName도 랜덤하게 선택된다고 하셨는데 조금만 추가 설명 부탁드립니다..!

  • 어떤 것을 랜덤하게 선택하려고 의도하셨는지 궁금합니다! (랜덤적인 요소가 들어가면 저도 좋을 것 같다고 생각합니다!!)

그리고 제 개인적인 생각인데 JUnit의 order와 같이 register 연산을 등록할 때 순서를 부여하는 것도 괜찮을 것 같습니다.


현재 registeredName은 selectName이 없는 경우 가장 먼저 호출된 registeredName이 적용되는 구조입니다. (동일한 클래스 인 경우)

코드와 함께 추가 설명을 하자면, 하기의 코드와 같이 String이라는 클래스에 대해 register 연산이 여러 개 등록된 경우 가장 먼저 등록된 배송이 있는 주문이 선택 됩니다.

@Property
void registeredNameRandomly() {
	FixtureMonkey sut = FixtureMonkey.builder()
		.registeredName(
			"배송이 있는 주문",
			String.class,
			monkey -> monkey.giveMeBuilder("exists")
		)
		.registeredName(
			"배송이 없는 주문",
			String.class,
			monkey -> monkey.giveMeBuilder("not exist")
		)
		.registeredName(
			"배송이 취소된 주문",
			String.class,
			monkey -> monkey.giveMeBuilder("cancelled")
		)
		.registeredName(
			"배송이 연기된 주문",
			Integer.class,
			monkey -> monkey.giveMeBuilder(20241102)
		)
		.build();

	SimpleObject actual = sut.giveMeBuilder(SimpleObject.class)
		.sample();

	then(actual.getStr()).isEqualTo("exists");
	then(actual.getWrapperInteger()).isEqualTo(20241102);
}

Copy link
Contributor

@seongahjo seongahjo Nov 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

성아님께서 registeredName도 랜덤하게 선택된다고 하셨는데 조금만 추가 설명 부탁드립니다..!
코드와 함께 추가 설명을 하자면, 하기의 코드와 같이 String이라는 클래스에 대해 register 연산이 여러 개 등록된 경우 가장 먼저 등록된 배송이 있는 주문이 선택 됩니다.

`첫 번째로 등록한 연산을 적용하는 것보다 적용할 regiserGroup을 임의로 (arbitrary) 정하는 방향을 생각했습니다.
name을 지정하지 않으면 지정한 그룹 중 임의의 그룹이 와도 테스트를 통과해야 한다고 생각했습니다.

만약 통과하지 못한다면 다음 두 가지 경우일 것이라고 생각합니다.

  1. registerGroup가 해당 객체가 가져야 하는 기본 형태를 나타내지 못했다. ex. 매우 지엽적인 케이스를 registerGroup으로 설정함.
  2. 로직이 일관성을 제공하지 못했으므로 생각하지 못한 엣지 케이스가 있을 수 있다.

그리고 제 개인적인 생각인데 JUnit의 order와 같이 register 연산을 등록할 때 순서를 부여하는 것도 괜찮을 것 같습니다.
우선순위가 있는 것도 좋을 것 같은데, 다음 PR에서 고민해보면 어떨까 싶네요.
어떻게 입력받을지 고민해보면 좋을 것 같습니다.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

첫 번째로 등록한 연산을 적용하는 것보다 적용할 regiserGroup을 임의로 (arbitrary) 정하는 방향을 생각했습니다.

이번 PR의 목적은 ArbitraryBuilder를 관리하는 부분을 리팩토링하는 것이므로, 이번 PR과는 내용이 어울리지 않다고 생각합니다!
그래서 우선순위 기능과 같이 다음 PR에서 진행해도 괜찮을까요?

우선순위가 있는 것도 좋을 것 같은데, 다음 PR에서 고민해보면 어떨까 싶네요.
어떻게 입력받을지 고민해보면 좋을 것 같습니다.

넵! 성아님께서 괜찮으시다면 연산을 임의로 선택하는 것과 함께 고민해보겠습니다 :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵 다음 PR에서 진행하시죠 👍

return builderContext.getSelectedNames().stream().anyMatch(
name -> it.match(property, new NamedMatcherMetadata<>(name))
);
})
.findFirst()
.map(MatcherOperator::getOperator)
.filter(it -> it instanceof DefaultArbitraryBuilder<?>)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
public final class ArbitraryBuilderContext {
private final List<ArbitraryManipulator> manipulators;
private final List<ContainerInfoManipulator> containerInfoManipulators;
private final List<String> selectNames;
private final Map<Class<?>, List<Property>> propertyConfigurers;
private final Map<Class<?>, ArbitraryIntrospector> arbitraryIntrospectorsByType;
private boolean validOnly;
Expand All @@ -54,6 +55,7 @@ public final class ArbitraryBuilderContext {
public ArbitraryBuilderContext(
List<ArbitraryManipulator> manipulators,
List<ContainerInfoManipulator> containerInfoManipulators,
List<String> selectNames,
Map<Class<?>, List<Property>> propertyConfigurers,
Map<Class<?>, ArbitraryIntrospector> arbitraryIntrospectorsByType,
boolean validOnly,
Expand All @@ -62,6 +64,7 @@ public ArbitraryBuilderContext(
) {
this.manipulators = manipulators;
this.containerInfoManipulators = containerInfoManipulators;
this.selectNames = selectNames;
this.propertyConfigurers = propertyConfigurers;
this.arbitraryIntrospectorsByType = arbitraryIntrospectorsByType;
this.validOnly = validOnly;
Expand All @@ -71,7 +74,8 @@ public ArbitraryBuilderContext(

public ArbitraryBuilderContext() {
this(
new ArrayList<>(), new ArrayList<>(), new HashMap<>(), new HashMap<>(), true, null, null);
new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new HashMap<>(), new HashMap<>(), true, null, null
);
}

public ArbitraryBuilderContext copy() {
Expand All @@ -82,6 +86,7 @@ public ArbitraryBuilderContext copy() {
return new ArbitraryBuilderContext(
new ArrayList<>(this.manipulators),
copiedContainerInfoManipulators,
this.selectNames,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new ArrayList<>(this.selectNames)로 새로운 리스트를 할당하게 하는 게 좋을 것 같습니다.
selectNames의 변경이 copy()한 인스턴스까지 전파되지 않게 하는 게 좋을 것 같습니다.

new HashMap<>(propertyConfigurers),
new HashMap<>(arbitraryIntrospectorsByType),
this.validOnly,
Expand Down Expand Up @@ -114,6 +119,15 @@ public List<ContainerInfoManipulator> getContainerInfoManipulators() {
return Collections.unmodifiableList(containerInfoManipulators);
}

public void addSelectedNames(List<String> selectNames) {
this.selectNames.addAll(selectNames);
}

public List<String> getSelectedNames() {
return this.selectNames;
}


public void putPropertyConfigurer(Class<?> type, List<Property> propertyConfigurer) {
this.propertyConfigurers.put(type, propertyConfigurer);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ public CombinableArbitrary<?> resolve(
List<ArbitraryManipulator> registeredManipulators =
monkeyManipulatorFactory.newRegisteredArbitraryManipulators(
registeredArbitraryBuilders,
objectTree.getMetadata().getNodesByProperty()
objectTree.getMetadata().getNodesByProperty(),
builderContext
);

List<ArbitraryManipulator> joinedManipulators =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@
import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
Expand Down Expand Up @@ -59,6 +59,8 @@
import com.navercorp.fixturemonkey.api.instantiator.InstantiatorProcessor;
import com.navercorp.fixturemonkey.api.lazy.LazyArbitrary;
import com.navercorp.fixturemonkey.api.matcher.MatcherOperator;
import com.navercorp.fixturemonkey.api.matcher.NamedMatcher;
import com.navercorp.fixturemonkey.api.matcher.NamedMatcherMetadata;
import com.navercorp.fixturemonkey.api.option.FixtureMonkeyOptions;
import com.navercorp.fixturemonkey.api.property.PropertyNameResolver;
import com.navercorp.fixturemonkey.api.property.PropertySelector;
Expand Down Expand Up @@ -87,7 +89,6 @@ public final class DefaultArbitraryBuilder<T> implements ArbitraryBuilder<T>, Ex
private final ManipulatorOptimizer manipulatorOptimizer;
private final MonkeyContext monkeyContext;
private final InstantiatorProcessor instantiatorProcessor;
private final Map<String, MatcherOperator<? extends ArbitraryBuilder<?>>> namedArbitraryBuilderMap;

public DefaultArbitraryBuilder(
FixtureMonkeyOptions fixtureMonkeyOptions,
Expand All @@ -97,7 +98,6 @@ public DefaultArbitraryBuilder(
MonkeyManipulatorFactory monkeyManipulatorFactory,
ArbitraryBuilderContext context,
List<MatcherOperator<? extends ArbitraryBuilder<?>>> registeredArbitraryBuilders,
Map<String, MatcherOperator<? extends ArbitraryBuilder<?>>> registeredArbitraryBuildersByRegsiteredName,
MonkeyContext monkeyContext,
ManipulatorOptimizer manipulatorOptimizer,
InstantiatorProcessor instantiatorProcessor
Expand All @@ -109,7 +109,6 @@ public DefaultArbitraryBuilder(
this.context = context;
this.monkeyManipulatorFactory = monkeyManipulatorFactory;
this.registeredArbitraryBuilders = registeredArbitraryBuilders;
this.namedArbitraryBuilderMap = registeredArbitraryBuildersByRegsiteredName;
this.manipulatorOptimizer = manipulatorOptimizer;
this.monkeyContext = monkeyContext;
this.instantiatorProcessor = instantiatorProcessor;
Expand Down Expand Up @@ -185,28 +184,31 @@ public ArbitraryBuilder<T> setLazy(PropertySelector propertySelector, Supplier<?
);
}

@Override
public ArbitraryBuilder<T> selectName(String... names) {
List<MatcherOperator<? extends ArbitraryBuilder<?>>> registeredArbitraryBuildersCopy =
new ArrayList<>(this.registeredArbitraryBuilders);

for (String name : names) {
MatcherOperator<? extends ArbitraryBuilder<?>> namedArbitraryBuilder = namedArbitraryBuilderMap.get(name);

if (namedArbitraryBuilder == null) {
Stream.of(names).forEach(name -> {
boolean matched = registeredArbitraryBuilders.stream()
.map(MatcherOperator::getMatcher)
.filter(NamedMatcher.class::isInstance)
.map(NamedMatcher.class::cast)
.anyMatch(operator -> operator.matchRegisteredName(name));

if (!matched) {
throw new IllegalArgumentException("Given name is not registered. name: " + name);
}
registeredArbitraryBuildersCopy.add(namedArbitraryBuilder);
}
});

ArbitraryBuilderContext builderContext = registeredArbitraryBuildersCopy.stream()
.filter(it -> it.match(rootProperty))
ArbitraryBuilderContext builderContext = registeredArbitraryBuilders.stream()
.filter(operator -> Arrays.stream(names)
.anyMatch(name -> operator.match(rootProperty, new NamedMatcherMetadata<>(name)))
)
.map(MatcherOperator::getOperator)
.findAny()
.map(DefaultArbitraryBuilder.class::cast)
.map(DefaultArbitraryBuilder::getContext)
.orElse(new ArbitraryBuilderContext());

builderContext.addSelectedNames(Arrays.asList(names));

return new DefaultArbitraryBuilder<>(
this.fixtureMonkeyOptions,
this.rootProperty,
Expand All @@ -216,13 +218,12 @@ public ArbitraryBuilder<T> selectName(String... names) {
this.monkeyManipulatorFactory,
this.fixtureMonkeyOptions,
this.monkeyContext,
registeredArbitraryBuildersCopy
registeredArbitraryBuilders
),
this.traverser,
this.monkeyManipulatorFactory,
builderContext.copy(),
registeredArbitraryBuildersCopy,
this.namedArbitraryBuilderMap,
registeredArbitraryBuilders,
this.monkeyContext,
this.manipulatorOptimizer,
this.fixtureMonkeyOptions.getInstantiatorProcessor()
Expand Down Expand Up @@ -560,7 +561,6 @@ public ArbitraryBuilder<T> copy() {
monkeyManipulatorFactory,
context.copy(),
registeredArbitraryBuilders,
namedArbitraryBuilderMap,
monkeyContext,
manipulatorOptimizer,
instantiatorProcessor
Expand Down Expand Up @@ -612,7 +612,6 @@ private <R> DefaultArbitraryBuilder<R> generateArbitraryBuilderLazily(LazyArbitr
monkeyManipulatorFactory,
context,
registeredArbitraryBuilders,
namedArbitraryBuilderMap,
monkeyContext,
manipulatorOptimizer,
instantiatorProcessor
Expand Down