/*
* Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com
* The software in this package is published under the terms of the CPAL v1.0
* license, a copy of which has been included with this distribution in the
* LICENSE.txt file.
*/
package org.mule.runtime.config.spring.dsl.spring;
import static org.mule.runtime.dsl.api.component.DslSimpleType.SIMPLE_TYPE_VALUE_PARAMETER_NAME;
import static org.mule.runtime.dsl.api.component.DslSimpleType.isSimpleType;
import static org.springframework.beans.factory.support.BeanDefinitionBuilder.genericBeanDefinition;
import org.mule.runtime.config.spring.dsl.model.ComponentModel;
import org.mule.runtime.config.spring.dsl.processor.ObjectTypeVisitor;
import org.mule.runtime.dsl.api.component.ComponentBuildingDefinition;
import org.mule.runtime.dsl.api.component.MapEntry;
import org.mule.runtime.dsl.api.component.TypeDefinition.MapEntryType;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.ManagedList;
/**
* {@code BeanDefinitionCreator} that handles component that define a map entry.
* <p>
*
* <pre>
* <parsers-test:simple-type-entry key="key1" value="1"/>
* </pre>
*
* or
*
* <pre>
* <parsers-test:simple-type-entry key="key1" value-ref="anotherDefinition"/>
* </pre>
*
* or
*
* <pre>
* <parsers-test:complex-type-entry key="1">
* <parsers-test:parameter-collection-parser firstname="Pablo" lastname="La Greca" age="32"/>
* </parsers-test:complex-type-entry>
* </pre>
*
* @since 4.0
*/
public class MapEntryBeanDefinitionCreator extends BeanDefinitionCreator {
private static final String ENTRY_TYPE_KEY_PARAMETER_NAME = "key";
private static final String ENTRY_TYPE_VALUE_REF_PARAMETER_NAME = "value-ref";
@Override
boolean handleRequest(CreateBeanDefinitionRequest createBeanDefinitionRequest) {
ObjectTypeVisitor objectTypeVisitor = new ObjectTypeVisitor(createBeanDefinitionRequest.getComponentModel());
createBeanDefinitionRequest.getComponentBuildingDefinition().getTypeDefinition().visit(objectTypeVisitor);
Class<?> type = objectTypeVisitor.getType();
if (!(MapEntryType.class.isAssignableFrom(type))) {
return false;
}
ComponentModel componentModel = createBeanDefinitionRequest.getComponentModel();
ComponentBuildingDefinition componentBuildingDefinition = createBeanDefinitionRequest.getComponentBuildingDefinition();
componentModel.setType(type);
final Object key = componentModel.getParameters().get(ENTRY_TYPE_KEY_PARAMETER_NAME);
Object keyBeanDefinition = getConvertibleBeanDefinition(objectTypeVisitor.getMapEntryType().get().getKeyType(), key,
componentBuildingDefinition.getKeyTypeConverter());
Object value = null;
// MULE-11984: Check that generated map entries are not empty
if (componentModel.getParameters().get(ENTRY_TYPE_VALUE_REF_PARAMETER_NAME) != null) {
value = new RuntimeBeanReference(componentModel.getParameters().get(ENTRY_TYPE_VALUE_REF_PARAMETER_NAME));
} else {
value = getValue(objectTypeVisitor, componentModel, componentBuildingDefinition);
}
AbstractBeanDefinition beanDefinition = genericBeanDefinition(MapEntry.class).addConstructorArgValue(keyBeanDefinition)
.addConstructorArgValue(value).getBeanDefinition();
componentModel.setBeanDefinition(beanDefinition);
return true;
}
private Object getValue(ObjectTypeVisitor objectTypeVisitor, ComponentModel componentModel,
ComponentBuildingDefinition componentBuildingDefinition) {
Object value;
Class valueType = objectTypeVisitor.getMapEntryType().get().getValueType();
if (isSimpleType(valueType) || componentModel.getInnerComponents().isEmpty()) {
value = getConvertibleBeanDefinition(objectTypeVisitor.getMapEntryType().get().getValueType(),
componentModel.getParameters().get(SIMPLE_TYPE_VALUE_PARAMETER_NAME),
componentBuildingDefinition.getTypeConverter());
} else if (List.class.isAssignableFrom(objectTypeVisitor.getMapEntryType().get().getValueType())) {
if (componentModel.getInnerComponents().isEmpty()) {
String valueParameter = componentModel.getParameters().get(SIMPLE_TYPE_VALUE_PARAMETER_NAME);
value = getConvertibleBeanDefinition(valueType, valueParameter, componentBuildingDefinition.getTypeConverter());
} else {
ManagedList<Object> managedList = componentModel
.getInnerComponents().stream().map(childComponent -> childComponent.getBeanDefinition() != null
? childComponent.getBeanDefinition() : childComponent.getBeanReference())
.collect(Collectors.toCollection(ManagedList::new));
value = genericBeanDefinition(ObjectTypeVisitor.DEFAULT_COLLECTION_TYPE).addConstructorArgValue(managedList)
.getBeanDefinition();
}
} else {
ComponentModel childComponentModel = componentModel.getInnerComponents().get(0);
BeanDefinition beanDefinition = childComponentModel.getBeanDefinition();
value = beanDefinition != null ? beanDefinition : childComponentModel.getBeanReference();
}
return value;
}
}