use of org.mule.metadata.api.visitor.BasicTypeMetadataVisitor in project mule by mulesoft.
the class ExtensionDefinitionParser method parseCollectionParameter.
/**
* Registers a definition for a {@link ParameterModel} which represents an {@link ArrayType}
*
* @param key the key that the parsed value should have on the parsed parameter's map
* @param name the parameter's name
* @param arrayType the parameter's {@link ArrayType}
* @param defaultValue the parameter's default value
* @param expressionSupport the parameter's {@link ExpressionSupport}
* @param required whether the parameter is required
*/
protected void parseCollectionParameter(String key, String name, ArrayType arrayType, Object defaultValue, ExpressionSupport expressionSupport, boolean required, DslElementSyntax parameterDsl, Set<ModelProperty> modelProperties) {
parseAttributeParameter(key, name, arrayType, defaultValue, expressionSupport, required, modelProperties);
Class<?> collectionType = ExtensionMetadataTypeUtils.getType(arrayType).orElse(null);
if (Set.class.equals(collectionType)) {
collectionType = HashSet.class;
} else if (Collection.class.equals(collectionType) || Iterable.class.equals(collectionType) || collectionType == null) {
collectionType = List.class;
}
final String collectionElementName = parameterDsl.getElementName();
addParameter(getChildKey(key), fromChildConfiguration(collectionType).withWrapperIdentifier(collectionElementName));
addDefinition(baseDefinitionBuilder.withIdentifier(collectionElementName).withTypeDefinition(fromType(collectionType)).build());
Optional<DslElementSyntax> collectionItemDsl = parameterDsl.getGeneric(arrayType.getType());
if (parameterDsl.supportsChildDeclaration() && collectionItemDsl.isPresent()) {
String itemIdentifier = collectionItemDsl.get().getElementName();
String itemNamespace = collectionItemDsl.get().getPrefix();
arrayType.getType().accept(new BasicTypeMetadataVisitor() {
private void addBasicTypeDefinition(MetadataType metadataType) {
Builder itemDefinitionBuilder = baseDefinitionBuilder.withIdentifier(itemIdentifier).withNamespace(itemNamespace).withTypeDefinition(fromType(ExtensionMetadataTypeUtils.getType(metadataType).orElse(Object.class))).withTypeConverter(value -> resolverOf(name, metadataType, value, getDefaultValue(metadataType).orElse(null), getExpressionSupport(metadataType), false, emptySet()));
addDefinition(itemDefinitionBuilder.build());
}
@Override
protected void visitBasicType(MetadataType metadataType) {
addBasicTypeDefinition(metadataType);
}
@Override
public void visitDate(DateType dateType) {
addBasicTypeDefinition(dateType);
}
@Override
public void visitDateTime(DateTimeType dateTimeType) {
addBasicTypeDefinition(dateTimeType);
}
@Override
public void visitObject(ObjectType objectType) {
if (isMap(objectType)) {
return;
}
DslElementSyntax itemDsl = collectionItemDsl.get();
if ((itemDsl.supportsTopLevelDeclaration() || itemDsl.supportsChildDeclaration()) && !parsingContext.isRegistered(itemDsl.getElementName(), itemDsl.getPrefix())) {
try {
parsingContext.registerObjectType(itemDsl.getElementName(), itemDsl.getPrefix(), objectType);
new ObjectTypeParameterParser(baseDefinitionBuilder, objectType, getContextClassLoader(), dslResolver, parsingContext).parse().forEach(definition -> addDefinition(definition));
} catch (ConfigurationException e) {
throw new MuleRuntimeException(createStaticMessage("Could not create parser for collection complex type"), e);
}
}
}
});
}
}
use of org.mule.metadata.api.visitor.BasicTypeMetadataVisitor in project mule by mulesoft.
the class ParameterModelsLoaderDelegate method parseNullSafe.
private void parseNullSafe(ExtensionParameter extensionParameter, ParameterDeclarer parameter) {
if (extensionParameter.isAnnotatedWith(NullSafe.class)) {
if (extensionParameter.isAnnotatedWith(ConfigOverride.class)) {
throw new IllegalParameterModelDefinitionException(format("Parameter '%s' is annotated with '@%s' and also marked as a config override, which is redundant. " + "The default value for this parameter will come from the configuration parameter", extensionParameter.getName(), NullSafe.class.getSimpleName()));
}
if (extensionParameter.isRequired() && !extensionParameter.isAnnotatedWith(ParameterGroup.class)) {
throw new IllegalParameterModelDefinitionException(format("Parameter '%s' is required but annotated with '@%s', which is redundant", extensionParameter.getName(), NullSafe.class.getSimpleName()));
}
Type nullSafeAnnotationType = extensionParameter.getValueFromAnnotation(NullSafe.class).get().getClassValue(NullSafe::defaultImplementingType);
final boolean hasDefaultOverride = !nullSafeAnnotationType.isSameType(Object.class);
MetadataType nullSafeType = hasDefaultOverride ? nullSafeAnnotationType.asMetadataType() : parameter.getDeclaration().getType();
boolean isInstantiable = hasDefaultOverride ? nullSafeAnnotationType.isInstantiable() : extensionParameter.getType().isInstantiable();
parameter.getDeclaration().getType().accept(new BasicTypeMetadataVisitor() {
@Override
protected void visitBasicType(MetadataType metadataType) {
throw new IllegalParameterModelDefinitionException(format("Parameter '%s' is annotated with '@%s' but is of type '%s'. That annotation can only be " + "used with complex types (Pojos, Lists, Maps)", extensionParameter.getName(), NullSafe.class.getSimpleName(), extensionParameter.getType().getName()));
}
@Override
public void visitArrayType(ArrayType arrayType) {
if (hasDefaultOverride) {
throw new IllegalParameterModelDefinitionException(format("Parameter '%s' is annotated with '@%s' is of type '%s'" + " but a 'defaultImplementingType' was provided." + " Type override is not allowed for Collections", extensionParameter.getName(), NullSafe.class.getSimpleName(), extensionParameter.getType().getName()));
}
}
@Override
public void visitObject(ObjectType objectType) {
if (hasDefaultOverride && isMap(objectType)) {
throw new IllegalParameterModelDefinitionException(format("Parameter '%s' is annotated with '@%s' is of type '%s'" + " but a 'defaultImplementingType' was provided." + " Type override is not allowed for Maps", extensionParameter.getName(), NullSafe.class.getSimpleName(), extensionParameter.getType().getName()));
}
if (hasDefaultOverride && extensionParameter.getType().isInstantiable()) {
throw new IllegalParameterModelDefinitionException(format("Parameter '%s' is annotated with '@%s' is of concrete type '%s'," + " but a 'defaultImplementingType' was provided." + " Type override is not allowed for concrete types", extensionParameter.getName(), NullSafe.class.getSimpleName(), extensionParameter.getType().getName()));
}
if (!isInstantiable && !isMap(nullSafeType)) {
throw new IllegalParameterModelDefinitionException(format("Parameter '%s' is annotated with '@%s' but is of type '%s'. That annotation can only be " + "used with complex instantiable types (Pojos, Lists, Maps)", extensionParameter.getName(), NullSafe.class.getSimpleName(), extensionParameter.getType().getName()));
}
if (hasDefaultOverride && !extensionParameter.getType().isAssignableFrom(nullSafeAnnotationType)) {
throw new IllegalParameterModelDefinitionException(format("Parameter '%s' is annotated with '@%s' of type '%s', but provided type '%s" + " is not a subtype of the parameter's type", extensionParameter.getName(), NullSafe.class.getSimpleName(), extensionParameter.getType().getName(), getType(nullSafeType).getName()));
}
}
});
parameter.withModelProperty(new NullSafeModelProperty(nullSafeType));
if (hasDefaultOverride) {
parameter.withModelProperty(new DefaultImplementingTypeModelProperty(nullSafeType));
}
}
}
use of org.mule.metadata.api.visitor.BasicTypeMetadataVisitor in project mule by mulesoft.
the class ExtensionDefinitionParser method parseMapParameters.
/**
* Registers a definition for a {@link ParameterModel} which represents an open {@link ObjectType}
*
* @param key the key that the parsed value should have on the parsed parameter's map
* @param name the parameter's name
* @param dictionaryType the parameter's open {@link ObjectType}
* @param defaultValue the parameter's default value
* @param expressionSupport the parameter's {@link ExpressionSupport}
* @param required whether the parameter is required
*/
protected void parseMapParameters(String key, String name, ObjectType dictionaryType, Object defaultValue, ExpressionSupport expressionSupport, boolean required, DslElementSyntax paramDsl, Set<ModelProperty> modelProperties) {
parseAttributeParameter(key, name, dictionaryType, defaultValue, expressionSupport, required, modelProperties);
Class<? extends Map> mapType = getType(dictionaryType);
if (ConcurrentMap.class.equals(mapType)) {
mapType = ConcurrentHashMap.class;
} else if (Map.class.equals(mapType)) {
mapType = LinkedHashMap.class;
}
final MetadataType valueType = dictionaryType.getOpenRestriction().orElse(typeLoader.load(Object.class));
final Class<?> valueClass = getType(valueType);
final MetadataType keyType = typeLoader.load(String.class);
final Class<?> keyClass = String.class;
final String mapElementName = paramDsl.getElementName();
addParameter(getChildKey(key), fromChildMapConfiguration(String.class, valueClass).withWrapperIdentifier(mapElementName).withDefaultValue(defaultValue));
addDefinition(baseDefinitionBuilder.withIdentifier(mapElementName).withTypeDefinition(fromType(mapType)).build());
Optional<DslElementSyntax> mapValueChildDsl = paramDsl.getGeneric(valueType);
if (!mapValueChildDsl.isPresent()) {
return;
}
DslElementSyntax valueDsl = mapValueChildDsl.get();
valueType.accept(new MetadataTypeVisitor() {
@Override
protected void defaultVisit(MetadataType metadataType) {
String parameterName = paramDsl.getAttributeName();
addDefinition(baseDefinitionBuilder.withIdentifier(valueDsl.getElementName()).withTypeDefinition(fromMapEntryType(keyClass, valueClass)).withKeyTypeConverter(value -> resolverOf(parameterName, keyType, value, null, expressionSupport, true, emptySet(), false)).withTypeConverter(value -> resolverOf(parameterName, valueType, value, null, expressionSupport, true, emptySet(), false)).build());
}
@Override
public void visitObject(ObjectType objectType) {
defaultVisit(objectType);
Optional<DslElementSyntax> containedElement = valueDsl.getContainedElement(VALUE_ATTRIBUTE_NAME);
if (isMap(objectType) || !containedElement.isPresent()) {
return;
}
DslElementSyntax valueChild = containedElement.get();
if ((valueChild.supportsTopLevelDeclaration() || (valueChild.supportsChildDeclaration() && !valueChild.isWrapped())) && !parsingContext.isRegistered(valueChild.getElementName(), valueChild.getPrefix())) {
try {
parsingContext.registerObjectType(valueChild.getElementName(), valueChild.getPrefix(), objectType);
new ObjectTypeParameterParser(baseDefinitionBuilder, objectType, getContextClassLoader(), dslResolver, parsingContext).parse().forEach(definition -> addDefinition(definition));
} catch (ConfigurationException e) {
throw new MuleRuntimeException(createStaticMessage("Could not create parser for map complex type"), e);
}
}
}
@Override
public void visitArrayType(ArrayType arrayType) {
defaultVisit(arrayType);
Optional<DslElementSyntax> valueListGenericDsl = valueDsl.getGeneric(arrayType.getType());
if (valueDsl.supportsChildDeclaration() && valueListGenericDsl.isPresent()) {
arrayType.getType().accept(new BasicTypeMetadataVisitor() {
@Override
protected void visitBasicType(MetadataType metadataType) {
String parameterName = paramDsl.getAttributeName();
addDefinition(baseDefinitionBuilder.withIdentifier(valueListGenericDsl.get().getElementName()).withTypeDefinition(fromType(getType(metadataType))).withTypeConverter(value -> resolverOf(parameterName, metadataType, value, getDefaultValue(metadataType), getExpressionSupport(metadataType), false, emptySet())).build());
}
@Override
protected void defaultVisit(MetadataType metadataType) {
addDefinition(baseDefinitionBuilder.withIdentifier(valueListGenericDsl.get().getElementName()).withTypeDefinition(fromType(ValueResolver.class)).withObjectFactoryType(TopLevelParameterObjectFactory.class).withConstructorParameterDefinition(fromFixedValue(arrayType.getType()).build()).withConstructorParameterDefinition(fromFixedValue(getContextClassLoader()).build()).build());
}
});
}
}
});
}
use of org.mule.metadata.api.visitor.BasicTypeMetadataVisitor in project mule by mulesoft.
the class ExtensionDefinitionParser method getValueResolverFromMetadataType.
private ValueResolver getValueResolverFromMetadataType(final String parameterName, MetadataType expectedType, final Object value, final Object defaultValue, final boolean acceptsReferences, final Class<?> expectedClass) {
final Reference<ValueResolver> resolverValueHolder = new Reference<>();
expectedType.accept(new BasicTypeMetadataVisitor() {
@Override
protected void visitBasicType(MetadataType metadataType) {
if (conversionService.canConvert(value.getClass(), expectedClass)) {
resolverValueHolder.set(new StaticValueResolver<>(convertSimpleValue(value, expectedClass, parameterName)));
} else {
defaultVisit(metadataType);
}
}
@Override
public void visitDateTime(DateTimeType dateTimeType) {
resolverValueHolder.set(parseDate(value, dateTimeType, defaultValue));
}
@Override
public void visitDate(DateType dateType) {
resolverValueHolder.set(parseDate(value, dateType, defaultValue));
}
@Override
public void visitObject(ObjectType objectType) {
if (isMap(objectType)) {
defaultVisit(objectType);
return;
}
ValueResolver valueResolver;
Optional<? extends ParsingDelegate> delegate = locateParsingDelegate(valueResolverParsingDelegates, objectType);
Optional<DslElementSyntax> typeDsl = dslResolver.resolve(objectType);
if (delegate.isPresent() && typeDsl.isPresent()) {
valueResolver = (ValueResolver) delegate.get().parse(value.toString(), objectType, typeDsl.get());
} else {
valueResolver = acceptsReferences ? defaultValueResolverParsingDelegate.parse(value.toString(), objectType, null) : new StaticValueResolver<>(value);
}
resolverValueHolder.set(valueResolver);
}
@Override
protected void defaultVisit(MetadataType metadataType) {
ValueResolver delegateResolver = locateParsingDelegate(valueResolverParsingDelegates, metadataType).map(delegate -> delegate.parse(value.toString(), metadataType, null)).orElseGet(() -> acceptsReferences ? defaultValueResolverParsingDelegate.parse(value.toString(), metadataType, null) : new TypeSafeValueResolverWrapper(new StaticValueResolver<>(value), expectedClass));
resolverValueHolder.set(delegateResolver);
}
});
return resolverValueHolder.get();
}
use of org.mule.metadata.api.visitor.BasicTypeMetadataVisitor in project mule by mulesoft.
the class NullSafeModelValidator method validate.
@Override
public void validate(ExtensionModel extensionModel, ProblemsReporter problemsReporter) {
ReflectionCache reflectionCache = new ReflectionCache();
TypeLoader typeLoader = ExtensionsTypeLoaderFactory.getDefault().createTypeLoader();
new ExtensionWalker() {
@Override
public void onParameter(ParameterizedModel owner, ParameterGroupModel groupModel, ParameterModel model) {
model.getType().accept(new MetadataTypeVisitor() {
@Override
public void visitObject(ObjectType objectType) {
if (objectType.getMetadataFormat().equals(JAVA) && !isMap(objectType)) {
objectType.getAnnotation(TypeIdAnnotation.class).map(TypeIdAnnotation::getValue).ifPresent(typeId -> typeLoader.load(typeId).ifPresent(fieldMetadataType -> objectType.getFields().stream().filter(f -> f.getAnnotation(NullSafeTypeAnnotation.class).isPresent()).forEach(f -> validateField(getLocalPart(f), f, getType(fieldMetadataType), f.getAnnotation(NullSafeTypeAnnotation.class).get()))));
}
}
private void validateField(String fieldName, ObjectFieldType field, Class<?> declaringClass, NullSafeTypeAnnotation nullSafeTypeAnnotation) {
Class<?> nullSafeType = nullSafeTypeAnnotation.getType();
Class<?> fieldType = getType(field.getValue());
boolean hasDefaultOverride = nullSafeTypeAnnotation.hasDefaultOverride();
field.getValue().accept(new BasicTypeMetadataVisitor() {
@Override
protected void visitBasicType(MetadataType metadataType) {
problemsReporter.addError(new Problem(extensionModel, format("Field '%s' in class '%s' is annotated with '@%s' but is of type '%s'. That annotation can only be " + "used with complex types (Pojos, Lists, Maps)", fieldName, declaringClass.getName(), NullSafe.class.getSimpleName(), fieldType.getName())));
}
@Override
public void visitArrayType(ArrayType arrayType) {
if (hasDefaultOverride) {
problemsReporter.addError(new Problem(extensionModel, format("Field '%s' in class '%s' is annotated with '@%s' is of type '%s'" + " but a 'defaultImplementingType' was provided." + " Type override is not allowed for Collections", fieldName, declaringClass.getName(), NullSafe.class.getSimpleName(), fieldType.getName())));
}
}
@Override
public void visitObject(ObjectType objectType) {
String requiredFields = objectType.getFields().stream().filter(f -> f.isRequired() && !isFlattenedParameterGroup(f)).map(MetadataTypeUtils::getLocalPart).collect(joining(", "));
if (!isBlank(requiredFields) && isCompiletime(extensionModel)) {
problemsReporter.addError(new Problem(model, format("Class '%s' cannot be used with '@%s' parameter since it contains non optional fields: [%s]", getId(objectType).orElse(""), NullSafe.class.getSimpleName(), requiredFields)));
}
if (objectType.isOpen()) {
if (hasDefaultOverride) {
problemsReporter.addError(new Problem(model, format("Field '%s' in class '%s' is annotated with '@%s' is of type '%s'" + " but a 'defaultImplementingType' was provided." + " Type override is not allowed for Maps", fieldName, declaringClass.getName(), NullSafe.class.getSimpleName(), fieldType.getName())));
}
return;
}
if (hasDefaultOverride && isInstantiable(fieldType, reflectionCache)) {
problemsReporter.addError(new Problem(model, format("Field '%s' in class '%s' is annotated with '@%s' is of concrete type '%s'," + " but a 'defaultImplementingType' was provided." + " Type override is not allowed for concrete types", fieldName, declaringClass.getName(), NullSafe.class.getSimpleName(), fieldType.getName())));
}
if (!isInstantiable(nullSafeType, reflectionCache)) {
problemsReporter.addError(new Problem(model, format("Field '%s' in class '%s' is annotated with '@%s' but is of type '%s'. That annotation can only be " + "used with complex instantiable types (Pojos, Lists, Maps)", fieldName, declaringClass.getName(), NullSafe.class.getSimpleName(), nullSafeType.getName())));
}
if (hasDefaultOverride && !fieldType.isAssignableFrom(nullSafeType)) {
problemsReporter.addError(new Problem(model, format("Field '%s' in class '%s' is annotated with '@%s' of type '%s', but provided type '%s" + " is not a subtype of the parameter's type", fieldName, declaringClass.getName(), NullSafe.class.getSimpleName(), fieldType.getName(), nullSafeType.getName())));
}
}
});
}
});
}
}.walk(extensionModel);
}
Aggregations