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

W-17475148: Simple type params handler not handling certain expression param values (#14097) #14099

Merged
merged 2 commits into from
Dec 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,32 @@
*/
package org.mule.runtime.config.api.dsl.model;

import static java.util.Optional.ofNullable;
import static org.mule.runtime.config.api.dsl.model.ComponentBuildingDefinitionRegistry.WrapperElementType.COLLECTION;
import static org.mule.runtime.config.api.dsl.model.ComponentBuildingDefinitionRegistry.WrapperElementType.MAP;
import static org.mule.runtime.config.api.dsl.model.ComponentBuildingDefinitionRegistry.WrapperElementType.SINGLE;
import static org.mule.runtime.config.internal.dsl.utils.DslConstants.CORE_PREFIX;

import static java.util.Collections.emptyList;
import static java.util.Objects.requireNonNullElse;
import static java.util.Optional.empty;
import static java.util.Optional.ofNullable;

import org.mule.runtime.api.component.ComponentIdentifier;
import org.mule.runtime.config.api.dsl.processor.AbstractAttributeDefinitionVisitor;
import org.mule.runtime.dsl.api.component.AttributeDefinition;
import org.mule.runtime.dsl.api.component.ComponentBuildingDefinition;
import org.mule.runtime.dsl.api.component.ComponentBuildingDefinitionProvider;
import org.mule.runtime.dsl.api.component.KeyAttributeDefinitionPair;
import org.mule.runtime.dsl.api.component.SetterAttributeDefinition;

import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Deque;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Predicate;

/**
* Registry with all {@link ComponentBuildingDefinition} that where discovered in the classpath.
Expand All @@ -35,7 +44,7 @@
@Deprecated
public final class ComponentBuildingDefinitionRegistry {

private final Map<ComponentIdentifier, ComponentBuildingDefinition<?>> builderDefinitionsMap = new HashMap<>();
private final Map<ComponentIdentifier, Deque<ComponentBuildingDefinition<?>>> builderDefinitionsMap = new HashMap<>();
private final Map<String, WrapperElementType> wrapperIdentifierAndTypeMap = new HashMap<>();

/**
Expand All @@ -44,7 +53,11 @@ public final class ComponentBuildingDefinitionRegistry {
* @param builderDefinition definition to be added in the registry
*/
public void register(ComponentBuildingDefinition<?> builderDefinition) {
builderDefinitionsMap.put(builderDefinition.getComponentIdentifier(), builderDefinition);
builderDefinitionsMap.computeIfAbsent(builderDefinition.getComponentIdentifier(),
// Use a stack structure so the order is consistent across executions
// and keep the behavior that the last element to be added takes precedence
k -> new ArrayDeque<>())
.push(builderDefinition);
wrapperIdentifierAndTypeMap.putAll(getWrapperIdentifierAndTypeMap(builderDefinition));
}

Expand All @@ -55,7 +68,28 @@ public void register(ComponentBuildingDefinition<?> builderDefinition) {
* @return the definition to build the component
*/
public Optional<ComponentBuildingDefinition<?>> getBuildingDefinition(ComponentIdentifier identifier) {
return ofNullable(builderDefinitionsMap.get(identifier));
final Deque<ComponentBuildingDefinition<?>> definitions = builderDefinitionsMap.get(identifier);
return definitions == null
? empty()
: ofNullable(definitions.peek());
}

/**
* Lookups a {@code ComponentBuildingDefinition} for a certain configuration component and a certain condition.
*
* @param identifier the component identifier
* @param condition how to determine which of the available definitions to use
* @return the definition to build the component
*/
public Optional<ComponentBuildingDefinition<?>> getBuildingDefinition(ComponentIdentifier identifier,
Predicate<ComponentBuildingDefinition<?>> condition) {
final Collection<ComponentBuildingDefinition<?>> buildingDefinitions =
requireNonNullElse(builderDefinitionsMap.get(identifier),
emptyList());
return buildingDefinitions
.stream()
.filter(condition)
.findFirst();
}

/**
Expand Down Expand Up @@ -109,7 +143,7 @@ public void onMultipleValues(KeyAttributeDefinitionPair[] definitions) {
Consumer<AttributeDefinition> collectWrappersConsumer =
attributeDefinition -> attributeDefinition.accept(wrapperIdentifiersCollector);
buildingDefinition.getSetterParameterDefinitions().stream()
.map(setterAttributeDefinition -> setterAttributeDefinition.getAttributeDefinition())
.map(SetterAttributeDefinition::getAttributeDefinition)
.forEach(collectWrappersConsumer);
buildingDefinition.getConstructorAttributeDefinition().stream().forEach(collectWrappersConsumer);
return wrapperIdentifierAndTypeMap;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@
*/
package org.mule.runtime.config.internal.dsl.spring;

import static org.mule.runtime.api.i18n.I18nMessageFactory.createStaticMessage;

import static org.springframework.beans.factory.support.BeanDefinitionBuilder.genericBeanDefinition;

import org.mule.runtime.api.exception.MuleRuntimeException;
import org.mule.runtime.ast.api.ComponentAst;
import org.mule.runtime.config.internal.dsl.model.SpringComponentModel;
import org.mule.runtime.config.internal.factories.ConstantFactoryBean;
Expand Down Expand Up @@ -41,8 +44,12 @@ public void setNext(BeanDefinitionCreator<R> nextBeanDefinitionCreator) {
* @param request
*/
public final void processRequest(Map<ComponentAst, SpringComponentModel> springComponentModels, R request) {
if (handleRequest(springComponentModels, request)) {
return;
try {
if (handleRequest(springComponentModels, request)) {
return;
}
} catch (Exception e) {
throw new MuleRuntimeException(createStaticMessage("Exception processing " + request.toString()), e);
}
if (next != null) {
next.processRequest(springComponentModels, request);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
import static org.mule.runtime.config.api.properties.PropertiesResolverUtils.loadProviderFactories;
import static org.mule.runtime.config.internal.dsl.XmlConstants.buildRawParamKeyForDocAttribute;
import static org.mule.runtime.config.internal.dsl.spring.ComponentModelHelper.addAnnotation;
import static org.mule.runtime.config.internal.dsl.utils.DslConstants.CORE_PREFIX;
import static org.mule.runtime.config.internal.dsl.utils.DslConstants.NAME_ATTRIBUTE_NAME;
import static org.mule.runtime.config.internal.model.ApplicationModel.ANNOTATIONS_ELEMENT_IDENTIFIER;
import static org.mule.runtime.config.internal.model.ApplicationModel.DESCRIPTION_IDENTIFIER;
import static org.mule.runtime.config.internal.model.ApplicationModel.DOC_DESCRIPTION_IDENTIFIER;
Expand All @@ -30,8 +32,6 @@
import static org.mule.runtime.extension.api.util.ExtensionMetadataTypeUtils.isMap;
import static org.mule.runtime.extension.api.util.ExtensionModelUtils.isContent;
import static org.mule.runtime.extension.api.util.ExtensionModelUtils.isText;
import static org.mule.runtime.config.internal.dsl.utils.DslConstants.CORE_PREFIX;
import static org.mule.runtime.config.internal.dsl.utils.DslConstants.NAME_ATTRIBUTE_NAME;

import static java.lang.Class.forName;
import static java.util.Collections.emptyList;
Expand Down Expand Up @@ -63,6 +63,8 @@
import org.mule.runtime.config.internal.context.SpringConfigurationComponentLocator;
import org.mule.runtime.config.internal.dsl.model.SpringComponentModel;
import org.mule.runtime.dsl.api.component.ComponentBuildingDefinition;
import org.mule.runtime.dsl.api.component.TypeDefinition.MapEntryType;
import org.mule.runtime.dsl.api.component.TypeDefinitionVisitor;
import org.mule.runtime.extension.api.property.NoWrapperModelProperty;

import java.util.ArrayList;
Expand Down Expand Up @@ -205,7 +207,8 @@ public void resolveComponent(Map<ComponentAst, SpringComponentModel> springCompo
resolveComponentBeanDefinition(springComponentModels, componentHierarchy, component,
paramsModels, registry, componentLocator,
nestedComp -> resolveComponent(springComponentModels, nestedHierarchy, nestedComp,
registry, componentLocator));
registry, componentLocator),
false);
}

private List<SpringComponentModel> resolveParameterGroup(Map<ComponentAst, SpringComponentModel> springComponentModels,
Expand Down Expand Up @@ -272,20 +275,21 @@ private List<SpringComponentModel> resolveParamBeanDefinitionFixedValue(Map<Comp
AtomicReference<SpringComponentModel> model = new AtomicReference<>();
param.getModel().getType().accept(new MetadataTypeVisitor() {

protected void visitMultipleChildren(List<Object> values) {
protected void visitMultipleChildren(List<Object> values, boolean mapType) {
final List<ComponentAst> updatedHierarchy = new ArrayList<>(componentHierarchy);
updatedHierarchy.add(paramOwnerComponent);

if (values != null) {
values.stream()
.filter(child -> child instanceof ComponentAst)
.filter(ComponentAst.class::isInstance)
.forEach(child -> resolveComponentBeanDefinition(springComponentModels, updatedHierarchy, (ComponentAst) child,
emptyList(),
registry, componentLocator,
nestedComp -> resolveComponent(springComponentModels,
updatedHierarchy,
nestedComp, registry,
componentLocator)));
componentLocator),
mapType));
}

resolveComponentBeanDefinitionComplexParam(springComponentModels, updatedHierarchy, paramOwnerComponent, param,
Expand All @@ -299,7 +303,7 @@ protected void visitMultipleChildren(List<Object> values) {
public void visitArrayType(ArrayType arrayType) {
final Object complexValue = param.getValue().getRight();
if (complexValue instanceof List) {
visitMultipleChildren((List) complexValue);
visitMultipleChildren((List) complexValue, false);
} else {
// references to a list defined elsewhere
resolveParamBeanDefinitionSimpleType(springComponentModels, componentHierarchy, paramOwnerComponent, param, registry,
Expand All @@ -314,7 +318,7 @@ public void visitObject(ObjectType objectType) {

if (isMap(objectType)) {
if (complexValue instanceof List) {
visitMultipleChildren((List) complexValue);
visitMultipleChildren((List) complexValue, true);
} else {
// references to a map defined elsewhere
resolveParamBeanDefinitionSimpleType(springComponentModels, componentHierarchy, paramOwnerComponent, param, registry,
Expand All @@ -327,9 +331,7 @@ public void visitObject(ObjectType objectType) {
final List<ComponentAst> updatedHierarchy = new ArrayList<>(componentHierarchy);
updatedHierarchy.add(paramOwnerComponent);

if (complexValue instanceof ComponentAst) {
final ComponentAst child = (ComponentAst) complexValue;

if (complexValue instanceof final ComponentAst child) {
List<SpringComponentModel> childParamsModels = new ArrayList<>();

child.getModel(ParameterizedModel.class)
Expand Down Expand Up @@ -400,13 +402,19 @@ private Optional<SpringComponentModel> resolveComponentBeanDefinition(Map<Compon
List<SpringComponentModel> paramsModels,
BeanDefinitionRegistry registry,
SpringConfigurationComponentLocator componentLocator,
Consumer<ComponentAst> nestedComponentParamProcessor) {
Consumer<ComponentAst> nestedComponentParamProcessor,
boolean parentMapType) {
Optional<ComponentBuildingDefinition<?>> buildingDefinitionOptional =
componentBuildingDefinitionRegistry.getBuildingDefinition(component.getIdentifier());
componentBuildingDefinitionRegistry.getBuildingDefinition(component.getIdentifier(), bd -> {
final IsMapEntryTypeVisitor isMapEntryTypeVisitor = new IsMapEntryTypeVisitor();
bd.getTypeDefinition().visit(isMapEntryTypeVisitor);
return parentMapType == isMapEntryTypeVisitor.isMapType();
});
if (buildingDefinitionOptional.isPresent() || customBuildersComponentIdentifiers.contains(component.getIdentifier())) {
final CreateComponentBeanDefinitionRequest request =
new CreateComponentBeanDefinitionRequest(componentHierarchy, component, paramsModels,
buildingDefinitionOptional.orElse(null), nestedComponentParamProcessor);
buildingDefinitionOptional.orElse(null), nestedComponentParamProcessor,
parentMapType);

this.componentProcessor.processRequest(springComponentModels, request);
handleSpringComponentModel(request.getSpringComponentModel(), springComponentModels, registry, componentLocator);
Expand All @@ -416,6 +424,29 @@ private Optional<SpringComponentModel> resolveComponentBeanDefinition(Map<Compon
}
}

private static final class IsMapEntryTypeVisitor implements TypeDefinitionVisitor {

private boolean mapType;

@Override
public void onType(Class<?> type) {}

@Override
public void onMapType(MapEntryType mapEntryType) {
this.mapType = true;
}

@Override
public void onConfigurationAttribute(String groupName, String attributeName, Class<?> enforcedClass) {}

@Override
public void onConfigurationAttribute(String attributeName, Class<?> enforcedClass) {}

public boolean isMapType() {
return mapType;
}
}

private Optional<SpringComponentModel> resolveComponentBeanDefinitionComplexParam(Map<ComponentAst, SpringComponentModel> springComponentModels,
List<ComponentAst> componentHierarchy,
ComponentAst paramOwnerComponent,
Expand Down Expand Up @@ -473,8 +504,7 @@ private ComponentIdentifier getParamValueComponentIdentifier(final ComponentPara
final ComponentIdentifier paramComponentIdentifier) {
if (param.getValue().getValue().isPresent()) {
Object valueObject = param.getValue().getValue().get();
if (valueObject instanceof ComponentAst) {
ComponentAst valueAst = (ComponentAst) valueObject;
if (valueObject instanceof ComponentAst valueAst) {
return valueAst.getIdentifier();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,17 @@
public class CreateComponentBeanDefinitionRequest extends CreateBeanDefinitionRequest {

private final Consumer<ComponentAst> nestedComponentParamProcessor;
private final boolean parentMapType;

public CreateComponentBeanDefinitionRequest(List<ComponentAst> componentHierarchy,
ComponentAst component,
List<SpringComponentModel> paramsModels,
ComponentBuildingDefinition componentBuildingDefinition,
Consumer<ComponentAst> nestedComponentParamProcessor) {
Consumer<ComponentAst> nestedComponentParamProcessor,
boolean parentMapType) {
super(componentHierarchy, component, paramsModels, componentBuildingDefinition, component.getIdentifier());
this.nestedComponentParamProcessor = nestedComponentParamProcessor;
this.parentMapType = parentMapType;
}

@Override
Expand All @@ -34,4 +37,13 @@ public ComponentAst resolveConfigurationComponent() {
public Consumer<ComponentAst> getNestedComponentParamProcessor() {
return nestedComponentParamProcessor;
}

public boolean isParentMapType() {
return parentMapType;
}

@Override
public String toString() {
return "component request for `" + getComponent().toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,11 @@ public ParameterGroupModel getParamGroupModel() {
public ComponentParameterAst getParameter(String parameterName) {
return paramOwnerComponent.getParameter(paramGroupModel.getName(), parameterName);
}

@Override
public String toString() {
return "DSL param group request for `"
+ getParamGroupModel().getName() + "` in component `"
+ getParamOwnerComponent().toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,12 @@ public ComponentParameterAst getParameter(String parameterName) {
.findFirst()
.orElse(null);
}

@Override
public String toString() {
return "param request for `"
+ getParam().getGroupModel().getName() + "."
+ getParam().getModel().getName() + "` in component `"
+ getParamOwnerComponent().toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
*/
package org.mule.runtime.config.internal.dsl.spring;

import static java.util.stream.Collectors.toCollection;
import static org.mule.runtime.api.meta.model.parameter.ParameterGroupModel.DEFAULT_GROUP_NAME;
import static org.mule.runtime.config.internal.dsl.processor.ObjectTypeVisitor.DEFAULT_COLLECTION_TYPE;
import static org.mule.runtime.dsl.api.component.DslSimpleType.SIMPLE_TYPE_VALUE_PARAMETER_NAME;

import static java.util.stream.Collectors.toCollection;

import static org.springframework.beans.factory.support.BeanDefinitionBuilder.genericBeanDefinition;

import org.mule.runtime.ast.api.ComponentAst;
Expand Down Expand Up @@ -61,11 +63,16 @@ class MapEntryBeanDefinitionCreator extends BeanDefinitionCreator<CreateComponen
@Override
boolean handleRequest(Map<ComponentAst, SpringComponentModel> springComponentModels,
CreateComponentBeanDefinitionRequest request) {
if (!request.isParentMapType()) {
return false;
}

ComponentAst component = request.getComponent();
Class<?> type = request.getSpringComponentModel().getType();
if (!(MapEntryType.class.isAssignableFrom(type))) {
return false;
}

ComponentBuildingDefinition componentBuildingDefinition = request.getComponentBuildingDefinition();
request.getSpringComponentModel().setType(type);
final String key = component.getParameter(DEFAULT_GROUP_NAME, ENTRY_TYPE_KEY_PARAMETER_NAME).getResolvedRawValue();
Expand Down
Loading