Skip to content

Commit

Permalink
W-17475148/W-17484538: Fix NPE in MapEntryBeanDefinitionCreator/MapBe…
Browse files Browse the repository at this point in the history
…anDefinitionCreator

* W-17475148: Simple type params handler not handling certain expression param values (#14097)
* W-17484538: Disambiguate colliding componentIds in ComponentBuildingDefinitionRegistry (#14105)
  • Loading branch information
elrodro83 authored Dec 23, 2024
1 parent c22fa44 commit 361e731
Show file tree
Hide file tree
Showing 11 changed files with 309 additions and 29 deletions.
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

0 comments on commit 361e731

Please sign in to comment.